map.c revision 73188
138032Speter/*
273188Sgshapiro * Copyright (c) 1998-2001 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
1438032Speter#ifndef lint
1573188Sgshapirostatic char id[] = "@(#)$Id: map.c,v 8.414.4.39 2001/02/22 18:56:22 gshapiro Exp $";
1664562Sgshapiro#endif /* ! lint */
1738032Speter
1864562Sgshapiro#include <sendmail.h>
1938032Speter
2064562Sgshapiro
2138032Speter#ifdef NDBM
2238032Speter# include <ndbm.h>
2338032Speter# ifdef R_FIRST
2438032Speter  ERROR README:	You are running the Berkeley DB version of ndbm.h.  See
2538032Speter  ERROR README:	the README file about tweaking Berkeley DB so it can
2638032Speter  ERROR README:	coexist with NDBM, or delete -DNDBM from the Makefile
2738032Speter  ERROR README: and use -DNEWDB instead.
2864562Sgshapiro# endif /* R_FIRST */
2964562Sgshapiro#endif /* NDBM */
3038032Speter#ifdef NEWDB
3138032Speter# include <db.h>
3238032Speter# ifndef DB_VERSION_MAJOR
3338032Speter#  define DB_VERSION_MAJOR 1
3464562Sgshapiro# endif /* ! DB_VERSION_MAJOR */
3564562Sgshapiro#endif /* NEWDB */
3638032Speter#ifdef NIS
3738032Speter  struct dom_binding;	/* forward reference needed on IRIX */
3838032Speter# include <rpcsvc/ypclnt.h>
3938032Speter# ifdef NDBM
4038032Speter#  define NDBM_YP_COMPAT	/* create YP-compatible NDBM files */
4164562Sgshapiro# endif /* NDBM */
4264562Sgshapiro#endif /* NIS */
4338032Speter
4464562Sgshapiro#ifdef NEWDB
4564562Sgshapiro# if DB_VERSION_MAJOR < 2
4664562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
4764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
4864562Sgshapiro# if DB_VERSION_MAJOR == 2
4964562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
5064562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
5164562Sgshapiro# if DB_VERSION_MAJOR > 2
5264562Sgshapirostatic bool	db_map_open __P((MAP *, int, char *, DBTYPE, void **));
5364562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
5464562Sgshapiro#endif /* NEWDB */
5573188Sgshapirostatic bool	extract_canonname __P((char *, char *, char *, char[], int));
5664562Sgshapiro#ifdef LDAPMAP
5764562Sgshapirostatic void	ldapmap_clear __P((LDAPMAP_STRUCT *));
5864562Sgshapirostatic STAB	*ldapmap_findconn __P((LDAPMAP_STRUCT *));
5964562Sgshapirostatic int	ldapmap_geterrno __P((LDAP *));
6064562Sgshapirostatic void	ldapmap_setopts __P((LDAP *, LDAPMAP_STRUCT *));
6164562Sgshapirostatic bool	ldapmap_start __P((MAP *));
6264562Sgshapirostatic void	ldaptimeout __P((int));
6364562Sgshapiro#endif /* LDAPMAP */
6464562Sgshapirostatic void	map_close __P((STAB *, int));
6564562Sgshapirostatic void	map_init __P((STAB *, int));
6664562Sgshapiro#ifdef NISPLUS
6764562Sgshapirostatic bool	nisplus_getcanonname __P((char *, int, int *));
6864562Sgshapiro#endif /* NISPLUS */
6964562Sgshapiro#ifdef NIS
7064562Sgshapirostatic bool	nis_getcanonname __P((char *, int, int *));
7164562Sgshapiro#endif /* NIS */
7264562Sgshapiro#if NETINFO
7364562Sgshapirostatic bool	ni_getcanonname __P((char *, int, int *));
7464562Sgshapiro#endif /* NETINFO */
7564562Sgshapirostatic bool	text_getcanonname __P((char *, int, int *));
7664562Sgshapiro
7738032Speter/*
7838032Speter**  MAP.C -- implementations for various map classes.
7938032Speter**
8038032Speter**	Each map class implements a series of functions:
8138032Speter**
8238032Speter**	bool map_parse(MAP *map, char *args)
8338032Speter**		Parse the arguments from the config file.  Return TRUE
8438032Speter**		if they were ok, FALSE otherwise.  Fill in map with the
8538032Speter**		values.
8638032Speter**
8738032Speter**	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
8838032Speter**		Look up the key in the given map.  If found, do any
8938032Speter**		rewriting the map wants (including "args" if desired)
9038032Speter**		and return the value.  Set *pstat to the appropriate status
9138032Speter**		on error and return NULL.  Args will be NULL if called
9238032Speter**		from the alias routines, although this should probably
9338032Speter**		not be relied upon.  It is suggested you call map_rewrite
9438032Speter**		to return the results -- it takes care of null termination
9538032Speter**		and uses a dynamically expanded buffer as needed.
9638032Speter**
9738032Speter**	void map_store(MAP *map, char *key, char *value)
9838032Speter**		Store the key:value pair in the map.
9938032Speter**
10038032Speter**	bool map_open(MAP *map, int mode)
10138032Speter**		Open the map for the indicated mode.  Mode should
10238032Speter**		be either O_RDONLY or O_RDWR.  Return TRUE if it
10338032Speter**		was opened successfully, FALSE otherwise.  If the open
10438032Speter**		failed an the MF_OPTIONAL flag is not set, it should
10538032Speter**		also print an error.  If the MF_ALIAS bit is set
10638032Speter**		and this map class understands the @:@ convention, it
10738032Speter**		should call aliaswait() before returning.
10838032Speter**
10938032Speter**	void map_close(MAP *map)
11038032Speter**		Close the map.
11138032Speter**
11238032Speter**	This file also includes the implementation for getcanonname.
11338032Speter**	It is currently implemented in a pretty ad-hoc manner; it ought
11438032Speter**	to be more properly integrated into the map structure.
11538032Speter*/
11638032Speter
11738032Speter#define DBMMODE		0644
11838032Speter
11938032Speter#ifndef EX_NOTFOUND
12038032Speter# define EX_NOTFOUND	EX_NOHOST
12164562Sgshapiro#endif /* ! EX_NOTFOUND */
12238032Speter
12338032Speter#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
12438032Speter# define LOCK_ON_OPEN	1	/* we can open/create a locked file */
12564562Sgshapiro#else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
12638032Speter# define LOCK_ON_OPEN	0	/* no such luck -- bend over backwards */
12764562Sgshapiro#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
12838032Speter
12938032Speter#ifndef O_ACCMODE
13038032Speter# define O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR)
13164562Sgshapiro#endif /* ! O_ACCMODE */
13238032Speter/*
13338032Speter**  MAP_PARSEARGS -- parse config line arguments for database lookup
13438032Speter**
13538032Speter**	This is a generic version of the map_parse method.
13638032Speter**
13738032Speter**	Parameters:
13838032Speter**		map -- the map being initialized.
13938032Speter**		ap -- a pointer to the args on the config line.
14038032Speter**
14138032Speter**	Returns:
14238032Speter**		TRUE -- if everything parsed OK.
14338032Speter**		FALSE -- otherwise.
14438032Speter**
14538032Speter**	Side Effects:
14638032Speter**		null terminates the filename; stores it in map
14738032Speter*/
14838032Speter
14938032Speterbool
15038032Spetermap_parseargs(map, ap)
15138032Speter	MAP *map;
15238032Speter	char *ap;
15338032Speter{
15438032Speter	register char *p = ap;
15538032Speter
15664562Sgshapiro	/*
15764562Sgshapiro	**  there is no check whether there is really an argument,
15864562Sgshapiro	**  but that's not important enough to warrant extra code
15964562Sgshapiro	*/
16038032Speter	map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
16164562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
16238032Speter	for (;;)
16338032Speter	{
16438032Speter		while (isascii(*p) && isspace(*p))
16538032Speter			p++;
16638032Speter		if (*p != '-')
16738032Speter			break;
16838032Speter		switch (*++p)
16938032Speter		{
17038032Speter		  case 'N':
17138032Speter			map->map_mflags |= MF_INCLNULL;
17238032Speter			map->map_mflags &= ~MF_TRY0NULL;
17338032Speter			break;
17438032Speter
17538032Speter		  case 'O':
17638032Speter			map->map_mflags &= ~MF_TRY1NULL;
17738032Speter			break;
17838032Speter
17938032Speter		  case 'o':
18038032Speter			map->map_mflags |= MF_OPTIONAL;
18138032Speter			break;
18238032Speter
18338032Speter		  case 'f':
18438032Speter			map->map_mflags |= MF_NOFOLDCASE;
18538032Speter			break;
18638032Speter
18738032Speter		  case 'm':
18838032Speter			map->map_mflags |= MF_MATCHONLY;
18938032Speter			break;
19038032Speter
19138032Speter		  case 'A':
19238032Speter			map->map_mflags |= MF_APPEND;
19338032Speter			break;
19438032Speter
19538032Speter		  case 'q':
19638032Speter			map->map_mflags |= MF_KEEPQUOTES;
19738032Speter			break;
19838032Speter
19938032Speter		  case 'a':
20038032Speter			map->map_app = ++p;
20138032Speter			break;
20238032Speter
20338032Speter		  case 'T':
20438032Speter			map->map_tapp = ++p;
20538032Speter			break;
20638032Speter
20738032Speter		  case 'k':
20838032Speter			while (isascii(*++p) && isspace(*p))
20938032Speter				continue;
21038032Speter			map->map_keycolnm = p;
21138032Speter			break;
21238032Speter
21338032Speter		  case 'v':
21438032Speter			while (isascii(*++p) && isspace(*p))
21538032Speter				continue;
21638032Speter			map->map_valcolnm = p;
21738032Speter			break;
21838032Speter
21938032Speter		  case 'z':
22038032Speter			if (*++p != '\\')
22138032Speter				map->map_coldelim = *p;
22238032Speter			else
22338032Speter			{
22438032Speter				switch (*++p)
22538032Speter				{
22638032Speter				  case 'n':
22738032Speter					map->map_coldelim = '\n';
22838032Speter					break;
22938032Speter
23038032Speter				  case 't':
23138032Speter					map->map_coldelim = '\t';
23238032Speter					break;
23338032Speter
23438032Speter				  default:
23538032Speter					map->map_coldelim = '\\';
23638032Speter				}
23738032Speter			}
23838032Speter			break;
23938032Speter
24038032Speter		  case 't':
24138032Speter			map->map_mflags |= MF_NODEFER;
24238032Speter			break;
24338032Speter
24464562Sgshapiro
24564562Sgshapiro		  case 'S':
24664562Sgshapiro			map->map_spacesub = *++p;
24738032Speter			break;
24838032Speter
24964562Sgshapiro		  case 'D':
25064562Sgshapiro			map->map_mflags |= MF_DEFER;
25138032Speter			break;
25264562Sgshapiro
25364562Sgshapiro		  default:
25464562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
25564562Sgshapiro			break;
25638032Speter		}
25738032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
25838032Speter			p++;
25938032Speter		if (*p != '\0')
26038032Speter			*p++ = '\0';
26138032Speter	}
26238032Speter	if (map->map_app != NULL)
26338032Speter		map->map_app = newstr(map->map_app);
26438032Speter	if (map->map_tapp != NULL)
26538032Speter		map->map_tapp = newstr(map->map_tapp);
26638032Speter	if (map->map_keycolnm != NULL)
26738032Speter		map->map_keycolnm = newstr(map->map_keycolnm);
26838032Speter	if (map->map_valcolnm != NULL)
26938032Speter		map->map_valcolnm = newstr(map->map_valcolnm);
27038032Speter
27138032Speter	if (*p != '\0')
27238032Speter	{
27338032Speter		map->map_file = p;
27438032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
27538032Speter			p++;
27638032Speter		if (*p != '\0')
27738032Speter			*p++ = '\0';
27838032Speter		map->map_file = newstr(map->map_file);
27938032Speter	}
28038032Speter
28138032Speter	while (*p != '\0' && isascii(*p) && isspace(*p))
28238032Speter		p++;
28338032Speter	if (*p != '\0')
28438032Speter		map->map_rebuild = newstr(p);
28538032Speter
28638032Speter	if (map->map_file == NULL &&
28738032Speter	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
28838032Speter	{
28938032Speter		syserr("No file name for %s map %s",
29038032Speter			map->map_class->map_cname, map->map_mname);
29138032Speter		return FALSE;
29238032Speter	}
29338032Speter	return TRUE;
29438032Speter}
29538032Speter/*
29638032Speter**  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
29738032Speter**
29838032Speter**	It also adds the map_app string.  It can be used as a utility
29938032Speter**	in the map_lookup method.
30038032Speter**
30138032Speter**	Parameters:
30238032Speter**		map -- the map that causes this.
30338032Speter**		s -- the string to rewrite, NOT necessarily null terminated.
30438032Speter**		slen -- the length of s.
30538032Speter**		av -- arguments to interpolate into buf.
30638032Speter**
30738032Speter**	Returns:
30838032Speter**		Pointer to rewritten result.  This is static data that
30938032Speter**		should be copied if it is to be saved!
31038032Speter**
31138032Speter**	Side Effects:
31238032Speter**		none.
31338032Speter*/
31438032Speter
31538032Speterchar *
31638032Spetermap_rewrite(map, s, slen, av)
31738032Speter	register MAP *map;
31838032Speter	register const char *s;
31938032Speter	size_t slen;
32038032Speter	char **av;
32138032Speter{
32238032Speter	register char *bp;
32338032Speter	register char c;
32438032Speter	char **avp;
32538032Speter	register char *ap;
32638032Speter	size_t l;
32738032Speter	size_t len;
32838032Speter	static size_t buflen = 0;
32938032Speter	static char *buf = NULL;
33038032Speter
33138032Speter	if (tTd(39, 1))
33238032Speter	{
33364562Sgshapiro		dprintf("map_rewrite(%.*s), av =", (int)slen, s);
33438032Speter		if (av == NULL)
33564562Sgshapiro			dprintf(" (nullv)");
33638032Speter		else
33738032Speter		{
33838032Speter			for (avp = av; *avp != NULL; avp++)
33964562Sgshapiro				dprintf("\n\t%s", *avp);
34038032Speter		}
34164562Sgshapiro		dprintf("\n");
34238032Speter	}
34338032Speter
34438032Speter	/* count expected size of output (can safely overestimate) */
34538032Speter	l = len = slen;
34638032Speter	if (av != NULL)
34738032Speter	{
34838032Speter		const char *sp = s;
34938032Speter
35038032Speter		while (l-- > 0 && (c = *sp++) != '\0')
35138032Speter		{
35238032Speter			if (c != '%')
35338032Speter				continue;
35438032Speter			if (l-- <= 0)
35538032Speter				break;
35638032Speter			c = *sp++;
35738032Speter			if (!(isascii(c) && isdigit(c)))
35838032Speter				continue;
35938032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
36038032Speter				continue;
36138032Speter			if (*avp == NULL)
36238032Speter				continue;
36338032Speter			len += strlen(*avp);
36438032Speter		}
36538032Speter	}
36638032Speter	if (map->map_app != NULL)
36738032Speter		len += strlen(map->map_app);
36838032Speter	if (buflen < ++len)
36938032Speter	{
37038032Speter		/* need to malloc additional space */
37138032Speter		buflen = len;
37238032Speter		if (buf != NULL)
37338032Speter			free(buf);
37438032Speter		buf = xalloc(buflen);
37538032Speter	}
37638032Speter
37738032Speter	bp = buf;
37838032Speter	if (av == NULL)
37938032Speter	{
38064562Sgshapiro		memmove(bp, s, slen);
38138032Speter		bp += slen;
38264562Sgshapiro
38364562Sgshapiro		/* assert(len > slen); */
38464562Sgshapiro		len -= slen;
38538032Speter	}
38638032Speter	else
38738032Speter	{
38838032Speter		while (slen-- > 0 && (c = *s++) != '\0')
38938032Speter		{
39038032Speter			if (c != '%')
39138032Speter			{
39238032Speter  pushc:
39364562Sgshapiro				if (--len <= 0)
39464562Sgshapiro					break;
39538032Speter				*bp++ = c;
39638032Speter				continue;
39738032Speter			}
39838032Speter			if (slen-- <= 0 || (c = *s++) == '\0')
39938032Speter				c = '%';
40038032Speter			if (c == '%')
40138032Speter				goto pushc;
40238032Speter			if (!(isascii(c) && isdigit(c)))
40338032Speter			{
40438032Speter				*bp++ = '%';
40564562Sgshapiro				--len;
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)
41964562Sgshapiro		(void) strlcpy(bp, map->map_app, len);
42038032Speter	else
42138032Speter		*bp = '\0';
42238032Speter	if (tTd(39, 1))
42364562Sgshapiro		dprintf("map_rewrite => %s\n", buf);
42438032Speter	return buf;
42538032Speter}
42638032Speter/*
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}
44764562Sgshapiro/*
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 */
47038032Speter	if (s->s_type != 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))
47864562Sgshapiro		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))
48864562Sgshapiro			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	{
49538032Speter		map->map_class->map_close(map);
49638032Speter		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
49738032Speter	}
49838032Speter
49964562Sgshapiro	(void) rebuildaliases(map, FALSE);
50064562Sgshapiro	return;
50164562Sgshapiro}
50264562Sgshapiro/*
50364562Sgshapiro**  OPENMAP -- open a map
50464562Sgshapiro**
50564562Sgshapiro**	Parameters:
50664562Sgshapiro**		map -- map to open (it must not be open).
50764562Sgshapiro**
50864562Sgshapiro**	Returns:
50964562Sgshapiro**		whether open succeeded.
51064562Sgshapiro**
51164562Sgshapiro*/
51264562Sgshapiro
51364562Sgshapirobool
51464562Sgshapiroopenmap(map)
51564562Sgshapiro	MAP *map;
51664562Sgshapiro{
51764562Sgshapiro	bool restore = FALSE;
51864562Sgshapiro	bool savehold = HoldErrs;
51964562Sgshapiro	bool savequick = QuickAbort;
52064562Sgshapiro	int saveerrors = Errors;
52164562Sgshapiro
52264562Sgshapiro	if (!bitset(MF_VALID, map->map_mflags))
52364562Sgshapiro		return FALSE;
52464562Sgshapiro
52564562Sgshapiro	/* better safe than sorry... */
52664562Sgshapiro	if (bitset(MF_OPEN, map->map_mflags))
52764562Sgshapiro		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	{
53364562Sgshapiro		restore = TRUE;
53464562Sgshapiro		HoldErrs = TRUE;
53564562Sgshapiro		QuickAbort = FALSE;
53638032Speter	}
53738032Speter
53864562Sgshapiro	errno = 0;
53938032Speter	if (map->map_class->map_open(map, O_RDONLY))
54038032Speter	{
54138032Speter		if (tTd(38, 4))
54264562Sgshapiro			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;
55042575Speter		map->map_pid = getpid();
55138032Speter	}
55238032Speter	else
55338032Speter	{
55438032Speter		if (tTd(38, 4))
55564562Sgshapiro			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 ? "" : ": ",
56364562Sgshapiro				errno == 0 ? "" : errstring(errno));
56438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
56538032Speter		{
56638032Speter			extern MAPCLASS BogusMapClass;
56738032Speter
56838032Speter			map->map_class = &BogusMapClass;
56938032Speter			map->map_mflags |= MF_OPEN;
57042575Speter			map->map_pid = getpid();
57166494Sgshapiro			MapOpenErr = TRUE;
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}
58938032Speter/*
59042575Speter**  CLOSEMAPS -- close all open maps opened by the current pid.
59142575Speter**
59242575Speter**	Parameters:
59342575Speter**		none
59442575Speter**
59542575Speter**	Returns:
59642575Speter**		none.
59742575Speter*/
59842575Speter
59942575Spetervoid
60042575Speterclosemaps()
60142575Speter{
60242575Speter	stabapply(map_close, 0);
60342575Speter}
60464562Sgshapiro/*
60564562Sgshapiro**  MAP_CLOSE -- close a map opened by the current pid.
60664562Sgshapiro**
60764562Sgshapiro**	Parameters:
60864562Sgshapiro**		s -- STAB entry: if map: try to open
60964562Sgshapiro**		second parameter is unused (required by stabapply())
61064562Sgshapiro**
61164562Sgshapiro**	Returns:
61264562Sgshapiro**		none.
61364562Sgshapiro*/
61442575Speter
61542575Speter/* ARGSUSED1 */
61664562Sgshapirostatic void
61742575Spetermap_close(s, unused)
61842575Speter	register STAB *s;
61942575Speter	int unused;
62042575Speter{
62142575Speter	MAP *map;
62242575Speter
62342575Speter	if (s->s_type != ST_MAP)
62442575Speter		return;
62564562Sgshapiro
62642575Speter	map = &s->s_map;
62742575Speter
62842575Speter	if (!bitset(MF_VALID, map->map_mflags) ||
62942575Speter	    !bitset(MF_OPEN, map->map_mflags) ||
63042575Speter	    map->map_pid != getpid())
63142575Speter		return;
63264562Sgshapiro
63342575Speter	if (tTd(38, 5))
63464562Sgshapiro		dprintf("closemaps: closing %s (%s)\n",
63564562Sgshapiro			map->map_mname == NULL ? "NULL" : map->map_mname,
63664562Sgshapiro			map->map_file == NULL ? "NULL" : map->map_file);
63764562Sgshapiro
63842575Speter	map->map_class->map_close(map);
63942575Speter	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
64042575Speter}
64142575Speter/*
64238032Speter**  GETCANONNAME -- look up name using service switch
64338032Speter**
64438032Speter**	Parameters:
64538032Speter**		host -- the host name to look up.
64638032Speter**		hbsize -- the size of the host buffer.
64738032Speter**		trymx -- if set, try MX records.
64838032Speter**
64938032Speter**	Returns:
65038032Speter**		TRUE -- if the host was found.
65138032Speter**		FALSE -- otherwise.
65238032Speter*/
65338032Speter
65438032Speterbool
65538032Spetergetcanonname(host, hbsize, trymx)
65638032Speter	char *host;
65738032Speter	int hbsize;
65838032Speter	bool trymx;
65938032Speter{
66038032Speter	int nmaps;
66138032Speter	int mapno;
66238032Speter	bool found = FALSE;
66338032Speter	bool got_tempfail = FALSE;
66464562Sgshapiro	auto int status;
66538032Speter	char *maptype[MAXMAPSTACK];
66638032Speter	short mapreturn[MAXMAPACTIONS];
66738032Speter
66838032Speter	nmaps = switch_map_find("hosts", maptype, mapreturn);
66938032Speter	for (mapno = 0; mapno < nmaps; mapno++)
67038032Speter	{
67138032Speter		int i;
67238032Speter
67338032Speter		if (tTd(38, 20))
67464562Sgshapiro			dprintf("getcanonname(%s), trying %s\n",
67538032Speter				host, maptype[mapno]);
67638032Speter		if (strcmp("files", maptype[mapno]) == 0)
67738032Speter		{
67864562Sgshapiro			found = text_getcanonname(host, hbsize, &status);
67938032Speter		}
68038032Speter#ifdef NIS
68138032Speter		else if (strcmp("nis", maptype[mapno]) == 0)
68238032Speter		{
68364562Sgshapiro			found = nis_getcanonname(host, hbsize, &status);
68438032Speter		}
68564562Sgshapiro#endif /* NIS */
68638032Speter#ifdef NISPLUS
68738032Speter		else if (strcmp("nisplus", maptype[mapno]) == 0)
68838032Speter		{
68964562Sgshapiro			found = nisplus_getcanonname(host, hbsize, &status);
69038032Speter		}
69164562Sgshapiro#endif /* NISPLUS */
69238032Speter#if NAMED_BIND
69338032Speter		else if (strcmp("dns", maptype[mapno]) == 0)
69438032Speter		{
69564562Sgshapiro			found = dns_getcanonname(host, hbsize, trymx, &status);
69638032Speter		}
69764562Sgshapiro#endif /* NAMED_BIND */
69838032Speter#if NETINFO
69938032Speter		else if (strcmp("netinfo", maptype[mapno]) == 0)
70038032Speter		{
70164562Sgshapiro			found = ni_getcanonname(host, hbsize, &status);
70238032Speter		}
70364562Sgshapiro#endif /* NETINFO */
70438032Speter		else
70538032Speter		{
70638032Speter			found = FALSE;
70764562Sgshapiro			status = EX_UNAVAILABLE;
70838032Speter		}
70938032Speter
71038032Speter		/*
71138032Speter		**  Heuristic: if $m is not set, we are running during system
71238032Speter		**  startup.  In this case, when a name is apparently found
71338032Speter		**  but has no dot, treat is as not found.  This avoids
71438032Speter		**  problems if /etc/hosts has no FQDN but is listed first
71538032Speter		**  in the service switch.
71638032Speter		*/
71738032Speter
71838032Speter		if (found &&
71938032Speter		    (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
72038032Speter			break;
72138032Speter
72238032Speter		/* see if we should continue */
72364562Sgshapiro		if (status == EX_TEMPFAIL)
72438032Speter		{
72538032Speter			i = MA_TRYAGAIN;
72638032Speter			got_tempfail = TRUE;
72738032Speter		}
72864562Sgshapiro		else if (status == EX_NOTFOUND)
72938032Speter			i = MA_NOTFOUND;
73038032Speter		else
73138032Speter			i = MA_UNAVAIL;
73238032Speter		if (bitset(1 << mapno, mapreturn[i]))
73338032Speter			break;
73438032Speter	}
73538032Speter
73638032Speter	if (found)
73738032Speter	{
73838032Speter		char *d;
73938032Speter
74038032Speter		if (tTd(38, 20))
74164562Sgshapiro			dprintf("getcanonname(%s), found\n", host);
74238032Speter
74338032Speter		/*
74438032Speter		**  If returned name is still single token, compensate
74538032Speter		**  by tagging on $m.  This is because some sites set
74638032Speter		**  up their DNS or NIS databases wrong.
74738032Speter		*/
74838032Speter
74938032Speter		if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
75038032Speter		{
75138032Speter			d = macvalue('m', CurEnv);
75238032Speter			if (d != NULL &&
75338032Speter			    hbsize > (int) (strlen(host) + strlen(d) + 1))
75438032Speter			{
75538032Speter				if (host[strlen(host) - 1] != '.')
75664562Sgshapiro					(void) strlcat(host, ".", hbsize);
75764562Sgshapiro				(void) strlcat(host, d, hbsize);
75838032Speter			}
75938032Speter			else
76038032Speter				return FALSE;
76138032Speter		}
76238032Speter		return TRUE;
76338032Speter	}
76438032Speter
76538032Speter	if (tTd(38, 20))
76664562Sgshapiro		dprintf("getcanonname(%s), failed, status=%d\n", host, status);
76738032Speter
76838032Speter#if NAMED_BIND
76938032Speter	if (got_tempfail)
77073188Sgshapiro		SM_SET_H_ERRNO(TRY_AGAIN);
77138032Speter	else
77273188Sgshapiro		SM_SET_H_ERRNO(HOST_NOT_FOUND);
77364562Sgshapiro#endif /* NAMED_BIND */
77438032Speter	return FALSE;
77538032Speter}
77638032Speter/*
77738032Speter**  EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
77838032Speter**
77938032Speter**	Parameters:
78038032Speter**		name -- the name against which to match.
78173188Sgshapiro**		dot -- where to reinsert '.' to get FQDN
78238032Speter**		line -- the /etc/hosts line.
78338032Speter**		cbuf -- the location to store the result.
78438032Speter**		cbuflen -- the size of cbuf.
78538032Speter**
78638032Speter**	Returns:
78738032Speter**		TRUE -- if the line matched the desired name.
78838032Speter**		FALSE -- otherwise.
78938032Speter*/
79038032Speter
79164562Sgshapirostatic bool
79273188Sgshapiroextract_canonname(name, dot, line, cbuf, cbuflen)
79338032Speter	char *name;
79473188Sgshapiro	char *dot;
79538032Speter	char *line;
79638032Speter	char cbuf[];
79738032Speter	int cbuflen;
79838032Speter{
79938032Speter	int i;
80038032Speter	char *p;
80138032Speter	bool found = FALSE;
80238032Speter
80338032Speter	cbuf[0] = '\0';
80438032Speter	if (line[0] == '#')
80538032Speter		return FALSE;
80638032Speter
80738032Speter	for (i = 1; ; i++)
80838032Speter	{
80938032Speter		char nbuf[MAXNAME + 1];
81038032Speter
81138032Speter		p = get_column(line, i, '\0', nbuf, sizeof nbuf);
81238032Speter		if (p == NULL)
81338032Speter			break;
81438032Speter		if (*p == '\0')
81538032Speter			continue;
81638032Speter		if (cbuf[0] == '\0' ||
81738032Speter		    (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
81838032Speter		{
81938032Speter			snprintf(cbuf, cbuflen, "%s", p);
82038032Speter		}
82138032Speter		if (strcasecmp(name, p) == 0)
82238032Speter			found = TRUE;
82373188Sgshapiro		else if (dot != NULL)
82473188Sgshapiro		{
82573188Sgshapiro			/* try looking for the FQDN as well */
82673188Sgshapiro			*dot = '.';
82773188Sgshapiro			if (strcasecmp(name, p) == 0)
82873188Sgshapiro				found = TRUE;
82973188Sgshapiro			*dot = '\0';
83073188Sgshapiro		}
83138032Speter	}
83238032Speter	if (found && strchr(cbuf, '.') == NULL)
83338032Speter	{
83438032Speter		/* try to add a domain on the end of the name */
83538032Speter		char *domain = macvalue('m', CurEnv);
83638032Speter
83738032Speter		if (domain != NULL &&
83864562Sgshapiro		    strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen)
83938032Speter		{
84064562Sgshapiro			p = &cbuf[i];
84138032Speter			*p++ = '.';
84264562Sgshapiro			(void) strlcpy(p, domain, cbuflen - i - 1);
84338032Speter		}
84438032Speter	}
84538032Speter	return found;
84638032Speter}
84738032Speter/*
84838032Speter**  NDBM modules
84938032Speter*/
85038032Speter
85138032Speter#ifdef NDBM
85238032Speter
85338032Speter/*
85438032Speter**  NDBM_MAP_OPEN -- DBM-style map open
85538032Speter*/
85638032Speter
85738032Speterbool
85838032Speterndbm_map_open(map, mode)
85938032Speter	MAP *map;
86038032Speter	int mode;
86138032Speter{
86238032Speter	register DBM *dbm;
86364562Sgshapiro	int save_errno;
86438032Speter	int dfd;
86538032Speter	int pfd;
86664562Sgshapiro	long sff;
86738032Speter	int ret;
86838032Speter	int smode = S_IREAD;
86938032Speter	char dirfile[MAXNAME + 1];
87038032Speter	char pagfile[MAXNAME + 1];
87164562Sgshapiro	struct stat st;
87238032Speter	struct stat std, stp;
87338032Speter
87438032Speter	if (tTd(38, 2))
87564562Sgshapiro		dprintf("ndbm_map_open(%s, %s, %d)\n",
87638032Speter			map->map_mname, map->map_file, mode);
87738032Speter	map->map_lockfd = -1;
87838032Speter	mode &= O_ACCMODE;
87938032Speter
88038032Speter	/* do initial file and directory checks */
88138032Speter	snprintf(dirfile, sizeof dirfile, "%s.dir", map->map_file);
88238032Speter	snprintf(pagfile, sizeof pagfile, "%s.pag", map->map_file);
88338032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
88438032Speter	if (mode == O_RDWR)
88538032Speter	{
88638032Speter		sff |= SFF_CREAT;
88764562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
88838032Speter			sff |= SFF_NOSLINK;
88964562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
89038032Speter			sff |= SFF_NOHLINK;
89138032Speter		smode = S_IWRITE;
89238032Speter	}
89338032Speter	else
89438032Speter	{
89564562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
89638032Speter			sff |= SFF_NOWLINK;
89738032Speter	}
89864562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
89938032Speter		sff |= SFF_SAFEDIRPATH;
90038032Speter	ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
90138032Speter			    sff, smode, &std);
90238032Speter	if (ret == 0)
90338032Speter		ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
90438032Speter			       sff, smode, &stp);
90564562Sgshapiro
90664562Sgshapiro# if !_FFR_REMOVE_AUTOREBUILD
90738032Speter	if (ret == ENOENT && AutoRebuild &&
90838032Speter	    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
90938032Speter	    (bitset(MF_IMPL_NDBM, map->map_mflags) ||
91038032Speter	     bitset(MF_ALIAS, map->map_mflags)) &&
91138032Speter	    mode == O_RDONLY)
91238032Speter	{
91338032Speter		bool impl = bitset(MF_IMPL_NDBM, map->map_mflags);
91438032Speter
91538032Speter		/* may be able to rebuild */
91638032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
91738032Speter		if (!rebuildaliases(map, TRUE))
91838032Speter			return FALSE;
91938032Speter		if (impl)
92038032Speter			return impl_map_open(map, O_RDONLY);
92138032Speter		else
92238032Speter			return ndbm_map_open(map, O_RDONLY);
92338032Speter	}
92464562Sgshapiro# endif /* !_FFR_REMOVE_AUTOREBUILD */
92564562Sgshapiro
92638032Speter	if (ret != 0)
92738032Speter	{
92838032Speter		char *prob = "unsafe";
92938032Speter
93038032Speter		/* cannot open this map */
93138032Speter		if (ret == ENOENT)
93238032Speter			prob = "missing";
93338032Speter		if (tTd(38, 2))
93464562Sgshapiro			dprintf("\t%s map file: %d\n", prob, ret);
93538032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
93638032Speter			syserr("dbm map \"%s\": %s map file %s",
93738032Speter				map->map_mname, prob, map->map_file);
93838032Speter		return FALSE;
93938032Speter	}
94038032Speter	if (std.st_mode == ST_MODE_NOFILE)
94138032Speter		mode |= O_CREAT|O_EXCL;
94238032Speter
94364562Sgshapiro# if LOCK_ON_OPEN
94438032Speter	if (mode == O_RDONLY)
94538032Speter		mode |= O_SHLOCK;
94638032Speter	else
94738032Speter		mode |= O_TRUNC|O_EXLOCK;
94864562Sgshapiro# else /* LOCK_ON_OPEN */
94938032Speter	if ((mode & O_ACCMODE) == O_RDWR)
95038032Speter	{
95164562Sgshapiro#  if NOFTRUNCATE
95238032Speter		/*
95338032Speter		**  Warning: race condition.  Try to lock the file as
95438032Speter		**  quickly as possible after opening it.
95538032Speter		**	This may also have security problems on some systems,
95638032Speter		**	but there isn't anything we can do about it.
95738032Speter		*/
95838032Speter
95938032Speter		mode |= O_TRUNC;
96064562Sgshapiro#  else /* NOFTRUNCATE */
96138032Speter		/*
96238032Speter		**  This ugly code opens the map without truncating it,
96338032Speter		**  locks the file, then truncates it.  Necessary to
96438032Speter		**  avoid race conditions.
96538032Speter		*/
96638032Speter
96738032Speter		int dirfd;
96838032Speter		int pagfd;
96964562Sgshapiro		long sff = SFF_CREAT|SFF_OPENASROOT;
97038032Speter
97164562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
97238032Speter			sff |= SFF_NOSLINK;
97364562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
97438032Speter			sff |= SFF_NOHLINK;
97538032Speter
97638032Speter		dirfd = safeopen(dirfile, mode, DBMMODE, sff);
97738032Speter		pagfd = safeopen(pagfile, mode, DBMMODE, sff);
97838032Speter
97938032Speter		if (dirfd < 0 || pagfd < 0)
98038032Speter		{
98164562Sgshapiro			save_errno = errno;
98238032Speter			if (dirfd >= 0)
98338032Speter				(void) close(dirfd);
98438032Speter			if (pagfd >= 0)
98538032Speter				(void) close(pagfd);
98638032Speter			errno = save_errno;
98738032Speter			syserr("ndbm_map_open: cannot create database %s",
98838032Speter				map->map_file);
98938032Speter			return FALSE;
99038032Speter		}
99138032Speter		if (ftruncate(dirfd, (off_t) 0) < 0 ||
99238032Speter		    ftruncate(pagfd, (off_t) 0) < 0)
99338032Speter		{
99464562Sgshapiro			save_errno = errno;
99538032Speter			(void) close(dirfd);
99638032Speter			(void) close(pagfd);
99738032Speter			errno = save_errno;
99838032Speter			syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
99938032Speter				map->map_file);
100038032Speter			return FALSE;
100138032Speter		}
100238032Speter
100338032Speter		/* if new file, get "before" bits for later filechanged check */
100438032Speter		if (std.st_mode == ST_MODE_NOFILE &&
100538032Speter		    (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
100638032Speter		{
100764562Sgshapiro			save_errno = errno;
100838032Speter			(void) close(dirfd);
100938032Speter			(void) close(pagfd);
101038032Speter			errno = save_errno;
101138032Speter			syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
101238032Speter				map->map_file);
101338032Speter			return FALSE;
101438032Speter		}
101538032Speter
101638032Speter		/* have to save the lock for the duration (bletch) */
101738032Speter		map->map_lockfd = dirfd;
101864562Sgshapiro		(void) close(pagfd);
101938032Speter
102038032Speter		/* twiddle bits for dbm_open */
102138032Speter		mode &= ~(O_CREAT|O_EXCL);
102264562Sgshapiro#  endif /* NOFTRUNCATE */
102338032Speter	}
102464562Sgshapiro# endif /* LOCK_ON_OPEN */
102538032Speter
102638032Speter	/* open the database */
102738032Speter	dbm = dbm_open(map->map_file, mode, DBMMODE);
102838032Speter	if (dbm == NULL)
102938032Speter	{
103064562Sgshapiro		save_errno = errno;
103138032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
103238032Speter		    aliaswait(map, ".pag", FALSE))
103338032Speter			return TRUE;
103464562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
103538032Speter		if (map->map_lockfd >= 0)
103664562Sgshapiro			(void) close(map->map_lockfd);
103764562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
103838032Speter		errno = save_errno;
103938032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
104038032Speter			syserr("Cannot open DBM database %s", map->map_file);
104138032Speter		return FALSE;
104238032Speter	}
104338032Speter	dfd = dbm_dirfno(dbm);
104438032Speter	pfd = dbm_pagfno(dbm);
104538032Speter	if (dfd == pfd)
104638032Speter	{
104738032Speter		/* heuristic: if files are linked, this is actually gdbm */
104838032Speter		dbm_close(dbm);
104964562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
105038032Speter		if (map->map_lockfd >= 0)
105164562Sgshapiro			(void) close(map->map_lockfd);
105264562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
105338032Speter		errno = 0;
105438032Speter		syserr("dbm map \"%s\": cannot support GDBM",
105538032Speter			map->map_mname);
105638032Speter		return FALSE;
105738032Speter	}
105838032Speter
105938032Speter	if (filechanged(dirfile, dfd, &std) ||
106038032Speter	    filechanged(pagfile, pfd, &stp))
106138032Speter	{
106264562Sgshapiro		save_errno = errno;
106338032Speter		dbm_close(dbm);
106464562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE
106538032Speter		if (map->map_lockfd >= 0)
106664562Sgshapiro			(void) close(map->map_lockfd);
106764562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
106838032Speter		errno = save_errno;
106938032Speter		syserr("ndbm_map_open(%s): file changed after open",
107038032Speter			map->map_file);
107138032Speter		return FALSE;
107238032Speter	}
107338032Speter
107438032Speter	map->map_db1 = (ARBPTR_T) dbm;
107564562Sgshapiro
107664562Sgshapiro	/*
107764562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
107864562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
107964562Sgshapiro	**  map_mtime to be set
108064562Sgshapiro	*/
108164562Sgshapiro
108264562Sgshapiro	if (fstat(dfd, &st) >= 0)
108364562Sgshapiro		map->map_mtime = st.st_mtime;
108464562Sgshapiro
108538032Speter	if (mode == O_RDONLY)
108638032Speter	{
108764562Sgshapiro# if LOCK_ON_OPEN
108838032Speter		if (dfd >= 0)
108938032Speter			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
109038032Speter		if (pfd >= 0)
109138032Speter			(void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
109264562Sgshapiro# endif /* LOCK_ON_OPEN */
109338032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
109438032Speter		    !aliaswait(map, ".pag", TRUE))
109538032Speter			return FALSE;
109638032Speter	}
109738032Speter	else
109838032Speter	{
109938032Speter		map->map_mflags |= MF_LOCKED;
110042575Speter		if (geteuid() == 0 && TrustedUid != 0)
110138032Speter		{
110264562Sgshapiro#  if HASFCHOWN
110342575Speter			if (fchown(dfd, TrustedUid, -1) < 0 ||
110442575Speter			    fchown(pfd, TrustedUid, -1) < 0)
110538032Speter			{
110638032Speter				int err = errno;
110738032Speter
110838032Speter				sm_syslog(LOG_ALERT, NOQID,
110938032Speter					  "ownership change on %s failed: %s",
111038032Speter					  map->map_file, errstring(err));
111138032Speter				message("050 ownership change on %s failed: %s",
111238032Speter					map->map_file, errstring(err));
111338032Speter			}
111464562Sgshapiro#  endif /* HASFCHOWN */
111538032Speter		}
111638032Speter	}
111738032Speter	return TRUE;
111838032Speter}
111938032Speter
112038032Speter
112138032Speter/*
112238032Speter**  NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
112338032Speter*/
112438032Speter
112538032Speterchar *
112638032Speterndbm_map_lookup(map, name, av, statp)
112738032Speter	MAP *map;
112838032Speter	char *name;
112938032Speter	char **av;
113038032Speter	int *statp;
113138032Speter{
113238032Speter	datum key, val;
113338032Speter	int fd;
113438032Speter	char keybuf[MAXNAME + 1];
113538032Speter	struct stat stbuf;
113638032Speter
113738032Speter	if (tTd(38, 20))
113864562Sgshapiro		dprintf("ndbm_map_lookup(%s, %s)\n",
113938032Speter			map->map_mname, name);
114038032Speter
114138032Speter	key.dptr = name;
114238032Speter	key.dsize = strlen(name);
114338032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
114438032Speter	{
114538032Speter		if (key.dsize > sizeof keybuf - 1)
114638032Speter			key.dsize = sizeof keybuf - 1;
114764562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
114838032Speter		keybuf[key.dsize] = '\0';
114938032Speter		makelower(keybuf);
115038032Speter		key.dptr = keybuf;
115138032Speter	}
115238032Speterlockdbm:
115338032Speter	fd = dbm_dirfno((DBM *) map->map_db1);
115438032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
115538032Speter		(void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
115638032Speter	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
115738032Speter	{
115838032Speter		/* Reopen the database to sync the cache */
115938032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
116038032Speter								 : O_RDONLY;
116138032Speter
116264562Sgshapiro		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
116364562Sgshapiro			(void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
116438032Speter		map->map_class->map_close(map);
116538032Speter		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
116638032Speter		if (map->map_class->map_open(map, omode))
116738032Speter		{
116838032Speter			map->map_mflags |= MF_OPEN;
116942575Speter			map->map_pid = getpid();
117038032Speter			if ((omode && O_ACCMODE) == O_RDWR)
117138032Speter				map->map_mflags |= MF_WRITABLE;
117238032Speter			goto lockdbm;
117338032Speter		}
117438032Speter		else
117538032Speter		{
117638032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
117738032Speter			{
117838032Speter				extern MAPCLASS BogusMapClass;
117938032Speter
118038032Speter				*statp = EX_TEMPFAIL;
118138032Speter				map->map_class = &BogusMapClass;
118238032Speter				map->map_mflags |= MF_OPEN;
118342575Speter				map->map_pid = getpid();
118438032Speter				syserr("Cannot reopen NDBM database %s",
118538032Speter					map->map_file);
118638032Speter			}
118738032Speter			return NULL;
118838032Speter		}
118938032Speter	}
119038032Speter	val.dptr = NULL;
119138032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
119238032Speter	{
119338032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
119438032Speter		if (val.dptr != NULL)
119538032Speter			map->map_mflags &= ~MF_TRY1NULL;
119638032Speter	}
119738032Speter	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
119838032Speter	{
119938032Speter		key.dsize++;
120038032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
120138032Speter		if (val.dptr != NULL)
120238032Speter			map->map_mflags &= ~MF_TRY0NULL;
120338032Speter	}
120438032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
120538032Speter		(void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
120638032Speter	if (val.dptr == NULL)
120738032Speter		return NULL;
120838032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
120938032Speter		return map_rewrite(map, name, strlen(name), NULL);
121038032Speter	else
121138032Speter		return map_rewrite(map, val.dptr, val.dsize, av);
121238032Speter}
121338032Speter
121438032Speter
121538032Speter/*
121638032Speter**  NDBM_MAP_STORE -- store a datum in the database
121738032Speter*/
121838032Speter
121938032Spetervoid
122038032Speterndbm_map_store(map, lhs, rhs)
122138032Speter	register MAP *map;
122238032Speter	char *lhs;
122338032Speter	char *rhs;
122438032Speter{
122538032Speter	datum key;
122638032Speter	datum data;
122764562Sgshapiro	int status;
122838032Speter	char keybuf[MAXNAME + 1];
122938032Speter
123038032Speter	if (tTd(38, 12))
123164562Sgshapiro		dprintf("ndbm_map_store(%s, %s, %s)\n",
123238032Speter			map->map_mname, lhs, rhs);
123338032Speter
123438032Speter	key.dsize = strlen(lhs);
123538032Speter	key.dptr = lhs;
123638032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
123738032Speter	{
123838032Speter		if (key.dsize > sizeof keybuf - 1)
123938032Speter			key.dsize = sizeof keybuf - 1;
124064562Sgshapiro		memmove(keybuf, key.dptr, key.dsize);
124138032Speter		keybuf[key.dsize] = '\0';
124238032Speter		makelower(keybuf);
124338032Speter		key.dptr = keybuf;
124438032Speter	}
124538032Speter
124638032Speter	data.dsize = strlen(rhs);
124738032Speter	data.dptr = rhs;
124838032Speter
124938032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
125038032Speter	{
125138032Speter		key.dsize++;
125238032Speter		data.dsize++;
125338032Speter	}
125438032Speter
125564562Sgshapiro	status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
125664562Sgshapiro	if (status > 0)
125738032Speter	{
125838032Speter		if (!bitset(MF_APPEND, map->map_mflags))
125938032Speter			message("050 Warning: duplicate alias name %s", lhs);
126038032Speter		else
126138032Speter		{
126238032Speter			static char *buf = NULL;
126338032Speter			static int bufsiz = 0;
126438032Speter			auto int xstat;
126538032Speter			datum old;
126638032Speter
126738032Speter			old.dptr = ndbm_map_lookup(map, key.dptr,
126838032Speter						   (char **)NULL, &xstat);
126938032Speter			if (old.dptr != NULL && *(char *) old.dptr != '\0')
127038032Speter			{
127138032Speter				old.dsize = strlen(old.dptr);
127238032Speter				if (data.dsize + old.dsize + 2 > bufsiz)
127338032Speter				{
127438032Speter					if (buf != NULL)
127538032Speter						(void) free(buf);
127638032Speter					bufsiz = data.dsize + old.dsize + 2;
127738032Speter					buf = xalloc(bufsiz);
127838032Speter				}
127938032Speter				snprintf(buf, bufsiz, "%s,%s",
128038032Speter					data.dptr, old.dptr);
128138032Speter				data.dsize = data.dsize + old.dsize + 1;
128238032Speter				data.dptr = buf;
128338032Speter				if (tTd(38, 9))
128464562Sgshapiro					dprintf("ndbm_map_store append=%s\n",
128564562Sgshapiro						data.dptr);
128638032Speter			}
128738032Speter		}
128864562Sgshapiro		status = dbm_store((DBM *) map->map_db1,
128964562Sgshapiro				   key, data, DBM_REPLACE);
129038032Speter	}
129164562Sgshapiro	if (status != 0)
129264562Sgshapiro		syserr("readaliases: dbm put (%s): %d", lhs, status);
129338032Speter}
129438032Speter
129538032Speter
129638032Speter/*
129738032Speter**  NDBM_MAP_CLOSE -- close the database
129838032Speter*/
129938032Speter
130038032Spetervoid
130138032Speterndbm_map_close(map)
130238032Speter	register MAP  *map;
130338032Speter{
130438032Speter	if (tTd(38, 9))
130564562Sgshapiro		dprintf("ndbm_map_close(%s, %s, %lx)\n",
130638032Speter			map->map_mname, map->map_file, map->map_mflags);
130738032Speter
130838032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
130938032Speter	{
131064562Sgshapiro# ifdef NDBM_YP_COMPAT
131138032Speter		bool inclnull;
131242575Speter		char buf[MAXHOSTNAMELEN];
131338032Speter
131438032Speter		inclnull = bitset(MF_INCLNULL, map->map_mflags);
131538032Speter		map->map_mflags &= ~MF_INCLNULL;
131638032Speter
131738032Speter		if (strstr(map->map_file, "/yp/") != NULL)
131838032Speter		{
131938032Speter			long save_mflags = map->map_mflags;
132038032Speter
132138032Speter			map->map_mflags |= MF_NOFOLDCASE;
132238032Speter
132338032Speter			(void) snprintf(buf, sizeof buf, "%010ld", curtime());
132438032Speter			ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
132538032Speter
132638032Speter			(void) gethostname(buf, sizeof buf);
132738032Speter			ndbm_map_store(map, "YP_MASTER_NAME", buf);
132838032Speter
132938032Speter			map->map_mflags = save_mflags;
133038032Speter		}
133138032Speter
133238032Speter		if (inclnull)
133338032Speter			map->map_mflags |= MF_INCLNULL;
133464562Sgshapiro# endif /* NDBM_YP_COMPAT */
133538032Speter
133638032Speter		/* write out the distinguished alias */
133738032Speter		ndbm_map_store(map, "@", "@");
133838032Speter	}
133938032Speter	dbm_close((DBM *) map->map_db1);
134038032Speter
134138032Speter	/* release lock (if needed) */
134264562Sgshapiro# if !LOCK_ON_OPEN
134338032Speter	if (map->map_lockfd >= 0)
134438032Speter		(void) close(map->map_lockfd);
134564562Sgshapiro# endif /* !LOCK_ON_OPEN */
134638032Speter}
134738032Speter
134864562Sgshapiro#endif /* NDBM */
134938032Speter/*
135038032Speter**  NEWDB (Hash and BTree) Modules
135138032Speter*/
135238032Speter
135338032Speter#ifdef NEWDB
135438032Speter
135538032Speter/*
135638032Speter**  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
135738032Speter**
135838032Speter**	These do rather bizarre locking.  If you can lock on open,
135938032Speter**	do that to avoid the condition of opening a database that
136038032Speter**	is being rebuilt.  If you don't, we'll try to fake it, but
136138032Speter**	there will be a race condition.  If opening for read-only,
136238032Speter**	we immediately release the lock to avoid freezing things up.
136338032Speter**	We really ought to hold the lock, but guarantee that we won't
136438032Speter**	be pokey about it.  That's hard to do.
136538032Speter*/
136638032Speter
136738032Speter/* these should be K line arguments */
136864562Sgshapiro# if DB_VERSION_MAJOR < 2
136964562Sgshapiro#  define db_cachesize	cachesize
137064562Sgshapiro#  define h_nelem	nelem
137164562Sgshapiro#  ifndef DB_CACHE_SIZE
137264562Sgshapiro#   define DB_CACHE_SIZE	(1024 * 1024)	/* database memory cache size */
137364562Sgshapiro#  endif /* ! DB_CACHE_SIZE */
137464562Sgshapiro#  ifndef DB_HASH_NELEM
137564562Sgshapiro#   define DB_HASH_NELEM	4096		/* (starting) size of hash table */
137664562Sgshapiro#  endif /* ! DB_HASH_NELEM */
137764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
137838032Speter
137938032Speterbool
138038032Speterbt_map_open(map, mode)
138138032Speter	MAP *map;
138238032Speter	int mode;
138338032Speter{
138464562Sgshapiro# if DB_VERSION_MAJOR < 2
138538032Speter	BTREEINFO btinfo;
138664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
138764562Sgshapiro# if DB_VERSION_MAJOR == 2
138838032Speter	DB_INFO btinfo;
138964562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
139064562Sgshapiro# if DB_VERSION_MAJOR > 2
139164562Sgshapiro	void *btinfo = NULL;
139264562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
139338032Speter
139438032Speter	if (tTd(38, 2))
139564562Sgshapiro		dprintf("bt_map_open(%s, %s, %d)\n",
139638032Speter			map->map_mname, map->map_file, mode);
139738032Speter
139864562Sgshapiro# if DB_VERSION_MAJOR < 3
139964562Sgshapiro	memset(&btinfo, '\0', sizeof btinfo);
140064562Sgshapiro#  ifdef DB_CACHE_SIZE
140138032Speter	btinfo.db_cachesize = DB_CACHE_SIZE;
140264562Sgshapiro#  endif /* DB_CACHE_SIZE */
140364562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
140464562Sgshapiro
140538032Speter	return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
140638032Speter}
140738032Speter
140838032Speterbool
140938032Speterhash_map_open(map, mode)
141038032Speter	MAP *map;
141138032Speter	int mode;
141238032Speter{
141364562Sgshapiro# if DB_VERSION_MAJOR < 2
141438032Speter	HASHINFO hinfo;
141564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
141664562Sgshapiro# if DB_VERSION_MAJOR == 2
141738032Speter	DB_INFO hinfo;
141864562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
141964562Sgshapiro# if DB_VERSION_MAJOR > 2
142064562Sgshapiro	void *hinfo = NULL;
142164562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
142238032Speter
142338032Speter	if (tTd(38, 2))
142464562Sgshapiro		dprintf("hash_map_open(%s, %s, %d)\n",
142538032Speter			map->map_mname, map->map_file, mode);
142638032Speter
142764562Sgshapiro# if DB_VERSION_MAJOR < 3
142864562Sgshapiro	memset(&hinfo, '\0', sizeof hinfo);
142964562Sgshapiro#  ifdef DB_HASH_NELEM
143038032Speter	hinfo.h_nelem = DB_HASH_NELEM;
143164562Sgshapiro#  endif /* DB_HASH_NELEM */
143264562Sgshapiro#  ifdef DB_CACHE_SIZE
143338032Speter	hinfo.db_cachesize = DB_CACHE_SIZE;
143464562Sgshapiro#  endif /* DB_CACHE_SIZE */
143564562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */
143664562Sgshapiro
143738032Speter	return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
143838032Speter}
143938032Speter
144064562Sgshapirostatic bool
144138032Speterdb_map_open(map, mode, mapclassname, dbtype, openinfo)
144238032Speter	MAP *map;
144338032Speter	int mode;
144438032Speter	char *mapclassname;
144538032Speter	DBTYPE dbtype;
144664562Sgshapiro# if DB_VERSION_MAJOR < 2
144738032Speter	const void *openinfo;
144864562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
144964562Sgshapiro# if DB_VERSION_MAJOR == 2
145038032Speter	DB_INFO *openinfo;
145164562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */
145264562Sgshapiro# if DB_VERSION_MAJOR > 2
145364562Sgshapiro	void **openinfo;
145464562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */
145538032Speter{
145638032Speter	DB *db = NULL;
145738032Speter	int i;
145838032Speter	int omode;
145938032Speter	int smode = S_IREAD;
146038032Speter	int fd;
146164562Sgshapiro	long sff;
146264562Sgshapiro	int save_errno;
146338032Speter	struct stat st;
146438032Speter	char buf[MAXNAME + 1];
146538032Speter
146638032Speter	/* do initial file and directory checks */
146764562Sgshapiro	(void) strlcpy(buf, map->map_file, sizeof buf - 3);
146838032Speter	i = strlen(buf);
146938032Speter	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
147064562Sgshapiro		(void) strlcat(buf, ".db", sizeof buf);
147138032Speter
147238032Speter	mode &= O_ACCMODE;
147338032Speter	omode = mode;
147438032Speter
147538032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
147638032Speter	if (mode == O_RDWR)
147738032Speter	{
147838032Speter		sff |= SFF_CREAT;
147964562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
148038032Speter			sff |= SFF_NOSLINK;
148164562Sgshapiro		if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
148238032Speter			sff |= SFF_NOHLINK;
148338032Speter		smode = S_IWRITE;
148438032Speter	}
148538032Speter	else
148638032Speter	{
148764562Sgshapiro		if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
148838032Speter			sff |= SFF_NOWLINK;
148938032Speter	}
149064562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
149138032Speter		sff |= SFF_SAFEDIRPATH;
149238032Speter	i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
149364562Sgshapiro
149464562Sgshapiro# if !_FFR_REMOVE_AUTOREBUILD
149538032Speter	if (i == ENOENT && AutoRebuild &&
149638032Speter	    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
149738032Speter	    (bitset(MF_IMPL_HASH, map->map_mflags) ||
149838032Speter	     bitset(MF_ALIAS, map->map_mflags)) &&
149938032Speter	    mode == O_RDONLY)
150038032Speter	{
150138032Speter		bool impl = bitset(MF_IMPL_HASH, map->map_mflags);
150238032Speter
150338032Speter		/* may be able to rebuild */
150438032Speter		map->map_mflags &= ~MF_IMPL_HASH;
150538032Speter		if (!rebuildaliases(map, TRUE))
150638032Speter			return FALSE;
150738032Speter		if (impl)
150838032Speter			return impl_map_open(map, O_RDONLY);
150938032Speter		else
151038032Speter			return db_map_open(map, O_RDONLY, mapclassname,
151138032Speter					   dbtype, openinfo);
151238032Speter	}
151364562Sgshapiro# endif /* !_FFR_REMOVE_AUTOREBUILD */
151438032Speter
151538032Speter	if (i != 0)
151638032Speter	{
151738032Speter		char *prob = "unsafe";
151838032Speter
151938032Speter		/* cannot open this map */
152038032Speter		if (i == ENOENT)
152138032Speter			prob = "missing";
152238032Speter		if (tTd(38, 2))
152364562Sgshapiro			dprintf("\t%s map file: %s\n", prob, errstring(i));
152438032Speter		errno = i;
152538032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
152638032Speter			syserr("%s map \"%s\": %s map file %s",
152738032Speter				mapclassname, map->map_mname, prob, buf);
152838032Speter		return FALSE;
152938032Speter	}
153038032Speter	if (st.st_mode == ST_MODE_NOFILE)
153138032Speter		omode |= O_CREAT|O_EXCL;
153238032Speter
153338032Speter	map->map_lockfd = -1;
153438032Speter
153564562Sgshapiro# if LOCK_ON_OPEN
153638032Speter	if (mode == O_RDWR)
153738032Speter		omode |= O_TRUNC|O_EXLOCK;
153838032Speter	else
153938032Speter		omode |= O_SHLOCK;
154064562Sgshapiro# else /* LOCK_ON_OPEN */
154138032Speter	/*
154238032Speter	**  Pre-lock the file to avoid race conditions.  In particular,
154338032Speter	**  since dbopen returns NULL if the file is zero length, we
154438032Speter	**  must have a locked instance around the dbopen.
154538032Speter	*/
154638032Speter
154738032Speter	fd = open(buf, omode, DBMMODE);
154838032Speter	if (fd < 0)
154938032Speter	{
155038032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
155138032Speter			syserr("db_map_open: cannot pre-open database %s", buf);
155238032Speter		return FALSE;
155338032Speter	}
155438032Speter
155538032Speter	/* make sure no baddies slipped in just before the open... */
155638032Speter	if (filechanged(buf, fd, &st))
155738032Speter	{
155864562Sgshapiro		save_errno = errno;
155938032Speter		(void) close(fd);
156038032Speter		errno = save_errno;
156138032Speter		syserr("db_map_open(%s): file changed after pre-open", buf);
156238032Speter		return FALSE;
156338032Speter	}
156438032Speter
156538032Speter	/* if new file, get the "before" bits for later filechanged check */
156638032Speter	if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
156738032Speter	{
156864562Sgshapiro		save_errno = errno;
156938032Speter		(void) close(fd);
157038032Speter		errno = save_errno;
157138032Speter		syserr("db_map_open(%s): cannot fstat pre-opened file",
157238032Speter			buf);
157338032Speter		return FALSE;
157438032Speter	}
157538032Speter
157638032Speter	/* actually lock the pre-opened file */
157738032Speter	if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
157838032Speter		syserr("db_map_open: cannot lock %s", buf);
157938032Speter
158038032Speter	/* set up mode bits for dbopen */
158138032Speter	if (mode == O_RDWR)
158238032Speter		omode |= O_TRUNC;
158338032Speter	omode &= ~(O_EXCL|O_CREAT);
158464562Sgshapiro# endif /* LOCK_ON_OPEN */
158538032Speter
158664562Sgshapiro# if DB_VERSION_MAJOR < 2
158738032Speter	db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
158864562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
158938032Speter	{
159038032Speter		int flags = 0;
159164562Sgshapiro#  if DB_VERSION_MAJOR > 2
159264562Sgshapiro		int ret;
159364562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
159438032Speter
159538032Speter		if (mode == O_RDONLY)
159638032Speter			flags |= DB_RDONLY;
159738032Speter		if (bitset(O_CREAT, omode))
159838032Speter			flags |= DB_CREATE;
159938032Speter		if (bitset(O_TRUNC, omode))
160038032Speter			flags |= DB_TRUNCATE;
160138032Speter
160264562Sgshapiro#  if !HASFLOCK && defined(DB_FCNTL_LOCKING)
160364562Sgshapiro		flags |= DB_FCNTL_LOCKING;
160464562Sgshapiro#  endif /* !HASFLOCK && defined(DB_FCNTL_LOCKING) */
160564562Sgshapiro
160664562Sgshapiro#  if DB_VERSION_MAJOR > 2
160764562Sgshapiro		ret = db_create(&db, NULL, 0);
160864562Sgshapiro#  ifdef DB_CACHE_SIZE
160964562Sgshapiro		if (ret == 0 && db != NULL)
161064562Sgshapiro		{
161164562Sgshapiro			ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0);
161264562Sgshapiro			if (ret != 0)
161364562Sgshapiro			{
161464562Sgshapiro				(void) db->close(db, 0);
161564562Sgshapiro				db = NULL;
161664562Sgshapiro			}
161764562Sgshapiro		}
161864562Sgshapiro#  endif /* DB_CACHE_SIZE */
161964562Sgshapiro#  ifdef DB_HASH_NELEM
162064562Sgshapiro		if (dbtype == DB_HASH && ret == 0 && db != NULL)
162164562Sgshapiro		{
162264562Sgshapiro			ret = db->set_h_nelem(db, DB_HASH_NELEM);
162364562Sgshapiro			if (ret != 0)
162464562Sgshapiro			{
162564562Sgshapiro				(void) db->close(db, 0);
162664562Sgshapiro				db = NULL;
162764562Sgshapiro			}
162864562Sgshapiro		}
162964562Sgshapiro#  endif /* DB_HASH_NELEM */
163064562Sgshapiro		if (ret == 0 && db != NULL)
163164562Sgshapiro		{
163264562Sgshapiro			ret = db->open(db, buf, NULL, dbtype, flags, DBMMODE);
163364562Sgshapiro			if (ret != 0)
163464562Sgshapiro			{
163573188Sgshapiro#ifdef DB_OLD_VERSION
163673188Sgshapiro				if (ret == DB_OLD_VERSION)
163773188Sgshapiro					ret = EINVAL;
163873188Sgshapiro#endif /* DB_OLD_VERSION */
163964562Sgshapiro				(void) db->close(db, 0);
164064562Sgshapiro				db = NULL;
164164562Sgshapiro			}
164264562Sgshapiro		}
164364562Sgshapiro		errno = ret;
164464562Sgshapiro#  else /* DB_VERSION_MAJOR > 2 */
164538032Speter		errno = db_open(buf, dbtype, flags, DBMMODE,
164638032Speter				NULL, openinfo, &db);
164764562Sgshapiro#  endif /* DB_VERSION_MAJOR > 2 */
164838032Speter	}
164964562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
165064562Sgshapiro	save_errno = errno;
165138032Speter
165264562Sgshapiro# if !LOCK_ON_OPEN
165338032Speter	if (mode == O_RDWR)
165438032Speter		map->map_lockfd = fd;
165538032Speter	else
165638032Speter		(void) close(fd);
165764562Sgshapiro# endif /* !LOCK_ON_OPEN */
165838032Speter
165938032Speter	if (db == NULL)
166038032Speter	{
166138032Speter		if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
166238032Speter		    aliaswait(map, ".db", FALSE))
166338032Speter			return TRUE;
166464562Sgshapiro# if !LOCK_ON_OPEN
166538032Speter		if (map->map_lockfd >= 0)
166638032Speter			(void) close(map->map_lockfd);
166764562Sgshapiro# endif /* !LOCK_ON_OPEN */
166864562Sgshapiro		errno = save_errno;
166938032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
167038032Speter			syserr("Cannot open %s database %s",
167138032Speter				mapclassname, buf);
167238032Speter		return FALSE;
167338032Speter	}
167438032Speter
167564562Sgshapiro# if DB_VERSION_MAJOR < 2
167638032Speter	fd = db->fd(db);
167764562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
167838032Speter	fd = -1;
167938032Speter	errno = db->fd(db, &fd);
168064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
168138032Speter	if (filechanged(buf, fd, &st))
168238032Speter	{
168364562Sgshapiro		save_errno = errno;
168464562Sgshapiro# if DB_VERSION_MAJOR < 2
168564562Sgshapiro		(void) db->close(db);
168664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
168738032Speter		errno = db->close(db, 0);
168864562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
168964562Sgshapiro# if !LOCK_ON_OPEN
169038032Speter		if (map->map_lockfd >= 0)
169164562Sgshapiro			(void) close(map->map_lockfd);
169264562Sgshapiro# endif /* !LOCK_ON_OPEN */
169338032Speter		errno = save_errno;
169438032Speter		syserr("db_map_open(%s): file changed after open", buf);
169538032Speter		return FALSE;
169638032Speter	}
169738032Speter
169838032Speter	if (mode == O_RDWR)
169938032Speter		map->map_mflags |= MF_LOCKED;
170064562Sgshapiro# if LOCK_ON_OPEN
170138032Speter	if (fd >= 0 && mode == O_RDONLY)
170238032Speter	{
170338032Speter		(void) lockfile(fd, buf, NULL, LOCK_UN);
170438032Speter	}
170564562Sgshapiro# endif /* LOCK_ON_OPEN */
170638032Speter
170738032Speter	/* try to make sure that at least the database header is on disk */
170838032Speter	if (mode == O_RDWR)
170938032Speter	{
171038032Speter		(void) db->sync(db, 0);
171142575Speter		if (geteuid() == 0 && TrustedUid != 0)
171238032Speter		{
171364562Sgshapiro#  if HASFCHOWN
171442575Speter			if (fchown(fd, TrustedUid, -1) < 0)
171538032Speter			{
171638032Speter				int err = errno;
171738032Speter
171838032Speter				sm_syslog(LOG_ALERT, NOQID,
171938032Speter					  "ownership change on %s failed: %s",
172038032Speter					  buf, errstring(err));
172138032Speter				message("050 ownership change on %s failed: %s",
172238032Speter					buf, errstring(err));
172338032Speter			}
172464562Sgshapiro#  endif /* HASFCHOWN */
172538032Speter		}
172638032Speter	}
172738032Speter
172864562Sgshapiro	map->map_db2 = (ARBPTR_T) db;
172964562Sgshapiro
173064562Sgshapiro	/*
173164562Sgshapiro	**  Need to set map_mtime before the call to aliaswait()
173264562Sgshapiro	**  as aliaswait() will call map_lookup() which requires
173364562Sgshapiro	**  map_mtime to be set
173464562Sgshapiro	*/
173564562Sgshapiro
173638032Speter	if (fd >= 0 && fstat(fd, &st) >= 0)
173738032Speter		map->map_mtime = st.st_mtime;
173838032Speter
173938032Speter	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
174038032Speter	    !aliaswait(map, ".db", TRUE))
174138032Speter		return FALSE;
174238032Speter	return TRUE;
174338032Speter}
174438032Speter
174538032Speter
174638032Speter/*
174738032Speter**  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
174838032Speter*/
174938032Speter
175038032Speterchar *
175138032Speterdb_map_lookup(map, name, av, statp)
175238032Speter	MAP *map;
175338032Speter	char *name;
175438032Speter	char **av;
175538032Speter	int *statp;
175638032Speter{
175738032Speter	DBT key, val;
175838032Speter	register DB *db = (DB *) map->map_db2;
175938032Speter	int i;
176038032Speter	int st;
176164562Sgshapiro	int save_errno;
176238032Speter	int fd;
176338032Speter	struct stat stbuf;
176438032Speter	char keybuf[MAXNAME + 1];
176538032Speter	char buf[MAXNAME + 1];
176638032Speter
176764562Sgshapiro	memset(&key, '\0', sizeof key);
176864562Sgshapiro	memset(&val, '\0', sizeof val);
176938032Speter
177038032Speter	if (tTd(38, 20))
177164562Sgshapiro		dprintf("db_map_lookup(%s, %s)\n",
177238032Speter			map->map_mname, name);
177338032Speter
177438032Speter	i = strlen(map->map_file);
177538032Speter	if (i > MAXNAME)
177638032Speter		i = MAXNAME;
177764562Sgshapiro	(void) strlcpy(buf, map->map_file, i + 1);
177838032Speter	if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
177938032Speter		buf[i - 3] = '\0';
178038032Speter
178138032Speter	key.size = strlen(name);
178238032Speter	if (key.size > sizeof keybuf - 1)
178338032Speter		key.size = sizeof keybuf - 1;
178438032Speter	key.data = keybuf;
178564562Sgshapiro	memmove(keybuf, name, key.size);
178638032Speter	keybuf[key.size] = '\0';
178738032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
178838032Speter		makelower(keybuf);
178938032Speter  lockdb:
179064562Sgshapiro# if DB_VERSION_MAJOR < 2
179138032Speter	fd = db->fd(db);
179264562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
179338032Speter	fd = -1;
179438032Speter	errno = db->fd(db, &fd);
179564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
179638032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
179738032Speter		(void) lockfile(fd, buf, ".db", LOCK_SH);
179838032Speter	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
179938032Speter	{
180038032Speter		/* Reopen the database to sync the cache */
180138032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
180238032Speter								 : O_RDONLY;
180338032Speter
180464562Sgshapiro		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
180564562Sgshapiro			(void) lockfile(fd, buf, ".db", LOCK_UN);
180638032Speter		map->map_class->map_close(map);
180738032Speter		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
180838032Speter		if (map->map_class->map_open(map, omode))
180938032Speter		{
181038032Speter			map->map_mflags |= MF_OPEN;
181142575Speter			map->map_pid = getpid();
181238032Speter			if ((omode && O_ACCMODE) == O_RDWR)
181338032Speter				map->map_mflags |= MF_WRITABLE;
181438032Speter			db = (DB *) map->map_db2;
181538032Speter			goto lockdb;
181638032Speter		}
181738032Speter		else
181838032Speter		{
181938032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
182038032Speter			{
182138032Speter				extern MAPCLASS BogusMapClass;
182238032Speter
182338032Speter				*statp = EX_TEMPFAIL;
182438032Speter				map->map_class = &BogusMapClass;
182538032Speter				map->map_mflags |= MF_OPEN;
182642575Speter				map->map_pid = getpid();
182738032Speter				syserr("Cannot reopen DB database %s",
182838032Speter					map->map_file);
182938032Speter			}
183038032Speter			return NULL;
183138032Speter		}
183238032Speter	}
183338032Speter
183438032Speter	st = 1;
183538032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
183638032Speter	{
183764562Sgshapiro# if DB_VERSION_MAJOR < 2
183838032Speter		st = db->get(db, &key, &val, 0);
183964562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
184038032Speter		errno = db->get(db, NULL, &key, &val, 0);
184138032Speter		switch (errno)
184238032Speter		{
184338032Speter		  case DB_NOTFOUND:
184438032Speter		  case DB_KEYEMPTY:
184538032Speter			st = 1;
184638032Speter			break;
184738032Speter
184838032Speter		  case 0:
184938032Speter			st = 0;
185038032Speter			break;
185138032Speter
185238032Speter		  default:
185338032Speter			st = -1;
185438032Speter			break;
185538032Speter		}
185664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
185738032Speter		if (st == 0)
185838032Speter			map->map_mflags &= ~MF_TRY1NULL;
185938032Speter	}
186038032Speter	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
186138032Speter	{
186238032Speter		key.size++;
186364562Sgshapiro# if DB_VERSION_MAJOR < 2
186438032Speter		st = db->get(db, &key, &val, 0);
186564562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
186638032Speter		errno = db->get(db, NULL, &key, &val, 0);
186738032Speter		switch (errno)
186838032Speter		{
186938032Speter		  case DB_NOTFOUND:
187038032Speter		  case DB_KEYEMPTY:
187138032Speter			st = 1;
187238032Speter			break;
187338032Speter
187438032Speter		  case 0:
187538032Speter			st = 0;
187638032Speter			break;
187738032Speter
187838032Speter		  default:
187938032Speter			st = -1;
188038032Speter			break;
188138032Speter		}
188264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
188338032Speter		if (st == 0)
188438032Speter			map->map_mflags &= ~MF_TRY0NULL;
188538032Speter	}
188664562Sgshapiro	save_errno = errno;
188738032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
188838032Speter		(void) lockfile(fd, buf, ".db", LOCK_UN);
188938032Speter	if (st != 0)
189038032Speter	{
189164562Sgshapiro		errno = save_errno;
189238032Speter		if (st < 0)
189338032Speter			syserr("db_map_lookup: get (%s)", name);
189438032Speter		return NULL;
189538032Speter	}
189638032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
189738032Speter		return map_rewrite(map, name, strlen(name), NULL);
189838032Speter	else
189938032Speter		return map_rewrite(map, val.data, val.size, av);
190038032Speter}
190138032Speter
190238032Speter
190338032Speter/*
190438032Speter**  DB_MAP_STORE -- store a datum in the NEWDB database
190538032Speter*/
190638032Speter
190738032Spetervoid
190838032Speterdb_map_store(map, lhs, rhs)
190938032Speter	register MAP *map;
191038032Speter	char *lhs;
191138032Speter	char *rhs;
191238032Speter{
191364562Sgshapiro	int status;
191438032Speter	DBT key;
191538032Speter	DBT data;
191638032Speter	register DB *db = map->map_db2;
191738032Speter	char keybuf[MAXNAME + 1];
191838032Speter
191964562Sgshapiro	memset(&key, '\0', sizeof key);
192064562Sgshapiro	memset(&data, '\0', sizeof data);
192138032Speter
192238032Speter	if (tTd(38, 12))
192364562Sgshapiro		dprintf("db_map_store(%s, %s, %s)\n",
192438032Speter			map->map_mname, lhs, rhs);
192538032Speter
192638032Speter	key.size = strlen(lhs);
192738032Speter	key.data = lhs;
192838032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
192938032Speter	{
193038032Speter		if (key.size > sizeof keybuf - 1)
193138032Speter			key.size = sizeof keybuf - 1;
193264562Sgshapiro		memmove(keybuf, key.data, key.size);
193338032Speter		keybuf[key.size] = '\0';
193438032Speter		makelower(keybuf);
193538032Speter		key.data = keybuf;
193638032Speter	}
193738032Speter
193838032Speter	data.size = strlen(rhs);
193938032Speter	data.data = rhs;
194038032Speter
194138032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
194238032Speter	{
194338032Speter		key.size++;
194438032Speter		data.size++;
194538032Speter	}
194638032Speter
194764562Sgshapiro# if DB_VERSION_MAJOR < 2
194864562Sgshapiro	status = db->put(db, &key, &data, R_NOOVERWRITE);
194964562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
195038032Speter	errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE);
195138032Speter	switch (errno)
195238032Speter	{
195338032Speter	  case DB_KEYEXIST:
195464562Sgshapiro		status = 1;
195538032Speter		break;
195638032Speter
195738032Speter	  case 0:
195864562Sgshapiro		status = 0;
195938032Speter		break;
196038032Speter
196138032Speter	  default:
196264562Sgshapiro		status = -1;
196338032Speter		break;
196438032Speter	}
196564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
196664562Sgshapiro	if (status > 0)
196738032Speter	{
196838032Speter		if (!bitset(MF_APPEND, map->map_mflags))
196938032Speter			message("050 Warning: duplicate alias name %s", lhs);
197038032Speter		else
197138032Speter		{
197238032Speter			static char *buf = NULL;
197338032Speter			static int bufsiz = 0;
197438032Speter			DBT old;
197538032Speter
197664562Sgshapiro			memset(&old, '\0', sizeof old);
197738032Speter
197864562Sgshapiro			old.data = db_map_lookup(map, key.data,
197964562Sgshapiro						 (char **)NULL, &status);
198038032Speter			if (old.data != NULL)
198138032Speter			{
198238032Speter				old.size = strlen(old.data);
198364562Sgshapiro				if (data.size + old.size + 2 > (size_t)bufsiz)
198438032Speter				{
198538032Speter					if (buf != NULL)
198638032Speter						(void) free(buf);
198738032Speter					bufsiz = data.size + old.size + 2;
198838032Speter					buf = xalloc(bufsiz);
198938032Speter				}
199038032Speter				snprintf(buf, bufsiz, "%s,%s",
199138032Speter					(char *) data.data, (char *) old.data);
199238032Speter				data.size = data.size + old.size + 1;
199338032Speter				data.data = buf;
199438032Speter				if (tTd(38, 9))
199564562Sgshapiro					dprintf("db_map_store append=%s\n",
199664562Sgshapiro						(char *) data.data);
199738032Speter			}
199838032Speter		}
199964562Sgshapiro# if DB_VERSION_MAJOR < 2
200064562Sgshapiro		status = db->put(db, &key, &data, 0);
200164562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
200264562Sgshapiro		status = errno = db->put(db, NULL, &key, &data, 0);
200364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
200438032Speter	}
200564562Sgshapiro	if (status != 0)
200638032Speter		syserr("readaliases: db put (%s)", lhs);
200738032Speter}
200838032Speter
200938032Speter
201038032Speter/*
201138032Speter**  DB_MAP_CLOSE -- add distinguished entries and close the database
201238032Speter*/
201338032Speter
201438032Spetervoid
201538032Speterdb_map_close(map)
201638032Speter	MAP *map;
201738032Speter{
201838032Speter	register DB *db = map->map_db2;
201938032Speter
202038032Speter	if (tTd(38, 9))
202164562Sgshapiro		dprintf("db_map_close(%s, %s, %lx)\n",
202238032Speter			map->map_mname, map->map_file, map->map_mflags);
202338032Speter
202438032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
202538032Speter	{
202638032Speter		/* write out the distinguished alias */
202738032Speter		db_map_store(map, "@", "@");
202838032Speter	}
202938032Speter
203038032Speter	(void) db->sync(db, 0);
203138032Speter
203264562Sgshapiro# if !LOCK_ON_OPEN
203338032Speter	if (map->map_lockfd >= 0)
203438032Speter		(void) close(map->map_lockfd);
203564562Sgshapiro# endif /* !LOCK_ON_OPEN */
203638032Speter
203764562Sgshapiro# if DB_VERSION_MAJOR < 2
203838032Speter	if (db->close(db) != 0)
203964562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */
204042575Speter	/*
204142575Speter	**  Berkeley DB can use internal shared memory
204242575Speter	**  locking for its memory pool.  Closing a map
204342575Speter	**  opened by another process will interfere
204442575Speter	**  with the shared memory and locks of the parent
204542575Speter	**  process leaving things in a bad state.
204643730Speter	*/
204743730Speter
204843730Speter	/*
204942575Speter	**  If this map was not opened by the current
205043730Speter	**  process, do not close the map but recover
205142575Speter	**  the file descriptor.
205242575Speter	*/
205342575Speter	if (map->map_pid != getpid())
205442575Speter	{
205542575Speter		int fd = -1;
205642575Speter
205742575Speter		errno = db->fd(db, &fd);
205842575Speter		if (fd >= 0)
205942575Speter			(void) close(fd);
206042575Speter		return;
206142575Speter	}
206242575Speter
206338032Speter	if ((errno = db->close(db, 0)) != 0)
206464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */
206542575Speter		syserr("db_map_close(%s, %s, %lx): db close failure",
206642575Speter			map->map_mname, map->map_file, map->map_mflags);
206738032Speter}
206864562Sgshapiro#endif /* NEWDB */
206938032Speter/*
207038032Speter**  NIS Modules
207138032Speter*/
207238032Speter
207364562Sgshapiro#ifdef NIS
207438032Speter
207538032Speter# ifndef YPERR_BUSY
207638032Speter#  define YPERR_BUSY	16
207764562Sgshapiro# endif /* ! YPERR_BUSY */
207838032Speter
207938032Speter/*
208038032Speter**  NIS_MAP_OPEN -- open DBM map
208138032Speter*/
208238032Speter
208338032Speterbool
208438032Speternis_map_open(map, mode)
208538032Speter	MAP *map;
208638032Speter	int mode;
208738032Speter{
208838032Speter	int yperr;
208938032Speter	register char *p;
209038032Speter	auto char *vp;
209138032Speter	auto int vsize;
209238032Speter
209338032Speter	if (tTd(38, 2))
209464562Sgshapiro		dprintf("nis_map_open(%s, %s, %d)\n",
209538032Speter			map->map_mname, map->map_file, mode);
209638032Speter
209738032Speter	mode &= O_ACCMODE;
209838032Speter	if (mode != O_RDONLY)
209938032Speter	{
210038032Speter		/* issue a pseudo-error message */
210164562Sgshapiro# ifdef ENOSYS
210238032Speter		errno = ENOSYS;
210364562Sgshapiro# else /* ENOSYS */
210464562Sgshapiro#  ifdef EFTYPE
210538032Speter		errno = EFTYPE;
210664562Sgshapiro#  else /* EFTYPE */
210738032Speter		errno = ENXIO;
210864562Sgshapiro#  endif /* EFTYPE */
210964562Sgshapiro# endif /* ENOSYS */
211038032Speter		return FALSE;
211138032Speter	}
211238032Speter
211338032Speter	p = strchr(map->map_file, '@');
211438032Speter	if (p != NULL)
211538032Speter	{
211638032Speter		*p++ = '\0';
211738032Speter		if (*p != '\0')
211838032Speter			map->map_domain = p;
211938032Speter	}
212038032Speter
212138032Speter	if (*map->map_file == '\0')
212238032Speter		map->map_file = "mail.aliases";
212338032Speter
212438032Speter	if (map->map_domain == NULL)
212538032Speter	{
212638032Speter		yperr = yp_get_default_domain(&map->map_domain);
212738032Speter		if (yperr != 0)
212838032Speter		{
212938032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
213064562Sgshapiro				syserr("421 4.3.5 NIS map %s specified, but NIS not running",
213164562Sgshapiro				       map->map_file);
213238032Speter			return FALSE;
213338032Speter		}
213438032Speter	}
213538032Speter
213638032Speter	/* check to see if this map actually exists */
213764562Sgshapiro	vp = NULL;
213838032Speter	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
213938032Speter			&vp, &vsize);
214038032Speter	if (tTd(38, 10))
214164562Sgshapiro		dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n",
214238032Speter			map->map_domain, map->map_file, yperr_string(yperr));
214364562Sgshapiro	if (vp != NULL)
214464562Sgshapiro		free(vp);
214564562Sgshapiro
214638032Speter	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
214738032Speter	{
214838032Speter		/*
214938032Speter		**  We ought to be calling aliaswait() here if this is an
215038032Speter		**  alias file, but powerful HP-UX NIS servers  apparently
215138032Speter		**  don't insert the @:@ token into the alias map when it
215238032Speter		**  is rebuilt, so aliaswait() just hangs.  I hate HP-UX.
215338032Speter		*/
215438032Speter
215564562Sgshapiro# if 0
215638032Speter		if (!bitset(MF_ALIAS, map->map_mflags) ||
215738032Speter		    aliaswait(map, NULL, TRUE))
215864562Sgshapiro# endif /* 0 */
215938032Speter			return TRUE;
216038032Speter	}
216138032Speter
216238032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
216338032Speter	{
216464562Sgshapiro		syserr("421 4.0.0 Cannot bind to map %s in domain %s: %s",
216538032Speter			map->map_file, map->map_domain, yperr_string(yperr));
216638032Speter	}
216738032Speter
216838032Speter	return FALSE;
216938032Speter}
217038032Speter
217138032Speter
217238032Speter/*
217338032Speter**  NIS_MAP_LOOKUP -- look up a datum in a NIS map
217438032Speter*/
217538032Speter
217638032Speter/* ARGSUSED3 */
217738032Speterchar *
217838032Speternis_map_lookup(map, name, av, statp)
217938032Speter	MAP *map;
218038032Speter	char *name;
218138032Speter	char **av;
218238032Speter	int *statp;
218338032Speter{
218438032Speter	char *vp;
218538032Speter	auto int vsize;
218638032Speter	int buflen;
218738032Speter	int yperr;
218838032Speter	char keybuf[MAXNAME + 1];
218938032Speter
219038032Speter	if (tTd(38, 20))
219164562Sgshapiro		dprintf("nis_map_lookup(%s, %s)\n",
219238032Speter			map->map_mname, name);
219338032Speter
219438032Speter	buflen = strlen(name);
219538032Speter	if (buflen > sizeof keybuf - 1)
219638032Speter		buflen = sizeof keybuf - 1;
219764562Sgshapiro	memmove(keybuf, name, buflen);
219838032Speter	keybuf[buflen] = '\0';
219938032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
220038032Speter		makelower(keybuf);
220138032Speter	yperr = YPERR_KEY;
220264562Sgshapiro	vp = NULL;
220338032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
220438032Speter	{
220538032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
220638032Speter			     &vp, &vsize);
220738032Speter		if (yperr == 0)
220838032Speter			map->map_mflags &= ~MF_TRY1NULL;
220938032Speter	}
221038032Speter	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
221138032Speter	{
221264562Sgshapiro		if (vp != NULL)
221364562Sgshapiro		{
221464562Sgshapiro			free(vp);
221564562Sgshapiro			vp = NULL;
221664562Sgshapiro		}
221738032Speter		buflen++;
221838032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
221938032Speter			     &vp, &vsize);
222038032Speter		if (yperr == 0)
222138032Speter			map->map_mflags &= ~MF_TRY0NULL;
222238032Speter	}
222338032Speter	if (yperr != 0)
222438032Speter	{
222538032Speter		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
222638032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
222764562Sgshapiro		if (vp != NULL)
222864562Sgshapiro			free(vp);
222938032Speter		return NULL;
223038032Speter	}
223138032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
223238032Speter		return map_rewrite(map, name, strlen(name), NULL);
223338032Speter	else
223464562Sgshapiro	{
223564562Sgshapiro		char *ret;
223664562Sgshapiro
223764562Sgshapiro		ret = map_rewrite(map, vp, vsize, av);
223864562Sgshapiro		if (vp != NULL)
223964562Sgshapiro			free(vp);
224064562Sgshapiro		return ret;
224164562Sgshapiro	}
224238032Speter}
224338032Speter
224438032Speter
224538032Speter/*
224638032Speter**  NIS_GETCANONNAME -- look up canonical name in NIS
224738032Speter*/
224838032Speter
224964562Sgshapirostatic bool
225038032Speternis_getcanonname(name, hbsize, statp)
225138032Speter	char *name;
225238032Speter	int hbsize;
225338032Speter	int *statp;
225438032Speter{
225538032Speter	char *vp;
225638032Speter	auto int vsize;
225738032Speter	int keylen;
225838032Speter	int yperr;
225938032Speter	static bool try0null = TRUE;
226038032Speter	static bool try1null = TRUE;
226138032Speter	static char *yp_domain = NULL;
226238032Speter	char host_record[MAXLINE];
226338032Speter	char cbuf[MAXNAME];
226438032Speter	char nbuf[MAXNAME + 1];
226538032Speter
226638032Speter	if (tTd(38, 20))
226764562Sgshapiro		dprintf("nis_getcanonname(%s)\n", name);
226838032Speter
226964562Sgshapiro	if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
227038032Speter	{
227138032Speter		*statp = EX_UNAVAILABLE;
227238032Speter		return FALSE;
227338032Speter	}
227473188Sgshapiro	(void) shorten_hostname(nbuf);
227538032Speter	keylen = strlen(nbuf);
227638032Speter
227738032Speter	if (yp_domain == NULL)
227864562Sgshapiro		(void) yp_get_default_domain(&yp_domain);
227938032Speter	makelower(nbuf);
228038032Speter	yperr = YPERR_KEY;
228164562Sgshapiro	vp = NULL;
228238032Speter	if (try0null)
228338032Speter	{
228438032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
228538032Speter			     &vp, &vsize);
228638032Speter		if (yperr == 0)
228738032Speter			try1null = FALSE;
228838032Speter	}
228938032Speter	if (yperr == YPERR_KEY && try1null)
229038032Speter	{
229164562Sgshapiro		if (vp != NULL)
229264562Sgshapiro		{
229364562Sgshapiro			free(vp);
229464562Sgshapiro			vp = NULL;
229564562Sgshapiro		}
229638032Speter		keylen++;
229738032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
229838032Speter			     &vp, &vsize);
229938032Speter		if (yperr == 0)
230038032Speter			try0null = FALSE;
230138032Speter	}
230238032Speter	if (yperr != 0)
230338032Speter	{
230438032Speter		if (yperr == YPERR_KEY)
230538032Speter			*statp = EX_NOHOST;
230638032Speter		else if (yperr == YPERR_BUSY)
230738032Speter			*statp = EX_TEMPFAIL;
230838032Speter		else
230938032Speter			*statp = EX_UNAVAILABLE;
231064562Sgshapiro		if (vp != NULL)
231164562Sgshapiro			free(vp);
231238032Speter		return FALSE;
231338032Speter	}
231464562Sgshapiro	(void) strlcpy(host_record, vp, sizeof host_record);
231564562Sgshapiro	free(vp);
231638032Speter	if (tTd(38, 44))
231764562Sgshapiro		dprintf("got record `%s'\n", host_record);
231873188Sgshapiro	if (!extract_canonname(nbuf, NULL, host_record, cbuf, sizeof cbuf))
231938032Speter	{
232038032Speter		/* this should not happen, but.... */
232138032Speter		*statp = EX_NOHOST;
232238032Speter		return FALSE;
232338032Speter	}
232473188Sgshapiro	if (hbsize <= strlen(cbuf))
232538032Speter	{
232638032Speter		*statp = EX_UNAVAILABLE;
232738032Speter		return FALSE;
232838032Speter	}
232964562Sgshapiro	(void) strlcpy(name, cbuf, hbsize);
233038032Speter	*statp = EX_OK;
233138032Speter	return TRUE;
233238032Speter}
233338032Speter
233464562Sgshapiro#endif /* NIS */
233538032Speter/*
233638032Speter**  NISPLUS Modules
233738032Speter**
233838032Speter**	This code donated by Sun Microsystems.
233938032Speter*/
234038032Speter
234138032Speter#ifdef NISPLUS
234238032Speter
234364562Sgshapiro# undef NIS		/* symbol conflict in nis.h */
234464562Sgshapiro# undef T_UNSPEC	/* symbol conflict in nis.h -> ... -> sys/tiuser.h */
234564562Sgshapiro# include <rpcsvc/nis.h>
234664562Sgshapiro# include <rpcsvc/nislib.h>
234738032Speter
234864562Sgshapiro# define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
234964562Sgshapiro# define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
235064562Sgshapiro# define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
235164562Sgshapiro# define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
235238032Speter
235338032Speter/*
235438032Speter**  NISPLUS_MAP_OPEN -- open nisplus table
235538032Speter*/
235638032Speter
235738032Speterbool
235838032Speternisplus_map_open(map, mode)
235938032Speter	MAP *map;
236038032Speter	int mode;
236138032Speter{
236238032Speter	nis_result *res = NULL;
236338032Speter	int retry_cnt, max_col, i;
236438032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
236538032Speter
236638032Speter	if (tTd(38, 2))
236764562Sgshapiro		dprintf("nisplus_map_open(%s, %s, %d)\n",
236838032Speter			map->map_mname, map->map_file, mode);
236938032Speter
237038032Speter	mode &= O_ACCMODE;
237138032Speter	if (mode != O_RDONLY)
237238032Speter	{
237338032Speter		errno = EPERM;
237438032Speter		return FALSE;
237538032Speter	}
237638032Speter
237738032Speter	if (*map->map_file == '\0')
237838032Speter		map->map_file = "mail_aliases.org_dir";
237938032Speter
238038032Speter	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
238138032Speter	{
238238032Speter		/* set default NISPLUS Domain to $m */
238338032Speter		map->map_domain = newstr(nisplus_default_domain());
238438032Speter		if (tTd(38, 2))
238564562Sgshapiro			dprintf("nisplus_map_open(%s): using domain %s\n",
238664562Sgshapiro				map->map_file, map->map_domain);
238738032Speter	}
238838032Speter	if (!PARTIAL_NAME(map->map_file))
238938032Speter	{
239038032Speter		map->map_domain = newstr("");
239138032Speter		snprintf(qbuf, sizeof qbuf, "%s", map->map_file);
239238032Speter	}
239338032Speter	else
239438032Speter	{
239538032Speter		/* check to see if this map actually exists */
239638032Speter		snprintf(qbuf, sizeof qbuf, "%s.%s",
239738032Speter			map->map_file, map->map_domain);
239838032Speter	}
239938032Speter
240038032Speter	retry_cnt = 0;
240138032Speter	while (res == NULL || res->status != NIS_SUCCESS)
240238032Speter	{
240338032Speter		res = nis_lookup(qbuf, FOLLOW_LINKS);
240438032Speter		switch (res->status)
240538032Speter		{
240638032Speter		  case NIS_SUCCESS:
240738032Speter			break;
240838032Speter
240938032Speter		  case NIS_TRYAGAIN:
241038032Speter		  case NIS_RPCERROR:
241138032Speter		  case NIS_NAMEUNREACHABLE:
241238032Speter			if (retry_cnt++ > 4)
241338032Speter			{
241438032Speter				errno = EAGAIN;
241538032Speter				return FALSE;
241638032Speter			}
241738032Speter			/* try not to overwhelm hosed server */
241838032Speter			sleep(2);
241938032Speter			break;
242038032Speter
242138032Speter		  default:		/* all other nisplus errors */
242264562Sgshapiro# if 0
242338032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
242464562Sgshapiro				syserr("421 4.0.0 Cannot find table %s.%s: %s",
242538032Speter					map->map_file, map->map_domain,
242638032Speter					nis_sperrno(res->status));
242764562Sgshapiro# endif /* 0 */
242838032Speter			errno = EAGAIN;
242938032Speter			return FALSE;
243038032Speter		}
243138032Speter	}
243238032Speter
243338032Speter	if (NIS_RES_NUMOBJ(res) != 1 ||
243438032Speter	    (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
243538032Speter	{
243638032Speter		if (tTd(38, 10))
243764562Sgshapiro			dprintf("nisplus_map_open: %s is not a table\n", qbuf);
243864562Sgshapiro# if 0
243938032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
244064562Sgshapiro			syserr("421 4.0.0 %s.%s: %s is not a table",
244138032Speter				map->map_file, map->map_domain,
244238032Speter				nis_sperrno(res->status));
244364562Sgshapiro# endif /* 0 */
244438032Speter		errno = EBADF;
244538032Speter		return FALSE;
244638032Speter	}
244738032Speter	/* default key column is column 0 */
244838032Speter	if (map->map_keycolnm == NULL)
244938032Speter		map->map_keycolnm = newstr(COL_NAME(res,0));
245038032Speter
245138032Speter	max_col = COL_MAX(res);
245238032Speter
245338032Speter	/* verify the key column exist */
245464562Sgshapiro	for (i = 0; i< max_col; i++)
245538032Speter	{
245664562Sgshapiro		if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0)
245738032Speter			break;
245838032Speter	}
245938032Speter	if (i == max_col)
246038032Speter	{
246138032Speter		if (tTd(38, 2))
246264562Sgshapiro			dprintf("nisplus_map_open(%s): can not find key column %s\n",
246338032Speter				map->map_file, map->map_keycolnm);
246438032Speter		errno = ENOENT;
246538032Speter		return FALSE;
246638032Speter	}
246738032Speter
246838032Speter	/* default value column is the last column */
246938032Speter	if (map->map_valcolnm == NULL)
247038032Speter	{
247138032Speter		map->map_valcolno = max_col - 1;
247238032Speter		return TRUE;
247338032Speter	}
247438032Speter
247564562Sgshapiro	for (i = 0; i< max_col; i++)
247638032Speter	{
247738032Speter		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
247838032Speter		{
247938032Speter			map->map_valcolno = i;
248038032Speter			return TRUE;
248138032Speter		}
248238032Speter	}
248338032Speter
248438032Speter	if (tTd(38, 2))
248564562Sgshapiro		dprintf("nisplus_map_open(%s): can not find column %s\n",
248664562Sgshapiro			map->map_file, map->map_keycolnm);
248738032Speter	errno = ENOENT;
248838032Speter	return FALSE;
248938032Speter}
249038032Speter
249138032Speter
249238032Speter/*
249338032Speter**  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
249438032Speter*/
249538032Speter
249638032Speterchar *
249738032Speternisplus_map_lookup(map, name, av, statp)
249838032Speter	MAP *map;
249938032Speter	char *name;
250038032Speter	char **av;
250138032Speter	int *statp;
250238032Speter{
250338032Speter	char *p;
250438032Speter	auto int vsize;
250538032Speter	char *skp;
250638032Speter	int skleft;
250738032Speter	char search_key[MAXNAME + 4];
250838032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
250938032Speter	nis_result *result;
251038032Speter
251138032Speter	if (tTd(38, 20))
251264562Sgshapiro		dprintf("nisplus_map_lookup(%s, %s)\n",
251338032Speter			map->map_mname, name);
251438032Speter
251538032Speter	if (!bitset(MF_OPEN, map->map_mflags))
251638032Speter	{
251738032Speter		if (nisplus_map_open(map, O_RDONLY))
251842575Speter		{
251938032Speter			map->map_mflags |= MF_OPEN;
252042575Speter			map->map_pid = getpid();
252142575Speter		}
252238032Speter		else
252338032Speter		{
252438032Speter			*statp = EX_UNAVAILABLE;
252538032Speter			return NULL;
252638032Speter		}
252738032Speter	}
252838032Speter
252938032Speter	/*
253038032Speter	**  Copy the name to the key buffer, escaping double quote characters
253138032Speter	**  by doubling them and quoting "]" and "," to avoid having the
253238032Speter	**  NIS+ parser choke on them.
253338032Speter	*/
253438032Speter
253538032Speter	skleft = sizeof search_key - 4;
253638032Speter	skp = search_key;
253738032Speter	for (p = name; *p != '\0' && skleft > 0; p++)
253838032Speter	{
253938032Speter		switch (*p)
254038032Speter		{
254138032Speter		  case ']':
254238032Speter		  case ',':
254338032Speter			/* quote the character */
254438032Speter			*skp++ = '"';
254538032Speter			*skp++ = *p;
254638032Speter			*skp++ = '"';
254738032Speter			skleft -= 3;
254838032Speter			break;
254938032Speter
255038032Speter		  case '"':
255138032Speter			/* double the quote */
255238032Speter			*skp++ = '"';
255338032Speter			skleft--;
255464562Sgshapiro			/* FALLTHROUGH */
255538032Speter
255638032Speter		  default:
255738032Speter			*skp++ = *p;
255838032Speter			skleft--;
255938032Speter			break;
256038032Speter		}
256138032Speter	}
256238032Speter	*skp = '\0';
256338032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
256438032Speter		makelower(search_key);
256538032Speter
256638032Speter	/* construct the query */
256738032Speter	if (PARTIAL_NAME(map->map_file))
256838032Speter		snprintf(qbuf, sizeof qbuf, "[%s=%s],%s.%s",
256938032Speter			map->map_keycolnm, search_key, map->map_file,
257038032Speter			map->map_domain);
257138032Speter	else
257238032Speter		snprintf(qbuf, sizeof qbuf, "[%s=%s],%s",
257338032Speter			map->map_keycolnm, search_key, map->map_file);
257438032Speter
257538032Speter	if (tTd(38, 20))
257664562Sgshapiro		dprintf("qbuf=%s\n", qbuf);
257738032Speter	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
257838032Speter	if (result->status == NIS_SUCCESS)
257938032Speter	{
258038032Speter		int count;
258138032Speter		char *str;
258238032Speter
258338032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
258438032Speter		{
258538032Speter			if (LogLevel > 10)
258638032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
258764562Sgshapiro					  "%s: lookup error, expected 1 entry, got %d",
258864562Sgshapiro					  map->map_file, count);
258938032Speter
259038032Speter			/* ignore second entry */
259138032Speter			if (tTd(38, 20))
259264562Sgshapiro				dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
259338032Speter					name, count);
259438032Speter		}
259538032Speter
259638032Speter		p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
259738032Speter		/* set the length of the result */
259838032Speter		if (p == NULL)
259938032Speter			p = "";
260038032Speter		vsize = strlen(p);
260138032Speter		if (tTd(38, 20))
260264562Sgshapiro			dprintf("nisplus_map_lookup(%s), found %s\n",
260338032Speter				name, p);
260438032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
260538032Speter			str = map_rewrite(map, name, strlen(name), NULL);
260638032Speter		else
260738032Speter			str = map_rewrite(map, p, vsize, av);
260838032Speter		nis_freeresult(result);
260938032Speter		*statp = EX_OK;
261038032Speter		return str;
261138032Speter	}
261238032Speter	else
261338032Speter	{
261438032Speter		if (result->status == NIS_NOTFOUND)
261538032Speter			*statp = EX_NOTFOUND;
261638032Speter		else if (result->status == NIS_TRYAGAIN)
261738032Speter			*statp = EX_TEMPFAIL;
261838032Speter		else
261938032Speter		{
262038032Speter			*statp = EX_UNAVAILABLE;
262138032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
262238032Speter		}
262338032Speter	}
262438032Speter	if (tTd(38, 20))
262564562Sgshapiro		dprintf("nisplus_map_lookup(%s), failed\n", name);
262638032Speter	nis_freeresult(result);
262738032Speter	return NULL;
262838032Speter}
262938032Speter
263038032Speter
263138032Speter
263238032Speter/*
263338032Speter**  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
263438032Speter*/
263538032Speter
263664562Sgshapirostatic bool
263738032Speternisplus_getcanonname(name, hbsize, statp)
263838032Speter	char *name;
263938032Speter	int hbsize;
264038032Speter	int *statp;
264138032Speter{
264238032Speter	char *vp;
264338032Speter	auto int vsize;
264438032Speter	nis_result *result;
264538032Speter	char *p;
264638032Speter	char nbuf[MAXNAME + 1];
264738032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
264838032Speter
264938032Speter	if (strlen(name) >= sizeof nbuf)
265038032Speter	{
265138032Speter		*statp = EX_UNAVAILABLE;
265238032Speter		return FALSE;
265338032Speter	}
265464562Sgshapiro	(void) strlcpy(nbuf, name, sizeof nbuf);
265573188Sgshapiro	(void) shorten_hostname(nbuf);
265638032Speter
265738032Speter	p = strchr(nbuf, '.');
265838032Speter	if (p == NULL)
265938032Speter	{
266038032Speter		/* single token */
266138032Speter		snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir", nbuf);
266238032Speter	}
266338032Speter	else if (p[1] != '\0')
266438032Speter	{
266538032Speter		/* multi token -- take only first token in nbuf */
266638032Speter		*p = '\0';
266738032Speter		snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir.%s",
266838032Speter			nbuf, &p[1]);
266938032Speter	}
267038032Speter	else
267138032Speter	{
267238032Speter		*statp = EX_NOHOST;
267338032Speter		return FALSE;
267438032Speter	}
267538032Speter
267638032Speter	if (tTd(38, 20))
267764562Sgshapiro		dprintf("\nnisplus_getcanoname(%s), qbuf=%s\n",
267864562Sgshapiro			name, qbuf);
267938032Speter
268038032Speter	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
268138032Speter		NULL, NULL);
268238032Speter
268338032Speter	if (result->status == NIS_SUCCESS)
268438032Speter	{
268538032Speter		int count;
268638032Speter		char *domain;
268738032Speter
268838032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
268938032Speter		{
269038032Speter			if (LogLevel > 10)
269138032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
269264562Sgshapiro					  "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
269364562Sgshapiro					  count);
269438032Speter
269538032Speter			/* ignore second entry */
269638032Speter			if (tTd(38, 20))
269764562Sgshapiro				dprintf("nisplus_getcanoname(%s), got %d entries, all but first ignored\n",
269838032Speter					name, count);
269938032Speter		}
270038032Speter
270138032Speter		if (tTd(38, 20))
270264562Sgshapiro			dprintf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
270364562Sgshapiro				name, (NIS_RES_OBJECT(result))->zo_domain);
270438032Speter
270538032Speter
270638032Speter		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
270738032Speter		vsize = strlen(vp);
270838032Speter		if (tTd(38, 20))
270964562Sgshapiro			dprintf("nisplus_getcanonname(%s), found %s\n",
271038032Speter				name, vp);
271138032Speter		if (strchr(vp, '.') != NULL)
271238032Speter		{
271338032Speter			domain = "";
271438032Speter		}
271538032Speter		else
271638032Speter		{
271738032Speter			domain = macvalue('m', CurEnv);
271838032Speter			if (domain == NULL)
271938032Speter				domain = "";
272038032Speter		}
272138032Speter		if (hbsize > vsize + (int) strlen(domain) + 1)
272238032Speter		{
272338032Speter			if (domain[0] == '\0')
272464562Sgshapiro				(void) strlcpy(name, vp, hbsize);
272538032Speter			else
272638032Speter				snprintf(name, hbsize, "%s.%s", vp, domain);
272738032Speter			*statp = EX_OK;
272838032Speter		}
272938032Speter		else
273038032Speter			*statp = EX_NOHOST;
273138032Speter		nis_freeresult(result);
273238032Speter		return TRUE;
273338032Speter	}
273438032Speter	else
273538032Speter	{
273638032Speter		if (result->status == NIS_NOTFOUND)
273738032Speter			*statp = EX_NOHOST;
273838032Speter		else if (result->status == NIS_TRYAGAIN)
273938032Speter			*statp = EX_TEMPFAIL;
274038032Speter		else
274138032Speter			*statp = EX_UNAVAILABLE;
274238032Speter	}
274338032Speter	if (tTd(38, 20))
274464562Sgshapiro		dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
274538032Speter			name, result->status, *statp);
274638032Speter	nis_freeresult(result);
274738032Speter	return FALSE;
274838032Speter}
274938032Speter
275038032Speterchar *
275138032Speternisplus_default_domain()
275238032Speter{
275338032Speter	static char default_domain[MAXNAME + 1] = "";
275438032Speter	char *p;
275538032Speter
275638032Speter	if (default_domain[0] != '\0')
275764562Sgshapiro		return default_domain;
275838032Speter
275938032Speter	p = nis_local_directory();
276038032Speter	snprintf(default_domain, sizeof default_domain, "%s", p);
276138032Speter	return default_domain;
276238032Speter}
276338032Speter
276438032Speter#endif /* NISPLUS */
276538032Speter/*
276638032Speter**  LDAP Modules
276738032Speter*/
276838032Speter
276964562Sgshapiro/*
277064562Sgshapiro**  LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs
277164562Sgshapiro*/
277264562Sgshapiro
277364562Sgshapiro#if defined(LDAPMAP) || defined(PH_MAP)
277464562Sgshapiro
277564562Sgshapiro# ifdef PH_MAP
277664562Sgshapiro#  define ph_map_dequote ldapmap_dequote
277764562Sgshapiro# endif /* PH_MAP */
277864562Sgshapiro
277964562Sgshapirochar *
278064562Sgshapiroldapmap_dequote(str)
278164562Sgshapiro	char *str;
278264562Sgshapiro{
278364562Sgshapiro	char *p;
278464562Sgshapiro	char *start;
278564562Sgshapiro
278664562Sgshapiro	if (str == NULL)
278764562Sgshapiro		return NULL;
278864562Sgshapiro
278964562Sgshapiro	p = str;
279064562Sgshapiro	if (*p == '"')
279164562Sgshapiro	{
279264562Sgshapiro		/* Should probably swallow initial whitespace here */
279364562Sgshapiro		start = ++p;
279464562Sgshapiro	}
279564562Sgshapiro	else
279664562Sgshapiro		return str;
279764562Sgshapiro	while (*p != '"' && *p != '\0')
279864562Sgshapiro		p++;
279964562Sgshapiro	if (*p != '\0')
280064562Sgshapiro		*p = '\0';
280164562Sgshapiro	return start;
280264562Sgshapiro}
280364562Sgshapiro#endif /* defined(LDAPMAP) || defined(PH_MAP) */
280464562Sgshapiro
280538032Speter#ifdef LDAPMAP
280638032Speter
280764562SgshapiroLDAPMAP_STRUCT *LDAPDefaults = NULL;
280838032Speter
280938032Speter/*
281064562Sgshapiro**  LDAPMAP_OPEN -- open LDAP map
281138032Speter**
281264562Sgshapiro**	Connect to the LDAP server.  Re-use existing connections since a
281364562Sgshapiro**	single server connection to a host (with the same host, port,
281464562Sgshapiro**	bind DN, and secret) can answer queries for multiple maps.
281538032Speter*/
281638032Speter
281738032Speterbool
281864562Sgshapiroldapmap_open(map, mode)
281938032Speter	MAP *map;
282038032Speter	int mode;
282138032Speter{
282264562Sgshapiro	LDAPMAP_STRUCT *lmap;
282364562Sgshapiro	STAB *s;
282464562Sgshapiro
282538032Speter	if (tTd(38, 2))
282666494Sgshapiro		dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode);
282738032Speter
282838032Speter	mode &= O_ACCMODE;
282964562Sgshapiro
283064562Sgshapiro	/* sendmail doesn't have the ability to write to LDAP (yet) */
283138032Speter	if (mode != O_RDONLY)
283238032Speter	{
283338032Speter		/* issue a pseudo-error message */
283464562Sgshapiro# ifdef ENOSYS
283538032Speter		errno = ENOSYS;
283664562Sgshapiro# else /* ENOSYS */
283764562Sgshapiro#  ifdef EFTYPE
283838032Speter		errno = EFTYPE;
283964562Sgshapiro#  else /* EFTYPE */
284038032Speter		errno = ENXIO;
284164562Sgshapiro#  endif /* EFTYPE */
284264562Sgshapiro# endif /* ENOSYS */
284338032Speter		return FALSE;
284438032Speter	}
284564562Sgshapiro
284664562Sgshapiro	/* Comma separate if used as an alias file */
284764562Sgshapiro	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
284864562Sgshapiro		map->map_coldelim = ',';
284964562Sgshapiro
285064562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
285164562Sgshapiro
285264562Sgshapiro	s = ldapmap_findconn(lmap);
285364562Sgshapiro	if (s->s_ldap != NULL)
285464562Sgshapiro	{
285564562Sgshapiro		/* Already have a connection open to this LDAP server */
285664562Sgshapiro		lmap->ldap_ld = s->s_ldap;
285766494Sgshapiro		if (tTd(38, 2))
285866494Sgshapiro			dprintf("using cached connection\n");
285964562Sgshapiro		return TRUE;
286064562Sgshapiro	}
286164562Sgshapiro
286266494Sgshapiro	if (tTd(38, 2))
286366494Sgshapiro		dprintf("opening new connection\n");
286466494Sgshapiro
286564562Sgshapiro	/* No connection yet, connect */
286664562Sgshapiro	if (!ldapmap_start(map))
286764562Sgshapiro		return FALSE;
286864562Sgshapiro
286964562Sgshapiro	/* Save connection for reuse */
287064562Sgshapiro	s->s_ldap = lmap->ldap_ld;
287138032Speter	return TRUE;
287238032Speter}
287338032Speter
287438032Speter/*
287564562Sgshapiro**  LDAPMAP_START -- actually connect to an LDAP server
287638032Speter**
287764562Sgshapiro**	Parameters:
287864562Sgshapiro**		map -- the map being opened.
287964562Sgshapiro**
288064562Sgshapiro**	Returns:
288164562Sgshapiro**		TRUE if connection is successful, FALSE otherwise.
288264562Sgshapiro**
288364562Sgshapiro**	Side Effects:
288464562Sgshapiro**		Populates lmap->ldap_ld.
288538032Speter*/
288638032Speter
288738032Speterstatic jmp_buf	LDAPTimeout;
288838032Speter
288964562Sgshapirostatic bool
289064562Sgshapiroldapmap_start(map)
289138032Speter	MAP *map;
289238032Speter{
289364562Sgshapiro	register int bind_result;
289464562Sgshapiro	int save_errno;
289564562Sgshapiro	register EVENT *ev = NULL;
289664562Sgshapiro	LDAPMAP_STRUCT *lmap;
289738032Speter	LDAP *ld;
289838032Speter
289938032Speter	if (tTd(38, 2))
290064562Sgshapiro		dprintf("ldapmap_start(%s)\n", map->map_mname);
290138032Speter
290264562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
290338032Speter
290438032Speter	if (tTd(38,9))
290564562Sgshapiro		dprintf("ldapmap_start(%s, %d)\n",
290664562Sgshapiro			lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host,
290764562Sgshapiro			lmap->ldap_port);
290838032Speter
290964562Sgshapiro# if USE_LDAP_INIT
291064562Sgshapiro	ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
291171345Sgshapiro	save_errno = errno;
291264562Sgshapiro# else /* USE_LDAP_INIT */
291364562Sgshapiro	/*
291464562Sgshapiro	**  If using ldap_open(), the actual connection to the server
291564562Sgshapiro	**  happens now so we need the timeout here.  For ldap_init(),
291664562Sgshapiro	**  the connection happens at bind time.
291764562Sgshapiro	*/
291838032Speter
291938032Speter	/* set the timeout */
292064562Sgshapiro	if (lmap->ldap_timeout.tv_sec != 0)
292138032Speter	{
292238032Speter		if (setjmp(LDAPTimeout) != 0)
292338032Speter		{
292438032Speter			if (LogLevel > 1)
292538032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
292664562Sgshapiro					  "timeout conning to LDAP server %.100s",
292764562Sgshapiro					  lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
292864562Sgshapiro			return FALSE;
292938032Speter		}
293064562Sgshapiro		ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
293138032Speter	}
293238032Speter
293364562Sgshapiro	ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
293464562Sgshapiro	save_errno = errno;
293542575Speter
293664562Sgshapiro	/* clear the event if it has not sprung */
293764562Sgshapiro	if (ev != NULL)
293842575Speter		clrevent(ev);
293964562Sgshapiro# endif /* USE_LDAP_INIT */
294042575Speter
294164562Sgshapiro	errno = save_errno;
294242575Speter	if (ld == NULL)
294338032Speter	{
294438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
294538032Speter		{
294664562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
294764562Sgshapiro				syserr("%s failed to %s in map %s",
294864562Sgshapiro# if USE_LDAP_INIT
294964562Sgshapiro				       "ldap_init",
295064562Sgshapiro# else /* USE_LDAP_INIT */
295164562Sgshapiro				       "ldap_open",
295264562Sgshapiro# endif /* USE_LDAP_INIT */
295364562Sgshapiro				       lmap->ldap_host == NULL ? "localhost"
295464562Sgshapiro							       : lmap->ldap_host,
295564562Sgshapiro				       map->map_mname);
295664562Sgshapiro			else
295764562Sgshapiro				syserr("421 4.0.0 %s failed to %s in map %s",
295864562Sgshapiro# if USE_LDAP_INIT
295964562Sgshapiro				       "ldap_init",
296064562Sgshapiro# else /* USE_LDAP_INIT */
296164562Sgshapiro				       "ldap_open",
296264562Sgshapiro# endif /* USE_LDAP_INIT */
296364562Sgshapiro				       lmap->ldap_host == NULL ? "localhost"
296464562Sgshapiro							       : lmap->ldap_host,
296564562Sgshapiro				       map->map_mname);
296638032Speter		}
296738032Speter		return FALSE;
296838032Speter	}
296938032Speter
297064562Sgshapiro	ldapmap_setopts(ld, lmap);
297138032Speter
297264562Sgshapiro# if USE_LDAP_INIT
297364562Sgshapiro	/*
297464562Sgshapiro	**  If using ldap_init(), the actual connection to the server
297564562Sgshapiro	**  happens at ldap_bind_s() so we need the timeout here.
297664562Sgshapiro	*/
297764562Sgshapiro
297864562Sgshapiro	/* set the timeout */
297964562Sgshapiro	if (lmap->ldap_timeout.tv_sec != 0)
298038032Speter	{
298164562Sgshapiro		if (setjmp(LDAPTimeout) != 0)
298238032Speter		{
298364562Sgshapiro			if (LogLevel > 1)
298464562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
298564562Sgshapiro					  "timeout conning to LDAP server %.100s",
298664562Sgshapiro					  lmap->ldap_host == NULL ? "localhost"
298764562Sgshapiro								  : lmap->ldap_host);
298864562Sgshapiro			return FALSE;
298938032Speter		}
299064562Sgshapiro		ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
299138032Speter	}
299264562Sgshapiro# endif /* USE_LDAP_INIT */
299364562Sgshapiro
299464562Sgshapiro# ifdef LDAP_AUTH_KRBV4
299564562Sgshapiro	if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
299664562Sgshapiro	    lmap->ldap_secret != NULL)
299738032Speter	{
299864562Sgshapiro		/*
299964562Sgshapiro		**  Need to put ticket in environment here instead of
300064562Sgshapiro		**  during parseargs as there may be different tickets
300164562Sgshapiro		**  for different LDAP connections.
300264562Sgshapiro		*/
300364562Sgshapiro
300464562Sgshapiro		(void) putenv(lmap->ldap_secret);
300538032Speter	}
300664562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
300738032Speter
300864562Sgshapiro	bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
300964562Sgshapiro				  lmap->ldap_secret, lmap->ldap_method);
301064562Sgshapiro
301164562Sgshapiro# if USE_LDAP_INIT
301264562Sgshapiro	/* clear the event if it has not sprung */
301364562Sgshapiro	if (ev != NULL)
301464562Sgshapiro		clrevent(ev);
301564562Sgshapiro# endif /* USE_LDAP_INIT */
301664562Sgshapiro
301764562Sgshapiro	if (bind_result != LDAP_SUCCESS)
301864562Sgshapiro	{
301964562Sgshapiro		errno = bind_result + E_LDAPBASE;
302064562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
302164562Sgshapiro		{
302264562Sgshapiro			syserr("421 4.0.0 Cannot bind to map %s in ldap server %s",
302364562Sgshapiro			       map->map_mname,
302464562Sgshapiro			       lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host);
302564562Sgshapiro		}
302664562Sgshapiro		return FALSE;
302764562Sgshapiro	}
302864562Sgshapiro
302964562Sgshapiro	/* We need to cast ld into the map structure */
303064562Sgshapiro	lmap->ldap_ld = ld;
303164562Sgshapiro	return TRUE;
303238032Speter}
303338032Speter
303464562Sgshapiro/* ARGSUSED */
303564562Sgshapirostatic void
303664562Sgshapiroldaptimeout(sig_no)
303764562Sgshapiro	int sig_no;
303864562Sgshapiro{
303964562Sgshapiro	longjmp(LDAPTimeout, 1);
304064562Sgshapiro}
304138032Speter
304238032Speter/*
304364562Sgshapiro**  LDAPMAP_CLOSE -- close ldap map
304438032Speter*/
304538032Speter
304638032Spetervoid
304764562Sgshapiroldapmap_close(map)
304838032Speter	MAP *map;
304938032Speter{
305064562Sgshapiro	LDAPMAP_STRUCT *lmap;
305164562Sgshapiro	STAB *s;
305243730Speter
305364562Sgshapiro	if (tTd(38, 2))
305464562Sgshapiro		dprintf("ldapmap_close(%s)\n", map->map_mname);
305564562Sgshapiro
305664562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
305764562Sgshapiro
305864562Sgshapiro	/* Check if already closed */
305964562Sgshapiro	if (lmap->ldap_ld == NULL)
306064562Sgshapiro		return;
306164562Sgshapiro
306264562Sgshapiro	s = ldapmap_findconn(lmap);
306364562Sgshapiro
306464562Sgshapiro	/* Check if already closed */
306564562Sgshapiro	if (s->s_ldap == NULL)
306664562Sgshapiro		return;
306764562Sgshapiro
306864562Sgshapiro	/* If same as saved connection, stored connection is going away */
306964562Sgshapiro	if (s->s_ldap == lmap->ldap_ld)
307064562Sgshapiro		s->s_ldap = NULL;
307164562Sgshapiro
307264562Sgshapiro	if (lmap->ldap_ld != NULL)
307343730Speter	{
307464562Sgshapiro		ldap_unbind(lmap->ldap_ld);
307564562Sgshapiro		lmap->ldap_ld = NULL;
307643730Speter	}
307738032Speter}
307838032Speter
307964562Sgshapiro# ifdef SUNET_ID
308043730Speter/*
308142575Speter**  SUNET_ID_HASH -- Convert a string to it's Sunet_id canonical form
308242575Speter**  This only makes sense at Stanford University.
308338032Speter*/
308438032Speter
308538032Speterchar *
308638032Spetersunet_id_hash(str)
308738032Speter	char *str;
308838032Speter{
308938032Speter	char *p, *p_last;
309038032Speter
309138032Speter	p = str;
309238032Speter	p_last = p;
309338032Speter	while (*p != '\0')
309438032Speter	{
309538032Speter		if (islower(*p) || isdigit(*p))
309638032Speter		{
309738032Speter			*p_last = *p;
309838032Speter			p_last++;
309938032Speter		}
310038032Speter		else if (isupper(*p))
310138032Speter		{
310238032Speter			*p_last = tolower(*p);
310338032Speter			p_last++;
310438032Speter		}
310538032Speter		++p;
310638032Speter	}
310738032Speter	if (*p_last != '\0')
310838032Speter		*p_last = '\0';
310964562Sgshapiro	return str;
311038032Speter}
311164562Sgshapiro# endif /* SUNET_ID */
311238032Speter
311338032Speter/*
311464562Sgshapiro**  LDAPMAP_LOOKUP -- look up a datum in a LDAP map
311538032Speter*/
311638032Speter
311738032Speterchar *
311864562Sgshapiroldapmap_lookup(map, name, av, statp)
311938032Speter	MAP *map;
312038032Speter	char *name;
312138032Speter	char **av;
312238032Speter	int *statp;
312338032Speter{
312464562Sgshapiro	int i;
312564562Sgshapiro	int entries = 0;
312664562Sgshapiro	int msgid;
312764562Sgshapiro	int ret;
312864562Sgshapiro	int vsize;
312964562Sgshapiro	char *fp, *vp;
313064562Sgshapiro	char *p, *q;
313164562Sgshapiro	char *result = NULL;
313264562Sgshapiro	LDAPMAP_STRUCT *lmap = NULL;
313338032Speter	char keybuf[MAXNAME + 1];
313464562Sgshapiro	char filter[LDAPMAP_MAX_FILTER + 1];
313538032Speter
313638032Speter	if (tTd(38, 20))
313764562Sgshapiro		dprintf("ldapmap_lookup(%s, %s)\n", map->map_mname, name);
313838032Speter
313938032Speter	/* Get ldap struct pointer from map */
314064562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
314164562Sgshapiro	ldapmap_setopts(lmap->ldap_ld, lmap);
314238032Speter
314364562Sgshapiro	(void) strlcpy(keybuf, name, sizeof keybuf);
314438032Speter
314538032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
314664562Sgshapiro	{
314764562Sgshapiro# ifdef SUNET_ID
314838032Speter		sunet_id_hash(keybuf);
314964562Sgshapiro# else /* SUNET_ID */
315038032Speter		makelower(keybuf);
315164562Sgshapiro# endif /* SUNET_ID */
315264562Sgshapiro	}
315338032Speter
315442575Speter	/* substitute keybuf into filter, perhaps multiple times */
315564562Sgshapiro	memset(filter, '\0', sizeof filter);
315642575Speter	fp = filter;
315764562Sgshapiro	p = lmap->ldap_filter;
315842575Speter	while ((q = strchr(p, '%')) != NULL)
315942575Speter	{
316042575Speter		if (q[1] == 's')
316142575Speter		{
316242575Speter			snprintf(fp, SPACELEFT(filter, fp), "%.*s%s",
316366494Sgshapiro				 (int) (q - p), p, keybuf);
316464562Sgshapiro			fp += strlen(fp);
316542575Speter			p = q + 2;
316642575Speter		}
316764562Sgshapiro		else if (q[1] == '0')
316864562Sgshapiro		{
316964562Sgshapiro			char *k = keybuf;
317064562Sgshapiro
317164562Sgshapiro			snprintf(fp, SPACELEFT(filter, fp), "%.*s",
317266494Sgshapiro				 (int) (q - p), p);
317364562Sgshapiro			fp += strlen(fp);
317464562Sgshapiro			p = q + 2;
317564562Sgshapiro
317664562Sgshapiro			/* Properly escape LDAP special characters */
317764562Sgshapiro			while (SPACELEFT(filter, fp) > 0 &&
317864562Sgshapiro			       *k != '\0')
317964562Sgshapiro			{
318064562Sgshapiro				if (*k == '*' || *k == '(' ||
318164562Sgshapiro				    *k == ')' || *k == '\\')
318264562Sgshapiro				{
318364562Sgshapiro					(void) strlcat(fp,
318464562Sgshapiro						       (*k == '*' ? "\\2A" :
318564562Sgshapiro							(*k == '(' ? "\\28" :
318664562Sgshapiro							 (*k == ')' ? "\\29" :
318764562Sgshapiro							  (*k == '\\' ? "\\5C" :
318864562Sgshapiro							   "\00")))),
318964562Sgshapiro						SPACELEFT(filter, fp));
319064562Sgshapiro					fp += strlen(fp);
319164562Sgshapiro					k++;
319264562Sgshapiro				}
319364562Sgshapiro				else
319464562Sgshapiro					*fp++ = *k++;
319564562Sgshapiro			}
319664562Sgshapiro		}
319742575Speter		else
319842575Speter		{
319942575Speter			snprintf(fp, SPACELEFT(filter, fp), "%.*s",
320066494Sgshapiro				 (int) (q - p + 1), p);
320142575Speter			p = q + (q[1] == '%' ? 2 : 1);
320264562Sgshapiro			fp += strlen(fp);
320342575Speter		}
320442575Speter	}
320542575Speter	snprintf(fp, SPACELEFT(filter, fp), "%s", p);
320642575Speter	if (tTd(38, 20))
320764562Sgshapiro		dprintf("ldap search filter=%s\n", filter);
320838032Speter
320964562Sgshapiro	lmap->ldap_res = NULL;
321064562Sgshapiro	msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope,
321164562Sgshapiro			    filter,
321264562Sgshapiro			    (lmap->ldap_attr[0] == NULL ? NULL :
321364562Sgshapiro			     lmap->ldap_attr),
321464562Sgshapiro			    lmap->ldap_attrsonly);
321564562Sgshapiro	if (msgid == -1)
321638032Speter	{
321764562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
321864562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
321938032Speter		{
322064562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
322166494Sgshapiro				syserr("Error in ldap_search using %s in map %s",
322264562Sgshapiro				       filter, map->map_mname);
322364562Sgshapiro			else
322466494Sgshapiro				syserr("421 4.0.0 Error in ldap_search using %s in map %s",
322564562Sgshapiro				       filter, map->map_mname);
322638032Speter		}
322764562Sgshapiro		*statp = EX_TEMPFAIL;
322866494Sgshapiro#ifdef LDAP_SERVER_DOWN
322966494Sgshapiro		if (errno == LDAP_SERVER_DOWN)
323066494Sgshapiro		{
323166494Sgshapiro			int save_errno = errno;
323266494Sgshapiro
323366494Sgshapiro			/* server disappeared, try reopen on next search */
323466494Sgshapiro			map->map_class->map_close(map);
323566494Sgshapiro			map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
323666494Sgshapiro			errno = save_errno;
323766494Sgshapiro		}
323866494Sgshapiro#endif /* LDAP_SERVER_DOWN */
323964562Sgshapiro		return NULL;
324064562Sgshapiro	}
324164562Sgshapiro
324264562Sgshapiro	*statp = EX_NOTFOUND;
324364562Sgshapiro	vp = NULL;
324464562Sgshapiro
324564562Sgshapiro	/* Get results (all if MF_NOREWRITE, otherwise one by one) */
324664562Sgshapiro	while ((ret = ldap_result(lmap->ldap_ld, msgid,
324764562Sgshapiro				  bitset(MF_NOREWRITE, map->map_mflags),
324864562Sgshapiro				  (lmap->ldap_timeout.tv_sec == 0 ? NULL :
324964562Sgshapiro				   &(lmap->ldap_timeout)),
325064562Sgshapiro				  &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY)
325164562Sgshapiro	{
325264562Sgshapiro		LDAPMessage *entry;
325364562Sgshapiro
325464562Sgshapiro		if (bitset(MF_SINGLEMATCH, map->map_mflags))
325538032Speter		{
325664562Sgshapiro			entries += ldap_count_entries(lmap->ldap_ld,
325764562Sgshapiro						      lmap->ldap_res);
325864562Sgshapiro			if (entries > 1)
325964562Sgshapiro			{
326064562Sgshapiro				*statp = EX_NOTFOUND;
326164562Sgshapiro				if (lmap->ldap_res != NULL)
326264562Sgshapiro				{
326364562Sgshapiro					ldap_msgfree(lmap->ldap_res);
326464562Sgshapiro					lmap->ldap_res = NULL;
326564562Sgshapiro				}
326664562Sgshapiro				(void) ldap_abandon(lmap->ldap_ld, msgid);
326764562Sgshapiro				if (vp != NULL)
326864562Sgshapiro					free(vp);
326964562Sgshapiro				if (tTd(38, 25))
327064562Sgshapiro					dprintf("ldap search found multiple on a single match query\n");
327164562Sgshapiro				return NULL;
327264562Sgshapiro			}
327364562Sgshapiro		}
327464562Sgshapiro
327564562Sgshapiro		/* If we don't want multiple values and we have one, break */
327664562Sgshapiro		if (map->map_coldelim == '\0' && vp != NULL)
327764562Sgshapiro			break;
327864562Sgshapiro
327964562Sgshapiro		/* Cycle through all entries */
328064562Sgshapiro		for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res);
328164562Sgshapiro		     entry != NULL;
328264562Sgshapiro		     entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res))
328364562Sgshapiro		{
328464562Sgshapiro			BerElement *ber;
328564562Sgshapiro			char *attr;
328664562Sgshapiro			char **vals = NULL;
328764562Sgshapiro
328864562Sgshapiro			/*
328964562Sgshapiro			**  If matching only and found an entry,
329064562Sgshapiro			**  no need to spin through attributes
329164562Sgshapiro			*/
329264562Sgshapiro
329364562Sgshapiro			if (*statp == EX_OK &&
329464562Sgshapiro			    bitset(MF_MATCHONLY, map->map_mflags))
329564562Sgshapiro				continue;
329664562Sgshapiro
329764562Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
329864562Sgshapiro			/*
329964562Sgshapiro			**  Reset value to prevent lingering
330064562Sgshapiro			**  LDAP_DECODING_ERROR due to
330164562Sgshapiro			**  OpenLDAP 1.X's hack (see below)
330264562Sgshapiro			*/
330364562Sgshapiro
330464562Sgshapiro			lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
330564562Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
330664562Sgshapiro
330764562Sgshapiro			for (attr = ldap_first_attribute(lmap->ldap_ld, entry,
330864562Sgshapiro							 &ber);
330964562Sgshapiro			     attr != NULL;
331064562Sgshapiro			     attr = ldap_next_attribute(lmap->ldap_ld, entry,
331164562Sgshapiro							ber))
331264562Sgshapiro			{
331364562Sgshapiro				char *tmp, *vp_tmp;
331464562Sgshapiro
331564562Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_FALSE)
331664562Sgshapiro				{
331764562Sgshapiro					vals = ldap_get_values(lmap->ldap_ld,
331864562Sgshapiro							       entry,
331964562Sgshapiro							       attr);
332064562Sgshapiro					if (vals == NULL)
332164562Sgshapiro					{
332264562Sgshapiro						errno = ldapmap_geterrno(lmap->ldap_ld);
332364562Sgshapiro						if (errno == LDAP_SUCCESS)
332464562Sgshapiro							continue;
332564562Sgshapiro
332664562Sgshapiro						/* Must be an error */
332764562Sgshapiro						errno += E_LDAPBASE;
332864562Sgshapiro						if (!bitset(MF_OPTIONAL,
332964562Sgshapiro							    map->map_mflags))
333064562Sgshapiro						{
333164562Sgshapiro							if (bitset(MF_NODEFER,
333264562Sgshapiro								   map->map_mflags))
333364562Sgshapiro								syserr("Error getting LDAP values in map %s",
333464562Sgshapiro								       map->map_mname);
333564562Sgshapiro							else
333664562Sgshapiro								syserr("421 4.0.0 Error getting LDAP values in map %s",
333764562Sgshapiro								       map->map_mname);
333864562Sgshapiro						}
333964562Sgshapiro						*statp = EX_TEMPFAIL;
334064562Sgshapiro# if USING_NETSCAPE_LDAP
334166494Sgshapiro						ldap_memfree(attr);
334264562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
334364562Sgshapiro						if (lmap->ldap_res != NULL)
334464562Sgshapiro						{
334564562Sgshapiro							ldap_msgfree(lmap->ldap_res);
334664562Sgshapiro							lmap->ldap_res = NULL;
334764562Sgshapiro						}
334864562Sgshapiro						(void) ldap_abandon(lmap->ldap_ld,
334964562Sgshapiro								    msgid);
335064562Sgshapiro						if (vp != NULL)
335164562Sgshapiro							free(vp);
335264562Sgshapiro						return NULL;
335364562Sgshapiro					}
335464562Sgshapiro				}
335564562Sgshapiro
335664562Sgshapiro				*statp = EX_OK;
335764562Sgshapiro
335864562Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT)
335964562Sgshapiro				/*
336064562Sgshapiro				**  Reset value to prevent lingering
336164562Sgshapiro				**  LDAP_DECODING_ERROR due to
336264562Sgshapiro				**  OpenLDAP 1.X's hack (see below)
336364562Sgshapiro				*/
336464562Sgshapiro
336564562Sgshapiro				lmap->ldap_ld->ld_errno = LDAP_SUCCESS;
336664562Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */
336764562Sgshapiro
336864562Sgshapiro				/*
336964562Sgshapiro				**  If matching only,
337064562Sgshapiro				**  no need to spin through entries
337164562Sgshapiro				*/
337264562Sgshapiro
337364562Sgshapiro				if (bitset(MF_MATCHONLY, map->map_mflags))
337464562Sgshapiro					continue;
337564562Sgshapiro
337664562Sgshapiro				/*
337764562Sgshapiro				**  If we don't want multiple values,
337864562Sgshapiro				**  return first found.
337964562Sgshapiro				*/
338064562Sgshapiro
338164562Sgshapiro				if (map->map_coldelim == '\0')
338264562Sgshapiro				{
338364562Sgshapiro					if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
338464562Sgshapiro					{
338564562Sgshapiro						vp = newstr(attr);
338664562Sgshapiro# if USING_NETSCAPE_LDAP
338766494Sgshapiro						ldap_memfree(attr);
338864562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
338964562Sgshapiro						break;
339064562Sgshapiro					}
339164562Sgshapiro
339264562Sgshapiro					if (vals[0] == NULL)
339364562Sgshapiro					{
339464562Sgshapiro						ldap_value_free(vals);
339564562Sgshapiro# if USING_NETSCAPE_LDAP
339666494Sgshapiro						ldap_memfree(attr);
339764562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
339864562Sgshapiro						continue;
339964562Sgshapiro					}
340064562Sgshapiro
340164562Sgshapiro					vp = newstr(vals[0]);
340264562Sgshapiro					ldap_value_free(vals);
340364562Sgshapiro# if USING_NETSCAPE_LDAP
340466494Sgshapiro					ldap_memfree(attr);
340564562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
340664562Sgshapiro					break;
340764562Sgshapiro				}
340864562Sgshapiro
340964562Sgshapiro				/* attributes only */
341064562Sgshapiro				if (lmap->ldap_attrsonly == LDAPMAP_TRUE)
341164562Sgshapiro				{
341264562Sgshapiro					if (vp == NULL)
341364562Sgshapiro						vp = newstr(attr);
341464562Sgshapiro					else
341564562Sgshapiro					{
341664562Sgshapiro						vsize = strlen(vp) +
341764562Sgshapiro							strlen(attr) + 2;
341864562Sgshapiro						tmp = xalloc(vsize);
341964562Sgshapiro						snprintf(tmp, vsize, "%s%c%s",
342064562Sgshapiro							 vp, map->map_coldelim,
342164562Sgshapiro							 attr);
342264562Sgshapiro						free(vp);
342364562Sgshapiro						vp = tmp;
342464562Sgshapiro					}
342564562Sgshapiro# if USING_NETSCAPE_LDAP
342666494Sgshapiro					ldap_memfree(attr);
342764562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
342864562Sgshapiro					continue;
342964562Sgshapiro				}
343064562Sgshapiro
343164562Sgshapiro				/*
343264562Sgshapiro				**  If there is more than one,
343364562Sgshapiro				**  munge then into a map_coldelim
343464562Sgshapiro				**  separated string
343564562Sgshapiro				*/
343664562Sgshapiro
343764562Sgshapiro				vsize = 0;
343864562Sgshapiro				for (i = 0; vals[i] != NULL; i++)
343964562Sgshapiro					vsize += strlen(vals[i]) + 1;
344064562Sgshapiro				vp_tmp = xalloc(vsize);
344164562Sgshapiro				*vp_tmp = '\0';
344264562Sgshapiro
344364562Sgshapiro				p = vp_tmp;
344464562Sgshapiro				for (i = 0; vals[i] != NULL; i++)
344564562Sgshapiro				{
344664562Sgshapiro					p += strlcpy(p, vals[i],
344764562Sgshapiro						     vsize - (p - vp_tmp));
344864562Sgshapiro					if (p >= vp_tmp + vsize)
344964562Sgshapiro						syserr("ldapmap_lookup: Internal error: buffer too small for LDAP values");
345064562Sgshapiro					if (vals[i + 1] != NULL)
345164562Sgshapiro						*p++ = map->map_coldelim;
345264562Sgshapiro				}
345364562Sgshapiro
345464562Sgshapiro				ldap_value_free(vals);
345564562Sgshapiro# if USING_NETSCAPE_LDAP
345666494Sgshapiro				ldap_memfree(attr);
345764562Sgshapiro# endif /* USING_NETSCAPE_LDAP */
345864562Sgshapiro				if (vp == NULL)
345964562Sgshapiro				{
346064562Sgshapiro					vp = vp_tmp;
346164562Sgshapiro					continue;
346264562Sgshapiro				}
346364562Sgshapiro				vsize = strlen(vp) + strlen(vp_tmp) + 2;
346464562Sgshapiro				tmp = xalloc(vsize);
346564562Sgshapiro				snprintf(tmp, vsize, "%s%c%s",
346664562Sgshapiro					 vp, map->map_coldelim, vp_tmp);
346764562Sgshapiro
346864562Sgshapiro				free(vp);
346964562Sgshapiro				free(vp_tmp);
347064562Sgshapiro				vp = tmp;
347164562Sgshapiro			}
347264562Sgshapiro			errno = ldapmap_geterrno(lmap->ldap_ld);
347364562Sgshapiro
347464562Sgshapiro			/*
347564562Sgshapiro			**  We check errno != LDAP_DECODING_ERROR since
347664562Sgshapiro			**  OpenLDAP 1.X has a very ugly *undocumented*
347764562Sgshapiro			**  hack of returning this error code from
347864562Sgshapiro			**  ldap_next_attribute() if the library freed the
347964562Sgshapiro			**  ber attribute.  See:
348064562Sgshapiro			**  http://www.openldap.org/lists/openldap-devel/9901/msg00064.html
348164562Sgshapiro			*/
348264562Sgshapiro
348364562Sgshapiro			if (errno != LDAP_SUCCESS &&
348464562Sgshapiro			    errno != LDAP_DECODING_ERROR)
348564562Sgshapiro			{
348664562Sgshapiro				/* Must be an error */
348764562Sgshapiro				errno += E_LDAPBASE;
348864562Sgshapiro				if (!bitset(MF_OPTIONAL, map->map_mflags))
348964562Sgshapiro				{
349064562Sgshapiro					if (bitset(MF_NODEFER, map->map_mflags))
349164562Sgshapiro						syserr("Error getting LDAP attributes in map %s",
349264562Sgshapiro						       map->map_mname);
349364562Sgshapiro					else
349464562Sgshapiro						syserr("421 4.0.0 Error getting LDAP attributes in map %s",
349564562Sgshapiro						       map->map_mname);
349664562Sgshapiro				}
349764562Sgshapiro				*statp = EX_TEMPFAIL;
349864562Sgshapiro				if (lmap->ldap_res != NULL)
349964562Sgshapiro				{
350064562Sgshapiro					ldap_msgfree(lmap->ldap_res);
350164562Sgshapiro					lmap->ldap_res = NULL;
350264562Sgshapiro				}
350364562Sgshapiro				(void) ldap_abandon(lmap->ldap_ld, msgid);
350464562Sgshapiro				if (vp != NULL)
350564562Sgshapiro					free(vp);
350664562Sgshapiro				return NULL;
350764562Sgshapiro			}
350864562Sgshapiro
350964562Sgshapiro			/* We don't want multiple values and we have one */
351064562Sgshapiro			if (map->map_coldelim == '\0' && vp != NULL)
351164562Sgshapiro				break;
351264562Sgshapiro		}
351364562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld);
351464562Sgshapiro		if (errno != LDAP_SUCCESS && errno != LDAP_DECODING_ERROR)
351564562Sgshapiro		{
351664562Sgshapiro			/* Must be an error */
351764562Sgshapiro			errno += E_LDAPBASE;
351838032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
351938032Speter			{
352064562Sgshapiro				if (bitset(MF_NODEFER, map->map_mflags))
352164562Sgshapiro					syserr("Error getting LDAP entries in map %s",
352264562Sgshapiro					       map->map_mname);
352364562Sgshapiro				else
352464562Sgshapiro					syserr("421 4.0.0 Error getting LDAP entries in map %s",
352564562Sgshapiro					       map->map_mname);
352638032Speter			}
352738032Speter			*statp = EX_TEMPFAIL;
352864562Sgshapiro			if (lmap->ldap_res != NULL)
352964562Sgshapiro			{
353064562Sgshapiro				ldap_msgfree(lmap->ldap_res);
353164562Sgshapiro				lmap->ldap_res = NULL;
353264562Sgshapiro			}
353364562Sgshapiro			(void) ldap_abandon(lmap->ldap_ld, msgid);
353464562Sgshapiro			if (vp != NULL)
353564562Sgshapiro				free(vp);
353664562Sgshapiro			return NULL;
353738032Speter		}
353864562Sgshapiro		ldap_msgfree(lmap->ldap_res);
353964562Sgshapiro		lmap->ldap_res = NULL;
354038032Speter	}
354138032Speter
354264562Sgshapiro	/*
354364562Sgshapiro	**  If grabbing all results at once for MF_NOREWRITE and
354464562Sgshapiro	**  only want a single match, make sure that's all we have
354564562Sgshapiro	*/
354664562Sgshapiro
354764562Sgshapiro	if (ret == LDAP_RES_SEARCH_RESULT &&
354864562Sgshapiro	    bitset(MF_NOREWRITE|MF_SINGLEMATCH, map->map_mflags))
354938032Speter	{
355064562Sgshapiro		entries += ldap_count_entries(lmap->ldap_ld, lmap->ldap_res);
355164562Sgshapiro		if (entries > 1)
355264562Sgshapiro		{
355364562Sgshapiro			*statp = EX_NOTFOUND;
355464562Sgshapiro			if (lmap->ldap_res != NULL)
355564562Sgshapiro			{
355664562Sgshapiro				ldap_msgfree(lmap->ldap_res);
355764562Sgshapiro				lmap->ldap_res = NULL;
355864562Sgshapiro			}
355964562Sgshapiro			if (vp != NULL)
356064562Sgshapiro				free(vp);
356164562Sgshapiro			return NULL;
356264562Sgshapiro		}
356364562Sgshapiro		*statp = EX_OK;
356438032Speter	}
356538032Speter
356664562Sgshapiro	if (ret == 0)
356764562Sgshapiro		errno = ETIMEDOUT;
356864562Sgshapiro	else
356964562Sgshapiro		errno = ldapmap_geterrno(lmap->ldap_ld);
357064562Sgshapiro	if (errno != LDAP_SUCCESS)
357138032Speter	{
357264562Sgshapiro		/* Must be an error */
357364562Sgshapiro		if (ret != 0)
357464562Sgshapiro			errno += E_LDAPBASE;
357564562Sgshapiro		if (!bitset(MF_OPTIONAL, map->map_mflags))
357664562Sgshapiro		{
357764562Sgshapiro			if (bitset(MF_NODEFER, map->map_mflags))
357864562Sgshapiro				syserr("Error getting LDAP results in map %s",
357964562Sgshapiro				       map->map_mname);
358064562Sgshapiro			else
358164562Sgshapiro				syserr("421 4.0.0 Error getting LDAP results in map %s",
358264562Sgshapiro				       map->map_mname);
358364562Sgshapiro		}
358464562Sgshapiro		*statp = EX_TEMPFAIL;
358564562Sgshapiro		if (vp != NULL)
358664562Sgshapiro			free(vp);
358764562Sgshapiro		return NULL;
358838032Speter	}
358938032Speter
359064562Sgshapiro	/* Did we match anything? */
359171345Sgshapiro	if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags))
359264562Sgshapiro		return NULL;
359338032Speter
359464562Sgshapiro	/*
359564562Sgshapiro	**  If MF_NOREWRITE, we are special map which doesn't
359664562Sgshapiro	**  actually return a map value.  Instead, we don't free
359764562Sgshapiro	**  ldap_res and let the calling function process the LDAP
359864562Sgshapiro	**  results.  The caller should ldap_msgfree(lmap->ldap_res).
359964562Sgshapiro	*/
360038032Speter
360164562Sgshapiro	if (bitset(MF_NOREWRITE, map->map_mflags))
360264562Sgshapiro	{
360371345Sgshapiro		if (vp != NULL)
360471345Sgshapiro			free(vp);
360564562Sgshapiro		return "";
360664562Sgshapiro	}
360738032Speter
360864562Sgshapiro	if (*statp == EX_OK)
360964562Sgshapiro	{
361064562Sgshapiro		if (LogLevel > 9)
361164562Sgshapiro			sm_syslog(LOG_INFO, CurEnv->e_id,
361271345Sgshapiro				  "ldap %.100s => %s", name,
361371345Sgshapiro				  vp == NULL ? "<NULL>" : vp);
361464562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
361564562Sgshapiro			result = map_rewrite(map, name, strlen(name), NULL);
361664562Sgshapiro		else
361771345Sgshapiro		{
361871345Sgshapiro			/* vp != NULL according to test above */
361964562Sgshapiro			result = map_rewrite(map, vp, strlen(vp), av);
362071345Sgshapiro		}
362171345Sgshapiro		if (vp != NULL)
362271345Sgshapiro			free(vp);
362364562Sgshapiro	}
362464562Sgshapiro	return result;
362538032Speter}
362638032Speter
362738032Speter/*
362864562Sgshapiro**  LDAPMAP_FINDCONN -- find an LDAP connection to the server
362964562Sgshapiro**
363064562Sgshapiro**	Cache LDAP connections based on the host, port, bind DN,
363166494Sgshapiro**	secret, and PID so we don't have multiple connections open to
363266494Sgshapiro**	the same server for different maps.  Need a separate connection
363366494Sgshapiro**	per PID since a parent process may close the map before the
363466494Sgshapiro**	child is done with it.
363564562Sgshapiro**
363664562Sgshapiro**	Parameters:
363764562Sgshapiro**		lmap -- LDAP map information
363864562Sgshapiro**
363964562Sgshapiro**	Returns:
364064562Sgshapiro**		Symbol table entry for the LDAP connection.
364164562Sgshapiro**
364238032Speter*/
364338032Speter
364464562Sgshapirostatic STAB *
364564562Sgshapiroldapmap_findconn(lmap)
364664562Sgshapiro	LDAPMAP_STRUCT *lmap;
364738032Speter{
364864562Sgshapiro	int len;
364964562Sgshapiro	char *nbuf;
365064562Sgshapiro	STAB *s;
365138032Speter
365264562Sgshapiro	len = (lmap->ldap_host == NULL ? strlen("localhost") :
365364562Sgshapiro					 strlen(lmap->ldap_host)) + 1 + 8 + 1 +
365464562Sgshapiro		(lmap->ldap_binddn == NULL ? 0 : strlen(lmap->ldap_binddn)) +
365564562Sgshapiro		1 +
365664562Sgshapiro		(lmap->ldap_secret == NULL ? 0 : strlen(lmap->ldap_secret)) +
365766494Sgshapiro		8 + 1;
365864562Sgshapiro	nbuf = xalloc(len);
365966494Sgshapiro	snprintf(nbuf, len, "%s%c%d%c%s%c%s%d",
366064562Sgshapiro		 (lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host),
366164562Sgshapiro		 CONDELSE,
366264562Sgshapiro		 lmap->ldap_port,
366364562Sgshapiro		 CONDELSE,
366464562Sgshapiro		 (lmap->ldap_binddn == NULL ? "" : lmap->ldap_binddn),
366564562Sgshapiro		 CONDELSE,
366666494Sgshapiro		 (lmap->ldap_secret == NULL ? "" : lmap->ldap_secret),
366766494Sgshapiro		 getpid());
366864562Sgshapiro	s = stab(nbuf, ST_LDAP, ST_ENTER);
366964562Sgshapiro	free(nbuf);
367064562Sgshapiro	return s;
367164562Sgshapiro}
367264562Sgshapiro/*
367364562Sgshapiro**  LDAPMAP_SETOPTS -- set LDAP options
367464562Sgshapiro**
367564562Sgshapiro**	Parameters:
367664562Sgshapiro**		ld -- LDAP session handle
367764562Sgshapiro**		lmap -- LDAP map information
367864562Sgshapiro**
367964562Sgshapiro**	Returns:
368064562Sgshapiro**		None.
368164562Sgshapiro**
368264562Sgshapiro*/
368364562Sgshapiro
368464562Sgshapirostatic void
368564562Sgshapiroldapmap_setopts(ld, lmap)
368664562Sgshapiro	LDAP *ld;
368764562Sgshapiro	LDAPMAP_STRUCT *lmap;
368864562Sgshapiro{
368964562Sgshapiro# if USE_LDAP_SET_OPTION
369064562Sgshapiro	ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref);
369164562Sgshapiro	if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options))
369264562Sgshapiro		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON);
369338032Speter	else
369464562Sgshapiro		ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
369564562Sgshapiro	ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit);
369664562Sgshapiro	ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit);
369764562Sgshapiro# else /* USE_LDAP_SET_OPTION */
369864562Sgshapiro	/* From here on in we can use ldap internal timelimits */
369964562Sgshapiro	ld->ld_deref = lmap->ldap_deref;
370064562Sgshapiro	ld->ld_options = lmap->ldap_options;
370164562Sgshapiro	ld->ld_sizelimit = lmap->ldap_sizelimit;
370264562Sgshapiro	ld->ld_timelimit = lmap->ldap_timelimit;
370364562Sgshapiro# endif /* USE_LDAP_SET_OPTION */
370438032Speter}
370564562Sgshapiro/*
370664562Sgshapiro**  LDAPMAP_GETERRNO -- get ldap errno value
370764562Sgshapiro**
370864562Sgshapiro**	Parameters:
370964562Sgshapiro**		ld -- LDAP session handle
371064562Sgshapiro**
371164562Sgshapiro**	Returns:
371264562Sgshapiro**		LDAP errno.
371364562Sgshapiro**
371464562Sgshapiro*/
371538032Speter
371664562Sgshapirostatic int
371764562Sgshapiroldapmap_geterrno(ld)
371864562Sgshapiro	LDAP *ld;
371964562Sgshapiro{
372064562Sgshapiro	int err = LDAP_SUCCESS;
372164562Sgshapiro
372264562Sgshapiro# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3
372364562Sgshapiro	(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
372464562Sgshapiro# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
372564562Sgshapiro#  ifdef LDAP_OPT_SIZELIMIT
372664562Sgshapiro	err = ldap_get_lderrno(ld, NULL, NULL);
372764562Sgshapiro#  else /* LDAP_OPT_SIZELIMIT */
372864562Sgshapiro	err = ld->ld_errno;
372964562Sgshapiro
373064562Sgshapiro	/*
373164562Sgshapiro	**  Reset value to prevent lingering LDAP_DECODING_ERROR due to
373264562Sgshapiro	**  OpenLDAP 1.X's hack (see above)
373364562Sgshapiro	*/
373464562Sgshapiro
373564562Sgshapiro	ld->ld_errno = LDAP_SUCCESS;
373664562Sgshapiro#  endif /* LDAP_OPT_SIZELIMIT */
373764562Sgshapiro# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */
373864562Sgshapiro	return err;
373964562Sgshapiro}
374064562Sgshapiro
374138032Speter/*
374264562Sgshapiro**  LDAPX_MAP_PARSEARGS -- print warning about use of ldapx map.
374338032Speter*/
374438032Speter
374538032Speterbool
374664562Sgshapiroldapx_map_parseargs(map, args)
374738032Speter	MAP *map;
374838032Speter	char *args;
374938032Speter{
375064562Sgshapiro	printf("Warning: The \"ldapx\" map class is deprecated and will be removed in a future\n");
375164562Sgshapiro	printf("         version.  Use the \"ldap\" map class instead for map \"%s\".\n",
375264562Sgshapiro	       map->map_mname);
375364562Sgshapiro	return ldapmap_parseargs(map, args);
375464562Sgshapiro}
375538032Speter
375664562Sgshapiro/*
375764562Sgshapiro**  LDAPMAP_PARSEARGS -- parse ldap map definition args.
375864562Sgshapiro*/
375938032Speter
376064562Sgshapirostruct lamvalues LDAPAuthMethods[] =
376164562Sgshapiro{
376264562Sgshapiro	{	"none",		LDAP_AUTH_NONE		},
376364562Sgshapiro	{	"simple",	LDAP_AUTH_SIMPLE	},
376464562Sgshapiro# ifdef LDAP_AUTH_KRBV4
376564562Sgshapiro	{	"krbv4",	LDAP_AUTH_KRBV4		},
376664562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
376764562Sgshapiro	{	NULL,		0			}
376864562Sgshapiro};
376938032Speter
377064562Sgshapirostruct ladvalues LDAPAliasDereference[] =
377164562Sgshapiro{
377264562Sgshapiro	{	"never",	LDAP_DEREF_NEVER	},
377364562Sgshapiro	{	"always",	LDAP_DEREF_ALWAYS	},
377464562Sgshapiro	{	"search",	LDAP_DEREF_SEARCHING	},
377564562Sgshapiro	{	"find",		LDAP_DEREF_FINDING	},
377664562Sgshapiro	{	NULL,		0			}
377764562Sgshapiro};
377838032Speter
377964562Sgshapirostruct lssvalues LDAPSearchScope[] =
378064562Sgshapiro{
378164562Sgshapiro	{	"base",		LDAP_SCOPE_BASE		},
378264562Sgshapiro	{	"one",		LDAP_SCOPE_ONELEVEL	},
378364562Sgshapiro	{	"sub",		LDAP_SCOPE_SUBTREE	},
378464562Sgshapiro	{	NULL,		0			}
378564562Sgshapiro};
378638032Speter
378764562Sgshapirobool
378864562Sgshapiroldapmap_parseargs(map, args)
378964562Sgshapiro	MAP *map;
379064562Sgshapiro	char *args;
379164562Sgshapiro{
379264562Sgshapiro	bool secretread = TRUE;
379364562Sgshapiro	int i;
379464562Sgshapiro	register char *p = args;
379564562Sgshapiro	LDAPMAP_STRUCT *lmap;
379664562Sgshapiro	struct lamvalues *lam;
379764562Sgshapiro	struct ladvalues *lad;
379864562Sgshapiro	struct lssvalues *lss;
379964562Sgshapiro	char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
380064562Sgshapiro
380164562Sgshapiro	/* Get ldap struct pointer from map */
380264562Sgshapiro	lmap = (LDAPMAP_STRUCT *) map->map_db1;
380364562Sgshapiro
380464562Sgshapiro	/* Check if setting the initial LDAP defaults */
380564562Sgshapiro	if (lmap == NULL || lmap != LDAPDefaults)
380664562Sgshapiro	{
380764562Sgshapiro		/* We need to alloc an LDAPMAP_STRUCT struct */
380864562Sgshapiro		lmap = (LDAPMAP_STRUCT *) xalloc(sizeof *lmap);
380964562Sgshapiro		if (LDAPDefaults == NULL)
381064562Sgshapiro			ldapmap_clear(lmap);
381164562Sgshapiro		else
381264562Sgshapiro			STRUCTCOPY(*LDAPDefaults, *lmap);
381364562Sgshapiro	}
381464562Sgshapiro
381564562Sgshapiro	/* there is no check whether there is really an argument */
381664562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
381764562Sgshapiro	map->map_spacesub = SpaceSub;	/* default value */
381838032Speter	for (;;)
381938032Speter	{
382038032Speter		while (isascii(*p) && isspace(*p))
382138032Speter			p++;
382238032Speter		if (*p != '-')
382338032Speter			break;
382438032Speter		switch (*++p)
382538032Speter		{
382638032Speter		  case 'N':
382738032Speter			map->map_mflags |= MF_INCLNULL;
382838032Speter			map->map_mflags &= ~MF_TRY0NULL;
382938032Speter			break;
383038032Speter
383138032Speter		  case 'O':
383238032Speter			map->map_mflags &= ~MF_TRY1NULL;
383338032Speter			break;
383438032Speter
383538032Speter		  case 'o':
383638032Speter			map->map_mflags |= MF_OPTIONAL;
383738032Speter			break;
383838032Speter
383938032Speter		  case 'f':
384038032Speter			map->map_mflags |= MF_NOFOLDCASE;
384138032Speter			break;
384238032Speter
384338032Speter		  case 'm':
384438032Speter			map->map_mflags |= MF_MATCHONLY;
384538032Speter			break;
384638032Speter
384738032Speter		  case 'A':
384838032Speter			map->map_mflags |= MF_APPEND;
384938032Speter			break;
385038032Speter
385138032Speter		  case 'q':
385238032Speter			map->map_mflags |= MF_KEEPQUOTES;
385338032Speter			break;
385438032Speter
385538032Speter		  case 'a':
385638032Speter			map->map_app = ++p;
385738032Speter			break;
385838032Speter
385938032Speter		  case 'T':
386038032Speter			map->map_tapp = ++p;
386138032Speter			break;
386238032Speter
386364562Sgshapiro		  case 't':
386464562Sgshapiro			map->map_mflags |= MF_NODEFER;
386564562Sgshapiro			break;
386664562Sgshapiro
386764562Sgshapiro		  case 'S':
386864562Sgshapiro			map->map_spacesub = *++p;
386964562Sgshapiro			break;
387064562Sgshapiro
387164562Sgshapiro		  case 'D':
387264562Sgshapiro			map->map_mflags |= MF_DEFER;
387364562Sgshapiro			break;
387464562Sgshapiro
387564562Sgshapiro		  case 'z':
387664562Sgshapiro			if (*++p != '\\')
387764562Sgshapiro				map->map_coldelim = *p;
387864562Sgshapiro			else
387964562Sgshapiro			{
388064562Sgshapiro				switch (*++p)
388164562Sgshapiro				{
388264562Sgshapiro				  case 'n':
388364562Sgshapiro					map->map_coldelim = '\n';
388464562Sgshapiro					break;
388564562Sgshapiro
388664562Sgshapiro				  case 't':
388764562Sgshapiro					map->map_coldelim = '\t';
388864562Sgshapiro					break;
388964562Sgshapiro
389064562Sgshapiro				  default:
389164562Sgshapiro					map->map_coldelim = '\\';
389264562Sgshapiro				}
389364562Sgshapiro			}
389464562Sgshapiro			break;
389564562Sgshapiro
389664562Sgshapiro			/* Start of ldapmap specific args */
389738032Speter		  case 'k':		/* search field */
389838032Speter			while (isascii(*++p) && isspace(*p))
389938032Speter				continue;
390064562Sgshapiro			lmap->ldap_filter = p;
390138032Speter			break;
390238032Speter
390338032Speter		  case 'v':		/* attr to return */
390438032Speter			while (isascii(*++p) && isspace(*p))
390538032Speter				continue;
390664562Sgshapiro			lmap->ldap_attr[0] = p;
390764562Sgshapiro			lmap->ldap_attr[1] = NULL;
390838032Speter			break;
390938032Speter
391064562Sgshapiro		  case '1':
391164562Sgshapiro			map->map_mflags |= MF_SINGLEMATCH;
391264562Sgshapiro			break;
391364562Sgshapiro
391438032Speter			/* args stolen from ldapsearch.c */
391538032Speter		  case 'R':		/* don't auto chase referrals */
391664562Sgshapiro# ifdef LDAP_REFERRALS
391738032Speter			lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
391864562Sgshapiro# else /* LDAP_REFERRALS */
391938032Speter			syserr("compile with -DLDAP_REFERRALS for referral support\n");
392064562Sgshapiro# endif /* LDAP_REFERRALS */
392138032Speter			break;
392238032Speter
392364562Sgshapiro		  case 'n':		/* retrieve attribute names only */
392464562Sgshapiro			lmap->ldap_attrsonly = LDAPMAP_TRUE;
392538032Speter			break;
392638032Speter
392764562Sgshapiro		  case 'r':		/* alias dereferencing */
392864562Sgshapiro			while (isascii(*++p) && isspace(*p))
392964562Sgshapiro				continue;
393064562Sgshapiro
393164562Sgshapiro			if (strncasecmp(p, "LDAP_DEREF_", 11) == 0)
393264562Sgshapiro				p += 11;
393364562Sgshapiro
393464562Sgshapiro			for (lad = LDAPAliasDereference;
393564562Sgshapiro			     lad != NULL && lad->lad_name != NULL; lad++)
393638032Speter			{
393764562Sgshapiro				if (strncasecmp(p, lad->lad_name,
393864562Sgshapiro						strlen(lad->lad_name)) == 0)
393964562Sgshapiro					break;
394038032Speter			}
394164562Sgshapiro			if (lad->lad_name != NULL)
394264562Sgshapiro				lmap->ldap_deref = lad->lad_code;
394364562Sgshapiro			else
394438032Speter			{
394564562Sgshapiro				/* bad config line */
394664562Sgshapiro				if (!bitset(MCF_OPTFILE,
394764562Sgshapiro					    map->map_class->map_cflags))
394864562Sgshapiro				{
394964562Sgshapiro					char *ptr;
395064562Sgshapiro
395164562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
395264562Sgshapiro						*ptr = '\0';
395373188Sgshapiro					syserr("Deref must be [never|always|search|find] (not %s) in map %s",
395464562Sgshapiro						p, map->map_mname);
395564562Sgshapiro					if (ptr != NULL)
395664562Sgshapiro						*ptr = ' ';
395764562Sgshapiro					return FALSE;
395864562Sgshapiro				}
395938032Speter			}
396064562Sgshapiro			break;
396164562Sgshapiro
396264562Sgshapiro		  case 's':		/* search scope */
396364562Sgshapiro			while (isascii(*++p) && isspace(*p))
396464562Sgshapiro				continue;
396564562Sgshapiro
396664562Sgshapiro			if (strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
396764562Sgshapiro				p += 11;
396864562Sgshapiro
396964562Sgshapiro			for (lss = LDAPSearchScope;
397064562Sgshapiro			     lss != NULL && lss->lss_name != NULL; lss++)
397138032Speter			{
397264562Sgshapiro				if (strncasecmp(p, lss->lss_name,
397364562Sgshapiro						strlen(lss->lss_name)) == 0)
397464562Sgshapiro					break;
397538032Speter			}
397664562Sgshapiro			if (lss->lss_name != NULL)
397764562Sgshapiro				lmap->ldap_scope = lss->lss_code;
397838032Speter			else
397964562Sgshapiro			{
398064562Sgshapiro				/* bad config line */
398164562Sgshapiro				if (!bitset(MCF_OPTFILE,
398264562Sgshapiro					    map->map_class->map_cflags))
398338032Speter				{
398438032Speter					char *ptr;
398538032Speter
398638032Speter					if ((ptr = strchr(p, ' ')) != NULL)
398738032Speter						*ptr = '\0';
398873188Sgshapiro					syserr("Scope must be [base|one|sub] (not %s) in map %s",
398938032Speter						p, map->map_mname);
399038032Speter					if (ptr != NULL)
399138032Speter						*ptr = ' ';
399238032Speter					return FALSE;
399338032Speter				}
399438032Speter			}
399538032Speter			break;
399638032Speter
399738032Speter		  case 'h':		/* ldap host */
399838032Speter			while (isascii(*++p) && isspace(*p))
399938032Speter				continue;
400064562Sgshapiro			lmap->ldap_host = p;
400138032Speter			break;
400238032Speter
400338032Speter		  case 'b':		/* search base */
400438032Speter			while (isascii(*++p) && isspace(*p))
400538032Speter				continue;
400664562Sgshapiro			lmap->ldap_base = p;
400738032Speter			break;
400838032Speter
400938032Speter		  case 'p':		/* ldap port */
401038032Speter			while (isascii(*++p) && isspace(*p))
401138032Speter				continue;
401264562Sgshapiro			lmap->ldap_port = atoi(p);
401338032Speter			break;
401438032Speter
401538032Speter		  case 'l':		/* time limit */
401638032Speter			while (isascii(*++p) && isspace(*p))
401738032Speter				continue;
401864562Sgshapiro			lmap->ldap_timelimit = atoi(p);
401964562Sgshapiro			lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
402038032Speter			break;
402138032Speter
402264562Sgshapiro		  case 'Z':
402364562Sgshapiro			while (isascii(*++p) && isspace(*p))
402464562Sgshapiro				continue;
402564562Sgshapiro			lmap->ldap_sizelimit = atoi(p);
402664562Sgshapiro			break;
402764562Sgshapiro
402864562Sgshapiro		  case 'd':		/* Dn to bind to server as */
402964562Sgshapiro			while (isascii(*++p) && isspace(*p))
403064562Sgshapiro				continue;
403164562Sgshapiro			lmap->ldap_binddn = p;
403264562Sgshapiro			break;
403364562Sgshapiro
403464562Sgshapiro		  case 'M':		/* Method for binding */
403564562Sgshapiro			while (isascii(*++p) && isspace(*p))
403664562Sgshapiro				continue;
403764562Sgshapiro
403864562Sgshapiro			if (strncasecmp(p, "LDAP_AUTH_", 10) == 0)
403964562Sgshapiro				p += 10;
404064562Sgshapiro
404164562Sgshapiro			for (lam = LDAPAuthMethods;
404264562Sgshapiro			     lam != NULL && lam->lam_name != NULL; lam++)
404364562Sgshapiro			{
404464562Sgshapiro				if (strncasecmp(p, lam->lam_name,
404564562Sgshapiro						strlen(lam->lam_name)) == 0)
404664562Sgshapiro					break;
404764562Sgshapiro			}
404864562Sgshapiro			if (lam->lam_name != NULL)
404964562Sgshapiro				lmap->ldap_method = lam->lam_code;
405064562Sgshapiro			else
405164562Sgshapiro			{
405264562Sgshapiro				/* bad config line */
405364562Sgshapiro				if (!bitset(MCF_OPTFILE,
405464562Sgshapiro					    map->map_class->map_cflags))
405564562Sgshapiro				{
405664562Sgshapiro					char *ptr;
405764562Sgshapiro
405864562Sgshapiro					if ((ptr = strchr(p, ' ')) != NULL)
405964562Sgshapiro						*ptr = '\0';
406073188Sgshapiro					syserr("Method for binding must be [none|simple|krbv4] (not %s) in map %s",
406164562Sgshapiro						p, map->map_mname);
406264562Sgshapiro					if (ptr != NULL)
406364562Sgshapiro						*ptr = ' ';
406464562Sgshapiro					return FALSE;
406564562Sgshapiro				}
406664562Sgshapiro			}
406764562Sgshapiro
406864562Sgshapiro			break;
406964562Sgshapiro
407064562Sgshapiro			/*
407164562Sgshapiro			**  This is a string that is dependent on the
407264562Sgshapiro			**  method used defined above.
407364562Sgshapiro			*/
407464562Sgshapiro
407564562Sgshapiro		  case 'P':		/* Secret password for binding */
407664562Sgshapiro			 while (isascii(*++p) && isspace(*p))
407764562Sgshapiro				continue;
407864562Sgshapiro			lmap->ldap_secret = p;
407964562Sgshapiro			secretread = FALSE;
408064562Sgshapiro			break;
408164562Sgshapiro
408264562Sgshapiro		  default:
408364562Sgshapiro			syserr("Illegal option %c map %s", *p, map->map_mname);
408464562Sgshapiro			break;
408538032Speter		}
408638032Speter
408764562Sgshapiro		/* need to account for quoted strings here */
408864562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
408938032Speter		{
409038032Speter			if (*p == '"')
409138032Speter			{
409238032Speter				while (*++p != '"' && *p != '\0')
409338032Speter					continue;
409438032Speter				if (*p != '\0')
409538032Speter					p++;
409638032Speter			}
409738032Speter			else
409838032Speter				p++;
409938032Speter		}
410038032Speter
410138032Speter		if (*p != '\0')
410238032Speter			*p++ = '\0';
410338032Speter	}
410438032Speter
410538032Speter	if (map->map_app != NULL)
410664562Sgshapiro		map->map_app = newstr(ldapmap_dequote(map->map_app));
410738032Speter	if (map->map_tapp != NULL)
410864562Sgshapiro		map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
410938032Speter
411038032Speter	/*
411142575Speter	**  We need to swallow up all the stuff into a struct
411242575Speter	**  and dump it into map->map_dbptr1
411338032Speter	*/
411438032Speter
411564562Sgshapiro	if (lmap->ldap_host != NULL &&
411664562Sgshapiro	    (LDAPDefaults == NULL ||
411764562Sgshapiro	     LDAPDefaults == lmap ||
411864562Sgshapiro	     LDAPDefaults->ldap_host != lmap->ldap_host))
411964562Sgshapiro		lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
412064562Sgshapiro	map->map_domain = lmap->ldap_host;
412164562Sgshapiro
412264562Sgshapiro	if (lmap->ldap_binddn != NULL &&
412364562Sgshapiro	    (LDAPDefaults == NULL ||
412464562Sgshapiro	     LDAPDefaults == lmap ||
412564562Sgshapiro	     LDAPDefaults->ldap_binddn != lmap->ldap_binddn))
412664562Sgshapiro		lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
412764562Sgshapiro
412864562Sgshapiro	if (lmap->ldap_secret != NULL &&
412964562Sgshapiro	    (LDAPDefaults == NULL ||
413064562Sgshapiro	     LDAPDefaults == lmap ||
413164562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
413238032Speter	{
413364562Sgshapiro		FILE *sfd;
413464562Sgshapiro		long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
413538032Speter
413664562Sgshapiro		if (DontLockReadFiles)
413764562Sgshapiro			sff |= SFF_NOLOCK;
413838032Speter
413964562Sgshapiro		/* need to use method to map secret to passwd string */
414064562Sgshapiro		switch (lmap->ldap_method)
414164562Sgshapiro		{
414264562Sgshapiro		  case LDAP_AUTH_NONE:
414364562Sgshapiro			/* Do nothing */
414464562Sgshapiro			break;
414538032Speter
414664562Sgshapiro		  case LDAP_AUTH_SIMPLE:
414738032Speter
414864562Sgshapiro			/*
414964562Sgshapiro			**  Secret is the name of a file with
415064562Sgshapiro			**  the first line as the password.
415164562Sgshapiro			*/
415264562Sgshapiro
415364562Sgshapiro			/* Already read in the secret? */
415464562Sgshapiro			if (secretread)
415564562Sgshapiro				break;
415664562Sgshapiro
415764562Sgshapiro			sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
415864562Sgshapiro					O_RDONLY, 0, sff);
415964562Sgshapiro			if (sfd == NULL)
416064562Sgshapiro			{
416164562Sgshapiro				syserr("LDAP map: cannot open secret %s",
416264562Sgshapiro				       ldapmap_dequote(lmap->ldap_secret));
416364562Sgshapiro				return FALSE;
416464562Sgshapiro			}
416564562Sgshapiro			lmap->ldap_secret = sfgets(m_tmp, LDAPMAP_MAX_PASSWD,
416666494Sgshapiro						   sfd, TimeOuts.to_fileopen,
416766494Sgshapiro						   "ldapmap_parseargs");
416864562Sgshapiro			(void) fclose(sfd);
416964562Sgshapiro			if (lmap->ldap_secret != NULL &&
417064562Sgshapiro			    strlen(m_tmp) > 0)
417164562Sgshapiro			{
417264562Sgshapiro				/* chomp newline */
417364562Sgshapiro				if (m_tmp[strlen(m_tmp) - 1] == '\n')
417464562Sgshapiro					m_tmp[strlen(m_tmp) - 1] = '\0';
417564562Sgshapiro
417664562Sgshapiro				lmap->ldap_secret = m_tmp;
417764562Sgshapiro			}
417864562Sgshapiro			break;
417964562Sgshapiro
418064562Sgshapiro# ifdef LDAP_AUTH_KRBV4
418164562Sgshapiro		  case LDAP_AUTH_KRBV4:
418264562Sgshapiro
418364562Sgshapiro			/*
418464562Sgshapiro			**  Secret is where the ticket file is
418564562Sgshapiro			**  stashed
418664562Sgshapiro			*/
418764562Sgshapiro
418864562Sgshapiro			snprintf(m_tmp, MAXPATHLEN + LDAPMAP_MAX_PASSWD,
418964562Sgshapiro				 "KRBTKFILE=%s",
419064562Sgshapiro				 ldapmap_dequote(lmap->ldap_secret));
419164562Sgshapiro			lmap->ldap_secret = m_tmp;
419264562Sgshapiro			break;
419364562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */
419464562Sgshapiro
419564562Sgshapiro		  default:	       /* Should NEVER get here */
419664562Sgshapiro			syserr("LDAP map: Illegal value in lmap method");
419764562Sgshapiro			return FALSE;
419864562Sgshapiro			break;
419964562Sgshapiro		}
420038032Speter	}
420138032Speter
420264562Sgshapiro	if (lmap->ldap_secret != NULL &&
420364562Sgshapiro	    (LDAPDefaults == NULL ||
420464562Sgshapiro	     LDAPDefaults == lmap ||
420564562Sgshapiro	     LDAPDefaults->ldap_secret != lmap->ldap_secret))
420664562Sgshapiro		lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
420738032Speter
420864562Sgshapiro	if (lmap->ldap_base != NULL &&
420964562Sgshapiro	    (LDAPDefaults == NULL ||
421064562Sgshapiro	     LDAPDefaults == lmap ||
421164562Sgshapiro	     LDAPDefaults->ldap_base != lmap->ldap_base))
421264562Sgshapiro		lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
421364562Sgshapiro
421464562Sgshapiro	/*
421564562Sgshapiro	**  Save the server from extra work.  If request is for a single
421664562Sgshapiro	**  match, tell the server to only return enough records to
421764562Sgshapiro	**  determine if there is a single match or not.  This can not
421864562Sgshapiro	**  be one since the server would only return one and we wouldn't
421964562Sgshapiro	**  know if there were others available.
422064562Sgshapiro	*/
422164562Sgshapiro
422264562Sgshapiro	if (bitset(MF_SINGLEMATCH, map->map_mflags))
422364562Sgshapiro		lmap->ldap_sizelimit = 2;
422464562Sgshapiro
422564562Sgshapiro	/* If setting defaults, don't process ldap_filter and ldap_attr */
422664562Sgshapiro	if (lmap == LDAPDefaults)
422764562Sgshapiro		return TRUE;
422864562Sgshapiro
422964562Sgshapiro	if (lmap->ldap_filter != NULL)
423064562Sgshapiro		lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
423138032Speter	else
423238032Speter	{
423338032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
423438032Speter		{
423538032Speter			syserr("No filter given in map %s", map->map_mname);
423638032Speter			return FALSE;
423738032Speter		}
423838032Speter	}
423964562Sgshapiro
424064562Sgshapiro	if (lmap->ldap_attr[0] != NULL)
424138032Speter	{
424264562Sgshapiro		i = 0;
424364562Sgshapiro		p = ldapmap_dequote(lmap->ldap_attr[0]);
424464562Sgshapiro		lmap->ldap_attr[0] = NULL;
424564562Sgshapiro
424664562Sgshapiro		while (p != NULL)
424738032Speter		{
424864562Sgshapiro			char *v;
424964562Sgshapiro
425064562Sgshapiro			while (isascii(*p) && isspace(*p))
425164562Sgshapiro				p++;
425264562Sgshapiro			if (*p == '\0')
425364562Sgshapiro				break;
425464562Sgshapiro			v = p;
425564562Sgshapiro			p = strchr(v, ',');
425664562Sgshapiro			if (p != NULL)
425764562Sgshapiro				*p++ = '\0';
425864562Sgshapiro
425971345Sgshapiro			if (i >= LDAPMAP_MAX_ATTR)
426064562Sgshapiro			{
426164562Sgshapiro				syserr("Too many return attributes in %s (max %d)",
426264562Sgshapiro				       map->map_mname, LDAPMAP_MAX_ATTR);
426364562Sgshapiro				return FALSE;
426464562Sgshapiro			}
426564562Sgshapiro			if (*v != '\0')
426664562Sgshapiro				lmap->ldap_attr[i++] = newstr(v);
426738032Speter		}
426864562Sgshapiro		lmap->ldap_attr[i] = NULL;
426938032Speter	}
427038032Speter
427138032Speter	map->map_db1 = (ARBPTR_T) lmap;
427238032Speter	return TRUE;
427338032Speter}
427438032Speter
427564562Sgshapiro/*
427664562Sgshapiro**  LDAPMAP_CLEAR -- set default values for LDAPMAP_STRUCT
427764562Sgshapiro**
427864562Sgshapiro**	Parameters:
427964562Sgshapiro**		lmap -- pointer to LDAPMAP_STRUCT to clear
428064562Sgshapiro**
428164562Sgshapiro**	Returns:
428264562Sgshapiro**		None.
428364562Sgshapiro**
428464562Sgshapiro*/
428564562Sgshapiro
428664562Sgshapirostatic void
428764562Sgshapiroldapmap_clear(lmap)
428864562Sgshapiro	LDAPMAP_STRUCT *lmap;
428964562Sgshapiro{
429064562Sgshapiro	lmap->ldap_host = NULL;
429164562Sgshapiro	lmap->ldap_port = LDAP_PORT;
429264562Sgshapiro	lmap->ldap_deref = LDAP_DEREF_NEVER;
429364562Sgshapiro	lmap->ldap_timelimit = LDAP_NO_LIMIT;
429464562Sgshapiro	lmap->ldap_sizelimit = LDAP_NO_LIMIT;
429564562Sgshapiro# ifdef LDAP_REFERRALS
429664562Sgshapiro	lmap->ldap_options = LDAP_OPT_REFERRALS;
429764562Sgshapiro# else /* LDAP_REFERRALS */
429864562Sgshapiro	lmap->ldap_options = 0;
429964562Sgshapiro# endif /* LDAP_REFERRALS */
430064562Sgshapiro	lmap->ldap_binddn = NULL;
430164562Sgshapiro	lmap->ldap_secret = NULL;
430264562Sgshapiro	lmap->ldap_method = LDAP_AUTH_SIMPLE;
430364562Sgshapiro	lmap->ldap_base = NULL;
430464562Sgshapiro	lmap->ldap_scope = LDAP_SCOPE_SUBTREE;
430564562Sgshapiro	lmap->ldap_attrsonly = LDAPMAP_FALSE;
430664562Sgshapiro	lmap->ldap_timeout.tv_sec = 0;
430764562Sgshapiro	lmap->ldap_timeout.tv_usec = 0;
430864562Sgshapiro	lmap->ldap_ld = NULL;
430964562Sgshapiro	lmap->ldap_filter = NULL;
431064562Sgshapiro	lmap->ldap_attr[0] = NULL;
431164562Sgshapiro	lmap->ldap_res = NULL;
431264562Sgshapiro}
431338032Speter/*
431464562Sgshapiro**  LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
431564562Sgshapiro**
431664562Sgshapiro**	Parameters:
431764562Sgshapiro**		spec -- map argument string from LDAPDefaults option
431864562Sgshapiro**
431964562Sgshapiro**	Returns:
432064562Sgshapiro**		None.
432164562Sgshapiro**
432264562Sgshapiro*/
432364562Sgshapiro
432464562Sgshapirovoid
432564562Sgshapiroldapmap_set_defaults(spec)
432664562Sgshapiro	char *spec;
432764562Sgshapiro{
432873188Sgshapiro	STAB *class;
432964562Sgshapiro	MAP map;
433064562Sgshapiro
433164562Sgshapiro	/* Allocate and set the default values */
433264562Sgshapiro	if (LDAPDefaults == NULL)
433364562Sgshapiro		LDAPDefaults = (LDAPMAP_STRUCT *) xalloc(sizeof *LDAPDefaults);
433464562Sgshapiro	ldapmap_clear(LDAPDefaults);
433564562Sgshapiro
433664562Sgshapiro	memset(&map, '\0', sizeof map);
433773188Sgshapiro
433873188Sgshapiro	/* look up the class */
433973188Sgshapiro	class = stab("ldap", ST_MAPCLASS, ST_FIND);
434073188Sgshapiro	if (class == NULL)
434173188Sgshapiro	{
434273188Sgshapiro		syserr("readcf: LDAPDefaultSpec: class ldap not available");
434373188Sgshapiro		return;
434473188Sgshapiro	}
434573188Sgshapiro	map.map_class = &class->s_mapclass;
434664562Sgshapiro	map.map_db1 = (ARBPTR_T) LDAPDefaults;
434773188Sgshapiro	map.map_mname = "O LDAPDefaultSpec";
434864562Sgshapiro
434964562Sgshapiro	(void) ldapmap_parseargs(&map, spec);
435064562Sgshapiro
435164562Sgshapiro	/* These should never be set in LDAPDefaults */
435264562Sgshapiro	if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
435364562Sgshapiro	    map.map_spacesub != SpaceSub ||
435464562Sgshapiro	    map.map_app != NULL ||
435564562Sgshapiro	    map.map_tapp != NULL)
435664562Sgshapiro	{
435764562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
435864562Sgshapiro		if (map.map_app != NULL)
435964562Sgshapiro		{
436064562Sgshapiro			free(map.map_app);
436164562Sgshapiro			map.map_app = NULL;
436264562Sgshapiro		}
436364562Sgshapiro		if (map.map_tapp != NULL)
436464562Sgshapiro		{
436564562Sgshapiro			free(map.map_tapp);
436664562Sgshapiro			map.map_tapp = NULL;
436764562Sgshapiro		}
436864562Sgshapiro	}
436964562Sgshapiro
437064562Sgshapiro	if (LDAPDefaults->ldap_filter != NULL)
437164562Sgshapiro	{
437264562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
437364562Sgshapiro		/* don't free, it isn't malloc'ed in parseargs */
437464562Sgshapiro		LDAPDefaults->ldap_filter = NULL;
437564562Sgshapiro	}
437664562Sgshapiro
437764562Sgshapiro	if (LDAPDefaults->ldap_attr[0] != NULL)
437864562Sgshapiro	{
437964562Sgshapiro		syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
438064562Sgshapiro		/* don't free, they aren't malloc'ed in parseargs */
438164562Sgshapiro		LDAPDefaults->ldap_attr[0] = NULL;
438264562Sgshapiro	}
438364562Sgshapiro}
438464562Sgshapiro#endif /* LDAPMAP */
438564562Sgshapiro/*
438664562Sgshapiro**  PH map
438764562Sgshapiro*/
438864562Sgshapiro
438964562Sgshapiro#ifdef PH_MAP
439064562Sgshapiro
439164562Sgshapiro/*
439264562Sgshapiro**  Support for the CCSO Nameserver (ph/qi).
439364562Sgshapiro**  This code is intended to replace the so-called "ph mailer".
439464562Sgshapiro**  Contributed by Mark D. Roth <roth@uiuc.edu>.  Contact him for support.
439564562Sgshapiro*/
439664562Sgshapiro
439764562Sgshapiro# include <qiapi.h>
439864562Sgshapiro# include <qicode.h>
439964562Sgshapiro
440064562Sgshapiro/*
440164562Sgshapiro**  PH_MAP_PARSEARGS -- parse ph map definition args.
440264562Sgshapiro*/
440364562Sgshapiro
440464562Sgshapirobool
440564562Sgshapiroph_map_parseargs(map, args)
440664562Sgshapiro	MAP *map;
440764562Sgshapiro	char *args;
440864562Sgshapiro{
440964562Sgshapiro	int i;
441064562Sgshapiro	register int done;
441164562Sgshapiro	PH_MAP_STRUCT *pmap = NULL;
441264562Sgshapiro	register char *p = args;
441364562Sgshapiro
441464562Sgshapiro	pmap = (PH_MAP_STRUCT *) xalloc(sizeof *pmap);
441564562Sgshapiro
441664562Sgshapiro	/* defaults */
441764562Sgshapiro	pmap->ph_servers = NULL;
441864562Sgshapiro	pmap->ph_field_list = NULL;
441964562Sgshapiro	pmap->ph_to_server = NULL;
442064562Sgshapiro	pmap->ph_from_server = NULL;
442164562Sgshapiro	pmap->ph_sockfd = -1;
442264562Sgshapiro	pmap->ph_timeout = 0;
442364562Sgshapiro
442464562Sgshapiro	map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
442564562Sgshapiro	for (;;)
442664562Sgshapiro	{
442764562Sgshapiro		while (isascii(*p) && isspace(*p))
442864562Sgshapiro			p++;
442964562Sgshapiro		if (*p != '-')
443064562Sgshapiro			break;
443164562Sgshapiro		switch (*++p)
443264562Sgshapiro		{
443364562Sgshapiro		  case 'N':
443464562Sgshapiro			map->map_mflags |= MF_INCLNULL;
443564562Sgshapiro			map->map_mflags &= ~MF_TRY0NULL;
443664562Sgshapiro			break;
443764562Sgshapiro
443864562Sgshapiro		  case 'O':
443964562Sgshapiro			map->map_mflags &= ~MF_TRY1NULL;
444064562Sgshapiro			break;
444164562Sgshapiro
444264562Sgshapiro		  case 'o':
444364562Sgshapiro			map->map_mflags |= MF_OPTIONAL;
444464562Sgshapiro			break;
444564562Sgshapiro
444664562Sgshapiro		  case 'f':
444764562Sgshapiro			map->map_mflags |= MF_NOFOLDCASE;
444864562Sgshapiro			break;
444964562Sgshapiro
445064562Sgshapiro		  case 'm':
445164562Sgshapiro			map->map_mflags |= MF_MATCHONLY;
445264562Sgshapiro			break;
445364562Sgshapiro
445464562Sgshapiro		  case 'A':
445564562Sgshapiro			map->map_mflags |= MF_APPEND;
445664562Sgshapiro			break;
445764562Sgshapiro
445864562Sgshapiro		  case 'q':
445964562Sgshapiro			map->map_mflags |= MF_KEEPQUOTES;
446064562Sgshapiro			break;
446164562Sgshapiro
446264562Sgshapiro		  case 't':
446364562Sgshapiro			map->map_mflags |= MF_NODEFER;
446464562Sgshapiro			break;
446564562Sgshapiro
446664562Sgshapiro		  case 'a':
446764562Sgshapiro			map->map_app = ++p;
446864562Sgshapiro			break;
446964562Sgshapiro
447064562Sgshapiro		  case 'T':
447164562Sgshapiro			map->map_tapp = ++p;
447264562Sgshapiro			break;
447364562Sgshapiro
447464562Sgshapiro#if _FFR_PHMAP_TIMEOUT
447564562Sgshapiro		  case 'l':
447664562Sgshapiro			while (isascii(*++p) && isspace(*p))
447764562Sgshapiro				continue;
447864562Sgshapiro			pmap->ph_timeout = atoi(p);
447964562Sgshapiro			break;
448064562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
448164562Sgshapiro
448264562Sgshapiro		  case 'S':
448364562Sgshapiro			map->map_spacesub = *++p;
448464562Sgshapiro			break;
448564562Sgshapiro
448664562Sgshapiro		  case 'D':
448764562Sgshapiro			map->map_mflags |= MF_DEFER;
448864562Sgshapiro			break;
448964562Sgshapiro
449064562Sgshapiro		  case 'h':		/* PH server list */
449164562Sgshapiro			while (isascii(*++p) && isspace(*p))
449264562Sgshapiro				continue;
449364562Sgshapiro			pmap->ph_servers = p;
449464562Sgshapiro			break;
449564562Sgshapiro
449664562Sgshapiro		  case 'v':		/* fields to search for */
449764562Sgshapiro			while (isascii(*++p) && isspace(*p))
449864562Sgshapiro				continue;
449964562Sgshapiro			pmap->ph_field_list = p;
450064562Sgshapiro			break;
450164562Sgshapiro
450264562Sgshapiro		  default:
450364562Sgshapiro			syserr("ph_map_parseargs: unknown option -%c\n", *p);
450464562Sgshapiro		}
450564562Sgshapiro
450664562Sgshapiro		/* try to account for quoted strings */
450764562Sgshapiro		done = isascii(*p) && isspace(*p);
450864562Sgshapiro		while (*p != '\0' && !done)
450964562Sgshapiro		{
451064562Sgshapiro			if (*p == '"')
451164562Sgshapiro			{
451264562Sgshapiro				while (*++p != '"' && *p != '\0')
451364562Sgshapiro					continue;
451464562Sgshapiro				if (*p != '\0')
451564562Sgshapiro					p++;
451664562Sgshapiro			}
451764562Sgshapiro			else
451864562Sgshapiro				p++;
451964562Sgshapiro			done = isascii(*p) && isspace(*p);
452064562Sgshapiro		}
452164562Sgshapiro
452264562Sgshapiro		if (*p != '\0')
452364562Sgshapiro			*p++ = '\0';
452464562Sgshapiro	}
452564562Sgshapiro
452664562Sgshapiro	if (map->map_app != NULL)
452764562Sgshapiro		map->map_app = newstr(ph_map_dequote(map->map_app));
452864562Sgshapiro	if (map->map_tapp != NULL)
452964562Sgshapiro		map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
453064562Sgshapiro
453164562Sgshapiro	if (pmap->ph_field_list != NULL)
453264562Sgshapiro		pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
453364562Sgshapiro	else
453464562Sgshapiro		pmap->ph_field_list = DEFAULT_PH_MAP_FIELDS;
453564562Sgshapiro
453664562Sgshapiro	if (pmap->ph_servers != NULL)
453764562Sgshapiro		pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
453864562Sgshapiro	else
453964562Sgshapiro	{
454064562Sgshapiro		syserr("ph_map_parseargs: -h flag is required");
454164562Sgshapiro		return FALSE;
454264562Sgshapiro	}
454364562Sgshapiro
454464562Sgshapiro	map->map_db1 = (ARBPTR_T) pmap;
454564562Sgshapiro	return TRUE;
454664562Sgshapiro}
454764562Sgshapiro
454864562Sgshapiro#if _FFR_PHMAP_TIMEOUT
454964562Sgshapiro/*
455064562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
455164562Sgshapiro*/
455264562Sgshapiro
455364562Sgshapirostatic void
455464562Sgshapiroph_map_safeclose(map)
455564562Sgshapiro	MAP *map;
455664562Sgshapiro{
455764562Sgshapiro	int save_errno = errno;
455864562Sgshapiro	PH_MAP_STRUCT *pmap;
455964562Sgshapiro
456064562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
456164562Sgshapiro
456264562Sgshapiro	if (pmap->ph_sockfd != -1)
456364562Sgshapiro	{
456464562Sgshapiro		(void) close(pmap->ph_sockfd);
456564562Sgshapiro		pmap->ph_sockfd = -1;
456664562Sgshapiro	}
456764562Sgshapiro	if (pmap->ph_from_server != NULL)
456864562Sgshapiro	{
456964562Sgshapiro		(void) fclose(pmap->ph_from_server);
457064562Sgshapiro		pmap->ph_from_server = NULL;
457164562Sgshapiro	}
457264562Sgshapiro	if (pmap->ph_to_server != NULL)
457364562Sgshapiro	{
457464562Sgshapiro		(void) fclose(pmap->ph_to_server);
457564562Sgshapiro		pmap->ph_to_server = NULL;
457664562Sgshapiro	}
457764562Sgshapiro	map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
457864562Sgshapiro	errno = save_errno;
457964562Sgshapiro}
458064562Sgshapiro
458164562Sgshapirovoid
458264562Sgshapiroph_map_close(map)
458364562Sgshapiro	MAP *map;
458464562Sgshapiro{
458564562Sgshapiro	PH_MAP_STRUCT *pmap;
458664562Sgshapiro
458764562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
458864562Sgshapiro	(void) fprintf(pmap->ph_to_server, "quit\n");
458964562Sgshapiro	(void) fflush(pmap->ph_to_server);
459064562Sgshapiro	ph_map_safeclose(map);
459164562Sgshapiro}
459264562Sgshapiro
459364562Sgshapirostatic jmp_buf  PHTimeout;
459464562Sgshapiro
459564562Sgshapiro/* ARGSUSED */
459664562Sgshapirostatic void
459764562Sgshapiroph_timeout_func(sig_no)
459864562Sgshapiro	int sig_no;
459964562Sgshapiro{
460064562Sgshapiro	longjmp(PHTimeout, 1);
460164562Sgshapiro}
460264562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
460364562Sgshapiro/*
460464562Sgshapiro**  PH_MAP_CLOSE -- close the connection to the ph server
460564562Sgshapiro*/
460664562Sgshapiro
460764562Sgshapirovoid
460864562Sgshapiroph_map_close(map)
460964562Sgshapiro	MAP *map;
461064562Sgshapiro{
461164562Sgshapiro	PH_MAP_STRUCT *pmap;
461264562Sgshapiro
461364562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
461464562Sgshapiro	CloseQi(pmap->ph_to_server, pmap->ph_from_server);
461564562Sgshapiro	pmap->ph_to_server = NULL;
461664562Sgshapiro	pmap->ph_from_server = NULL;
461764562Sgshapiro}
461864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
461964562Sgshapiro
462064562Sgshapiro/*
462164562Sgshapiro**  PH_MAP_OPEN -- sub for opening PH map
462264562Sgshapiro*/
462364562Sgshapirobool
462464562Sgshapiroph_map_open(map, mode)
462564562Sgshapiro	MAP *map;
462664562Sgshapiro	int mode;
462764562Sgshapiro{
462864562Sgshapiro#if !_FFR_PHMAP_TIMEOUT
462964562Sgshapiro	int save_errno = 0;
463064562Sgshapiro#endif /* !_FFR_PHMAP_TIMEOUT */
463164562Sgshapiro	int j;
463264562Sgshapiro	char *hostlist, *tmp;
463364562Sgshapiro	QIR *server_data = NULL;
463464562Sgshapiro	PH_MAP_STRUCT *pmap;
463564562Sgshapiro#if _FFR_PHMAP_TIMEOUT
463664562Sgshapiro	register EVENT *ev = NULL;
463764562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
463864562Sgshapiro
463964562Sgshapiro	if (tTd(38, 2))
464064562Sgshapiro		dprintf("ph_map_open(%s)\n", map->map_mname);
464164562Sgshapiro
464264562Sgshapiro	mode &= O_ACCMODE;
464364562Sgshapiro	if (mode != O_RDONLY)
464464562Sgshapiro	{
464564562Sgshapiro		/* issue a pseudo-error message */
464664562Sgshapiro# ifdef ENOSYS
464764562Sgshapiro		errno = ENOSYS;
464864562Sgshapiro# else /* ENOSYS */
464964562Sgshapiro#  ifdef EFTYPE
465064562Sgshapiro		errno = EFTYPE;
465164562Sgshapiro#  else /* EFTYPE */
465264562Sgshapiro		errno = ENXIO;
465364562Sgshapiro#  endif /* EFTYPE */
465464562Sgshapiro# endif /* ENOSYS */
465564562Sgshapiro		return FALSE;
465664562Sgshapiro	}
465764562Sgshapiro
465866494Sgshapiro	if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER &&
465966494Sgshapiro	    bitset(MF_DEFER, map->map_mflags))
466066494Sgshapiro	{
466166494Sgshapiro		if (tTd(9, 1))
466266494Sgshapiro			dprintf("ph_map_open(%s) => DEFERRED\n",
466371345Sgshapiro				map->map_mname);
466466494Sgshapiro
466566494Sgshapiro		/*
466666494Sgshapiro		** Unset MF_DEFER here so that map_lookup() returns
466766494Sgshapiro		** a temporary failure using the bogus map and
466866494Sgshapiro		** map->map_tapp instead of the default permanent error.
466966494Sgshapiro		*/
467066494Sgshapiro
467166494Sgshapiro		map->map_mflags &= ~MF_DEFER;
467266494Sgshapiro		return FALSE;
467366494Sgshapiro	}
467466494Sgshapiro
467564562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
467664562Sgshapiro
467764562Sgshapiro	hostlist = newstr(pmap->ph_servers);
467864562Sgshapiro	tmp = strtok(hostlist, " ");
467964562Sgshapiro	do
468064562Sgshapiro	{
468164562Sgshapiro#if _FFR_PHMAP_TIMEOUT
468264562Sgshapiro		if (pmap->ph_timeout != 0)
468364562Sgshapiro		{
468464562Sgshapiro			if (setjmp(PHTimeout) != 0)
468564562Sgshapiro			{
468664562Sgshapiro				ev = NULL;
468764562Sgshapiro				if (LogLevel > 1)
468864562Sgshapiro					sm_syslog(LOG_NOTICE, CurEnv->e_id,
468964562Sgshapiro						  "timeout connecting to PH server %.100s",
469064562Sgshapiro						  tmp);
469164562Sgshapiro# ifdef ETIMEDOUT
469264562Sgshapiro				errno = ETIMEDOUT;
469364562Sgshapiro# else /* ETIMEDOUT */
469466494Sgshapiro				errno = EAGAIN;
469564562Sgshapiro# endif /* ETIMEDOUT */
469664562Sgshapiro				goto ph_map_open_abort;
469764562Sgshapiro			}
469864562Sgshapiro			ev = setevent(pmap->ph_timeout, ph_timeout_func, 0);
469964562Sgshapiro		}
470064562Sgshapiro		if (!OpenQiSock(tmp, &(pmap->ph_sockfd)) &&
470164562Sgshapiro		    !Sock2FILEs(pmap->ph_sockfd, &(pmap->ph_to_server),
470264562Sgshapiro				&(pmap->ph_from_server)) &&
470364562Sgshapiro		    fprintf(pmap->ph_to_server, "id sendmail+phmap\n") >= 0 &&
470464562Sgshapiro		    fflush(pmap->ph_to_server) == 0 &&
470564562Sgshapiro		    (server_data = ReadQi(pmap->ph_from_server, &j)) != NULL &&
470664562Sgshapiro		    server_data->code == 200)
470764562Sgshapiro		{
470864562Sgshapiro			if (ev != NULL)
470964562Sgshapiro				clrevent(ev);
471064562Sgshapiro			FreeQIR(server_data);
471164562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
471264562Sgshapiro		if (OpenQi(tmp, &(pmap->ph_to_server),
471364562Sgshapiro			   &(pmap->ph_from_server)) >= 0)
471464562Sgshapiro		{
471564562Sgshapiro			if (fprintf(pmap->ph_to_server,
471664562Sgshapiro				    "id sendmail+phmap\n") < 0 ||
471764562Sgshapiro			    fflush(pmap->ph_to_server) < 0 ||
471864562Sgshapiro			    (server_data = ReadQi(pmap->ph_from_server,
471964562Sgshapiro						  &j)) == NULL ||
472064562Sgshapiro			    server_data->code != 200)
472164562Sgshapiro			{
472264562Sgshapiro				save_errno = errno;
472364562Sgshapiro				CloseQi(pmap->ph_to_server,
472464562Sgshapiro					pmap->ph_from_server);
472564562Sgshapiro				continue;
472664562Sgshapiro			}
472764562Sgshapiro			if (server_data != NULL)
472864562Sgshapiro				FreeQIR(server_data);
472964562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
473064562Sgshapiro			free(hostlist);
473164562Sgshapiro			return TRUE;
473264562Sgshapiro		}
473364562Sgshapiro#if _FFR_PHMAP_TIMEOUT
473464562Sgshapiro  ph_map_open_abort:
473564562Sgshapiro		if (ev != NULL)
473664562Sgshapiro			clrevent(ev);
473764562Sgshapiro		ph_map_safeclose(map);
473864562Sgshapiro		if (server_data != NULL)
473964562Sgshapiro		{
474064562Sgshapiro			FreeQIR(server_data);
474164562Sgshapiro			server_data = NULL;
474264562Sgshapiro		}
474364562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
474464562Sgshapiro		save_errno = errno;
474564562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
474664562Sgshapiro	} while (tmp = strtok(NULL, " "));
474764562Sgshapiro
474864562Sgshapiro#if !_FFR_PHMAP_TIMEOUT
474964562Sgshapiro	errno = save_errno;
475064562Sgshapiro#endif /* !_FFR_PHMAP_TIMEOUT */
475166494Sgshapiro	if (bitset(MF_NODEFER, map->map_mflags))
475264562Sgshapiro	{
475366494Sgshapiro		if (errno == 0)
475464562Sgshapiro			errno = EAGAIN;
475566494Sgshapiro		syserr("ph_map_open: %s: cannot connect to PH server",
475666494Sgshapiro		       map->map_mname);
475764562Sgshapiro	}
475866494Sgshapiro	else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1)
475964562Sgshapiro		sm_syslog(LOG_NOTICE, CurEnv->e_id,
476066494Sgshapiro			  "ph_map_open: %s: cannot connect to PH server",
476166494Sgshapiro			  map->map_mname);
476264562Sgshapiro	free(hostlist);
476364562Sgshapiro	return FALSE;
476464562Sgshapiro}
476564562Sgshapiro
476664562Sgshapiro/*
476764562Sgshapiro**  PH_MAP_LOOKUP -- look up key from ph server
476864562Sgshapiro*/
476964562Sgshapiro
477064562Sgshapiro#if _FFR_PHMAP_TIMEOUT
477164562Sgshapiro# define MAX_PH_FIELDS	20
477264562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
477364562Sgshapiro
477464562Sgshapirochar *
477564562Sgshapiroph_map_lookup(map, key, args, pstat)
477664562Sgshapiro	MAP *map;
477764562Sgshapiro	char *key;
477864562Sgshapiro	char **args;
477964562Sgshapiro	int *pstat;
478064562Sgshapiro{
478164562Sgshapiro	int j;
478264562Sgshapiro	size_t sz;
478364562Sgshapiro	char *tmp, *tmp2;
478464562Sgshapiro	char *message = NULL, *field = NULL, *fmtkey;
478564562Sgshapiro	QIR *server_data = NULL;
478664562Sgshapiro	QIR *qirp;
478764562Sgshapiro	char keybuf[MAXKEY + 1], fieldbuf[101];
478864562Sgshapiro#if _FFR_PHMAP_TIMEOUT
478964562Sgshapiro	QIR *hold_data[MAX_PH_FIELDS];
479064562Sgshapiro	int hold_data_idx = 0;
479164562Sgshapiro	register EVENT *ev = NULL;
479264562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
479364562Sgshapiro	PH_MAP_STRUCT *pmap;
479464562Sgshapiro
479564562Sgshapiro	pmap = (PH_MAP_STRUCT *)map->map_db1;
479664562Sgshapiro
479764562Sgshapiro	*pstat = EX_OK;
479864562Sgshapiro
479964562Sgshapiro#if _FFR_PHMAP_TIMEOUT
480064562Sgshapiro	if (pmap->ph_timeout != 0)
480164562Sgshapiro	{
480264562Sgshapiro		if (setjmp(PHTimeout) != 0)
480364562Sgshapiro		{
480464562Sgshapiro			ev = NULL;
480564562Sgshapiro			if (LogLevel > 1)
480664562Sgshapiro				sm_syslog(LOG_NOTICE, CurEnv->e_id,
480764562Sgshapiro					  "timeout during PH lookup of %.100s",
480864562Sgshapiro					  key);
480964562Sgshapiro# ifdef ETIMEDOUT
481064562Sgshapiro			errno = ETIMEDOUT;
481164562Sgshapiro# else /* ETIMEDOUT */
481264562Sgshapiro			errno = 0;
481364562Sgshapiro# endif /* ETIMEDOUT */
481464562Sgshapiro			*pstat = EX_TEMPFAIL;
481564562Sgshapiro			goto ph_map_lookup_abort;
481664562Sgshapiro		}
481764562Sgshapiro		ev = setevent(pmap->ph_timeout, ph_timeout_func, 0);
481864562Sgshapiro	}
481964562Sgshapiro
482064562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
482164562Sgshapiro	/* check all relevant fields */
482264562Sgshapiro	tmp = pmap->ph_field_list;
482364562Sgshapiro	do
482464562Sgshapiro	{
482564562Sgshapiro#if _FFR_PHMAP_TIMEOUT
482664562Sgshapiro		server_data = NULL;
482764562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
482864562Sgshapiro		while (isascii(*tmp) && isspace(*tmp))
482964562Sgshapiro			tmp++;
483064562Sgshapiro		if (*tmp == '\0')
483164562Sgshapiro			break;
483264562Sgshapiro		sz = strcspn(tmp, " ") + 1;
483364562Sgshapiro		if (sz > sizeof fieldbuf)
483464562Sgshapiro			sz = sizeof fieldbuf;
483564562Sgshapiro		(void) strlcpy(fieldbuf, tmp, sz);
483664562Sgshapiro		field = fieldbuf;
483764562Sgshapiro		tmp += sz;
483864562Sgshapiro
483964562Sgshapiro		(void) strlcpy(keybuf, key, sizeof keybuf);
484064562Sgshapiro		fmtkey = keybuf;
484164562Sgshapiro		if (strcmp(field, "alias") == 0)
484264562Sgshapiro		{
484364562Sgshapiro			/*
484464562Sgshapiro			**  for alias lookups, replace any punctuation
484564562Sgshapiro			**  characters with '-'
484664562Sgshapiro			*/
484764562Sgshapiro
484864562Sgshapiro			for (tmp2 = fmtkey; *tmp2 !=  '\0'; tmp2++)
484964562Sgshapiro			{
485064562Sgshapiro				if (isascii(*tmp2) && ispunct(*tmp2))
485164562Sgshapiro					*tmp2 = '-';
485264562Sgshapiro			}
485364562Sgshapiro			tmp2 = field;
485464562Sgshapiro		}
485564562Sgshapiro		else if (strcmp(field,"spacedname") == 0)
485664562Sgshapiro		{
485764562Sgshapiro			/*
485864562Sgshapiro			**  for "spaced" name lookups, replace any
485964562Sgshapiro			**  punctuation characters with a space
486064562Sgshapiro			*/
486164562Sgshapiro
486264562Sgshapiro			for (tmp2 = fmtkey; *tmp2 != '\0'; tmp2++)
486364562Sgshapiro			{
486464562Sgshapiro				if (isascii(*tmp2) && ispunct(*tmp2) &&
486564562Sgshapiro				    *tmp2 != '*')
486664562Sgshapiro					*tmp2 = ' ';
486764562Sgshapiro			}
486864562Sgshapiro			tmp2 = &(field[6]);
486964562Sgshapiro		}
487064562Sgshapiro		else
487164562Sgshapiro			tmp2 = field;
487264562Sgshapiro
487364562Sgshapiro		if (LogLevel > 9)
487464562Sgshapiro			sm_syslog(LOG_NOTICE, CurEnv->e_id,
487564562Sgshapiro				  "ph_map_lookup: query %s=\"%s\" return email",
487664562Sgshapiro				  tmp2, fmtkey);
487764562Sgshapiro		if (tTd(38, 20))
487864562Sgshapiro			dprintf("ph_map_lookup: query %s=\"%s\" return email\n",
487964562Sgshapiro				tmp2, fmtkey);
488064562Sgshapiro
488164562Sgshapiro		j = 0;
488264562Sgshapiro
488364562Sgshapiro		if (fprintf(pmap->ph_to_server, "query %s=%s return email\n",
488464562Sgshapiro			    tmp2, fmtkey) < 0)
488564562Sgshapiro			message = "qi query command failed";
488664562Sgshapiro		else if (fflush(pmap->ph_to_server) < 0)
488764562Sgshapiro			message = "qi fflush failed";
488864562Sgshapiro		else if ((server_data = ReadQi(pmap->ph_from_server,
488964562Sgshapiro					       &j)) == NULL)
489064562Sgshapiro			message = "ReadQi() returned NULL";
489164562Sgshapiro
489264562Sgshapiro#if _FFR_PHMAP_TIMEOUT
489364562Sgshapiro		if ((hold_data[hold_data_idx] = server_data) != NULL)
489464562Sgshapiro		{
489564562Sgshapiro			/* save pointer for later free() */
489664562Sgshapiro			hold_data_idx++;
489764562Sgshapiro		}
489864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
489964562Sgshapiro
490064562Sgshapiro		if (server_data == NULL ||
490164562Sgshapiro		    (server_data->code >= 400 &&
490264562Sgshapiro		     server_data->code < 500))
490364562Sgshapiro		{
490464562Sgshapiro			/* temporary failure */
490564562Sgshapiro			*pstat = EX_TEMPFAIL;
490664562Sgshapiro#if _FFR_PHMAP_TIMEOUT
490764562Sgshapiro			break;
490864562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
490964562Sgshapiro			if (server_data != NULL)
491064562Sgshapiro			{
491164562Sgshapiro				FreeQIR(server_data);
491264562Sgshapiro				server_data = NULL;
491364562Sgshapiro			}
491464562Sgshapiro			return NULL;
491564562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
491664562Sgshapiro		}
491764562Sgshapiro
491864562Sgshapiro		/*
491964562Sgshapiro		**  if we found a single match, break out.
492064562Sgshapiro		**  otherwise, try the next field.
492164562Sgshapiro		*/
492264562Sgshapiro
492364562Sgshapiro		if (j == 1)
492464562Sgshapiro			break;
492564562Sgshapiro
492664562Sgshapiro		/*
492764562Sgshapiro		**  check for a single response which is an error:
492864562Sgshapiro		**  ReadQi() doesn't set j on error responses,
492964562Sgshapiro		**  but we should stop here instead of moving on if
493064562Sgshapiro		**  it happens (e.g., alias found but email field empty)
493164562Sgshapiro		*/
493264562Sgshapiro
493364562Sgshapiro		for (qirp = server_data;
493464562Sgshapiro		     qirp != NULL && qirp->code < 0;
493564562Sgshapiro		     qirp++)
493664562Sgshapiro		{
493764562Sgshapiro			if (tTd(38, 20))
493864562Sgshapiro				dprintf("ph_map_lookup: QIR: %d:%d:%d:%s\n",
493964562Sgshapiro					qirp->code, qirp->subcode, qirp->field,
494064562Sgshapiro					(qirp->message ? qirp->message
494164562Sgshapiro					 : "[NULL]"));
494264562Sgshapiro			if (qirp->code <= -500)
494364562Sgshapiro			{
494464562Sgshapiro				j = 0;
494564562Sgshapiro				goto ph_map_lookup_abort;
494664562Sgshapiro			}
494764562Sgshapiro		}
494864562Sgshapiro
494964562Sgshapiro#if _FFR_PHMAP_TIMEOUT
495064562Sgshapiro	} while (*tmp != '\0' && hold_data_idx < MAX_PH_FIELDS);
495164562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
495264562Sgshapiro	} while (*tmp != '\0');
495364562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
495464562Sgshapiro
495564562Sgshapiro  ph_map_lookup_abort:
495664562Sgshapiro#if _FFR_PHMAP_TIMEOUT
495764562Sgshapiro	if (ev != NULL)
495864562Sgshapiro		clrevent(ev);
495964562Sgshapiro
496064562Sgshapiro	/*
496164562Sgshapiro	**  Return EX_TEMPFAIL if the timer popped
496264562Sgshapiro	**  or we got a temporary PH error
496364562Sgshapiro	*/
496464562Sgshapiro
496564562Sgshapiro	if (*pstat == EX_TEMPFAIL)
496664562Sgshapiro		ph_map_safeclose(map);
496764562Sgshapiro
496864562Sgshapiro	/* if we didn't find a single match, bail out */
496964562Sgshapiro	if (*pstat == EX_OK && j != 1)
497064562Sgshapiro		*pstat = EX_UNAVAILABLE;
497164562Sgshapiro
497264562Sgshapiro	if (*pstat == EX_OK)
497364562Sgshapiro	{
497464562Sgshapiro		/*
497564562Sgshapiro		** skip leading whitespace and chop at first address
497664562Sgshapiro		*/
497764562Sgshapiro
497864562Sgshapiro		for (tmp = server_data->message;
497964562Sgshapiro		     isascii(*tmp) && isspace(*tmp);
498064562Sgshapiro		     tmp++)
498164562Sgshapiro			continue;
498264562Sgshapiro
498364562Sgshapiro		for (tmp2 = tmp; *tmp2 != '\0'; tmp2++)
498464562Sgshapiro		{
498564562Sgshapiro			if (isascii(*tmp2) && isspace(*tmp2))
498664562Sgshapiro			{
498764562Sgshapiro				*tmp2 = '\0';
498864562Sgshapiro				break;
498964562Sgshapiro			}
499064562Sgshapiro		}
499164562Sgshapiro
499264562Sgshapiro		if (tTd(38,20))
499364562Sgshapiro			dprintf("ph_map_lookup: %s => %s\n", key, tmp);
499464562Sgshapiro
499564562Sgshapiro		if (bitset(MF_MATCHONLY, map->map_mflags))
499664562Sgshapiro			message = map_rewrite(map, key, strlen(key), NULL);
499764562Sgshapiro		else
499864562Sgshapiro			message = map_rewrite(map, tmp, strlen(tmp), args);
499964562Sgshapiro	}
500064562Sgshapiro
500164562Sgshapiro	/*
500264562Sgshapiro	**  Deferred free() of returned server_data values
500364562Sgshapiro	**  the deferral is to avoid the risk of a free() being
500464562Sgshapiro	**  interrupted by the event timer.  By now the timeout event
500564562Sgshapiro	**  has been cleared and none of the data is still in use.
500664562Sgshapiro	*/
500764562Sgshapiro
500864562Sgshapiro	while (--hold_data_idx >= 0)
500964562Sgshapiro	{
501064562Sgshapiro		if (hold_data[hold_data_idx] != NULL)
501164562Sgshapiro			FreeQIR(hold_data[hold_data_idx]);
501264562Sgshapiro	}
501364562Sgshapiro
501464562Sgshapiro	if (*pstat == EX_OK)
501564562Sgshapiro		return message;
501664562Sgshapiro
501764562Sgshapiro	return NULL;
501864562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */
501964562Sgshapiro	/* if we didn't find a single match, bail out */
502064562Sgshapiro	if (j != 1)
502164562Sgshapiro	{
502264562Sgshapiro		*pstat = EX_UNAVAILABLE;
502364562Sgshapiro		if (server_data != NULL)
502464562Sgshapiro		{
502564562Sgshapiro			FreeQIR(server_data);
502664562Sgshapiro			server_data = NULL;
502764562Sgshapiro		}
502864562Sgshapiro		return NULL;
502964562Sgshapiro	}
503064562Sgshapiro
503164562Sgshapiro	/*
503264562Sgshapiro	** skip leading whitespace and chop at first address
503364562Sgshapiro	*/
503464562Sgshapiro
503564562Sgshapiro	for (tmp = server_data->message;
503664562Sgshapiro	     isascii(*tmp) && isspace(*tmp);
503764562Sgshapiro	     tmp++)
503864562Sgshapiro		continue;
503964562Sgshapiro
504064562Sgshapiro	for (tmp2 = tmp; *tmp2 != '\0'; tmp2++)
504164562Sgshapiro	{
504264562Sgshapiro		if (isascii(*tmp2) && isspace(*tmp2))
504364562Sgshapiro		{
504464562Sgshapiro			*tmp2 = '\0';
504564562Sgshapiro			break;
504664562Sgshapiro		}
504764562Sgshapiro	}
504864562Sgshapiro
504964562Sgshapiro	if (tTd(38,20))
505064562Sgshapiro		dprintf("ph_map_lookup: %s => %s\n", key, tmp);
505164562Sgshapiro
505264562Sgshapiro	if (bitset(MF_MATCHONLY, map->map_mflags))
505364562Sgshapiro		message = map_rewrite(map, key, strlen(key), NULL);
505464562Sgshapiro	else
505564562Sgshapiro		message = map_rewrite(map, tmp, strlen(tmp), args);
505664562Sgshapiro	if (server_data != NULL)
505764562Sgshapiro	{
505864562Sgshapiro		FreeQIR(server_data);
505964562Sgshapiro		server_data = NULL;
506064562Sgshapiro	}
506164562Sgshapiro	return message;
506264562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */
506364562Sgshapiro}
506464562Sgshapiro#endif /* PH_MAP */
506564562Sgshapiro/*
506642575Speter**  syslog map
506738032Speter*/
506838032Speter
506938032Speter#define map_prio	map_lockfd	/* overload field */
507038032Speter
507138032Speter/*
507242575Speter**  SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
507338032Speter*/
507438032Speter
507538032Speterbool
507638032Spetersyslog_map_parseargs(map, args)
507738032Speter	MAP *map;
507838032Speter	char *args;
507938032Speter{
508038032Speter	char *p = args;
508138032Speter	char *priority = NULL;
508238032Speter
508364562Sgshapiro	/* there is no check whether there is really an argument */
508464562Sgshapiro	while (*p != '\0')
508538032Speter	{
508638032Speter		while (isascii(*p) && isspace(*p))
508738032Speter			p++;
508838032Speter		if (*p != '-')
508938032Speter			break;
509064562Sgshapiro		++p;
509164562Sgshapiro		if (*p == 'D')
509264562Sgshapiro		{
509364562Sgshapiro			map->map_mflags |= MF_DEFER;
509464562Sgshapiro			++p;
509564562Sgshapiro		}
509664562Sgshapiro		else if (*p == 'S')
509764562Sgshapiro		{
509864562Sgshapiro			map->map_spacesub = *++p;
509964562Sgshapiro			if (*p != '\0')
510064562Sgshapiro				p++;
510164562Sgshapiro		}
510264562Sgshapiro		else if (*p == 'L')
510364562Sgshapiro		{
510464562Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p))
510564562Sgshapiro				continue;
510664562Sgshapiro			if (*p == '\0')
510764562Sgshapiro				break;
510864562Sgshapiro			priority = p;
510964562Sgshapiro			while (*p != '\0' && !(isascii(*p) && isspace(*p)))
511064562Sgshapiro				p++;
511164562Sgshapiro			if (*p != '\0')
511264562Sgshapiro				*p++ = '\0';
511364562Sgshapiro		}
511464562Sgshapiro		else
511564562Sgshapiro		{
511664562Sgshapiro			syserr("Illegal option %c map syslog", *p);
511764562Sgshapiro			++p;
511864562Sgshapiro		}
511938032Speter	}
512038032Speter
512138032Speter	if (priority == NULL)
512238032Speter		map->map_prio = LOG_INFO;
512338032Speter	else
512438032Speter	{
512538032Speter		if (strncasecmp("LOG_", priority, 4) == 0)
512638032Speter			priority += 4;
512738032Speter
512838032Speter#ifdef LOG_EMERG
512938032Speter		if (strcasecmp("EMERG", priority) == 0)
513038032Speter			map->map_prio = LOG_EMERG;
513138032Speter		else
513264562Sgshapiro#endif /* LOG_EMERG */
513338032Speter#ifdef LOG_ALERT
513438032Speter		if (strcasecmp("ALERT", priority) == 0)
513538032Speter			map->map_prio = LOG_ALERT;
513638032Speter		else
513764562Sgshapiro#endif /* LOG_ALERT */
513838032Speter#ifdef LOG_CRIT
513938032Speter		if (strcasecmp("CRIT", priority) == 0)
514038032Speter			map->map_prio = LOG_CRIT;
514138032Speter		else
514264562Sgshapiro#endif /* LOG_CRIT */
514338032Speter#ifdef LOG_ERR
514438032Speter		if (strcasecmp("ERR", priority) == 0)
514538032Speter			map->map_prio = LOG_ERR;
514638032Speter		else
514764562Sgshapiro#endif /* LOG_ERR */
514838032Speter#ifdef LOG_WARNING
514938032Speter		if (strcasecmp("WARNING", priority) == 0)
515038032Speter			map->map_prio = LOG_WARNING;
515138032Speter		else
515264562Sgshapiro#endif /* LOG_WARNING */
515338032Speter#ifdef LOG_NOTICE
515438032Speter		if (strcasecmp("NOTICE", priority) == 0)
515538032Speter			map->map_prio = LOG_NOTICE;
515638032Speter		else
515764562Sgshapiro#endif /* LOG_NOTICE */
515838032Speter#ifdef LOG_INFO
515938032Speter		if (strcasecmp("INFO", priority) == 0)
516038032Speter			map->map_prio = LOG_INFO;
516138032Speter		else
516264562Sgshapiro#endif /* LOG_INFO */
516338032Speter#ifdef LOG_DEBUG
516438032Speter		if (strcasecmp("DEBUG", priority) == 0)
516538032Speter			map->map_prio = LOG_DEBUG;
516638032Speter		else
516764562Sgshapiro#endif /* LOG_DEBUG */
516838032Speter		{
516938032Speter			syserr("syslog_map_parseargs: Unknown priority %s\n",
517038032Speter			       priority);
517138032Speter			return FALSE;
517238032Speter		}
517338032Speter	}
517438032Speter	return TRUE;
517538032Speter}
517638032Speter
517738032Speter/*
517842575Speter**  SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
517938032Speter*/
518038032Speter
518138032Speterchar *
518238032Spetersyslog_map_lookup(map, string, args, statp)
518338032Speter	MAP *map;
518438032Speter	char *string;
518538032Speter	char **args;
518638032Speter	int *statp;
518738032Speter{
518838032Speter	char *ptr = map_rewrite(map, string, strlen(string), args);
518938032Speter
519038032Speter	if (ptr != NULL)
519138032Speter	{
519238032Speter		if (tTd(38, 20))
519364562Sgshapiro			dprintf("syslog_map_lookup(%s (priority %d): %s\n",
519464562Sgshapiro				map->map_mname, map->map_prio, ptr);
519538032Speter
519638032Speter		sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
519738032Speter	}
519838032Speter
519938032Speter	*statp = EX_OK;
520038032Speter	return "";
520138032Speter}
520238032Speter
520338032Speter/*
520438032Speter**  HESIOD Modules
520538032Speter*/
520638032Speter
520738032Speter#ifdef HESIOD
520838032Speter
520938032Speterbool
521038032Speterhes_map_open(map, mode)
521138032Speter	MAP *map;
521238032Speter	int mode;
521338032Speter{
521438032Speter	if (tTd(38, 2))
521564562Sgshapiro		dprintf("hes_map_open(%s, %s, %d)\n",
521638032Speter			map->map_mname, map->map_file, mode);
521738032Speter
521838032Speter	if (mode != O_RDONLY)
521938032Speter	{
522038032Speter		/* issue a pseudo-error message */
522164562Sgshapiro# ifdef ENOSYS
522238032Speter		errno = ENOSYS;
522364562Sgshapiro# else /* ENOSYS */
522464562Sgshapiro#  ifdef EFTYPE
522538032Speter		errno = EFTYPE;
522664562Sgshapiro#  else /* EFTYPE */
522738032Speter		errno = ENXIO;
522864562Sgshapiro#  endif /* EFTYPE */
522964562Sgshapiro# endif /* ENOSYS */
523038032Speter		return FALSE;
523138032Speter	}
523238032Speter
523364562Sgshapiro# ifdef HESIOD_INIT
523438032Speter	if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
523538032Speter		return TRUE;
523638032Speter
523738032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
523864562Sgshapiro		syserr("421 4.0.0 cannot initialize Hesiod map (%s)",
523938032Speter			errstring(errno));
524038032Speter	return FALSE;
524164562Sgshapiro# else /* HESIOD_INIT */
524238032Speter	if (hes_error() == HES_ER_UNINIT)
524338032Speter		hes_init();
524438032Speter	switch (hes_error())
524538032Speter	{
524638032Speter	  case HES_ER_OK:
524738032Speter	  case HES_ER_NOTFOUND:
524838032Speter		return TRUE;
524938032Speter	}
525038032Speter
525138032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
525264562Sgshapiro		syserr("421 4.0.0 cannot initialize Hesiod map (%d)", hes_error());
525338032Speter
525438032Speter	return FALSE;
525564562Sgshapiro# endif /* HESIOD_INIT */
525638032Speter}
525738032Speter
525838032Speterchar *
525938032Speterhes_map_lookup(map, name, av, statp)
526038032Speter	MAP *map;
526138032Speter	char *name;
526238032Speter	char **av;
526338032Speter	int *statp;
526438032Speter{
526538032Speter	char **hp;
526638032Speter
526738032Speter	if (tTd(38, 20))
526864562Sgshapiro		dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
526938032Speter
527038032Speter	if (name[0] == '\\')
527138032Speter	{
527238032Speter		char *np;
527338032Speter		int nl;
527438032Speter		char nbuf[MAXNAME];
527538032Speter
527638032Speter		nl = strlen(name);
527738032Speter		if (nl < sizeof nbuf - 1)
527838032Speter			np = nbuf;
527938032Speter		else
528038032Speter			np = xalloc(strlen(name) + 2);
528138032Speter		np[0] = '\\';
528264562Sgshapiro		(void) strlcpy(&np[1], name, (sizeof nbuf) - 1);
528364562Sgshapiro# ifdef HESIOD_INIT
528438032Speter		hp = hesiod_resolve(HesiodContext, np, map->map_file);
528564562Sgshapiro# else /* HESIOD_INIT */
528638032Speter		hp = hes_resolve(np, map->map_file);
528764562Sgshapiro# endif /* HESIOD_INIT */
528838032Speter		if (np != nbuf)
528938032Speter			free(np);
529038032Speter	}
529138032Speter	else
529238032Speter	{
529364562Sgshapiro# ifdef HESIOD_INIT
529438032Speter		hp = hesiod_resolve(HesiodContext, name, map->map_file);
529564562Sgshapiro# else /* HESIOD_INIT */
529638032Speter		hp = hes_resolve(name, map->map_file);
529764562Sgshapiro# endif /* HESIOD_INIT */
529838032Speter	}
529964562Sgshapiro# ifdef HESIOD_INIT
530038032Speter	if (hp == NULL)
530138032Speter		return NULL;
530238032Speter	if (*hp == NULL)
530338032Speter	{
530438032Speter		hesiod_free_list(HesiodContext, hp);
530538032Speter		switch (errno)
530638032Speter		{
530738032Speter		  case ENOENT:
530838032Speter			  *statp = EX_NOTFOUND;
530938032Speter			  break;
531038032Speter		  case ECONNREFUSED:
531138032Speter		  case EMSGSIZE:
531238032Speter			  *statp = EX_TEMPFAIL;
531338032Speter			  break;
531438032Speter		  case ENOMEM:
531538032Speter		  default:
531638032Speter			  *statp = EX_UNAVAILABLE;
531738032Speter			  break;
531838032Speter		}
531938032Speter		return NULL;
532038032Speter	}
532164562Sgshapiro# else /* HESIOD_INIT */
532238032Speter	if (hp == NULL || hp[0] == NULL)
532338032Speter	{
532438032Speter		switch (hes_error())
532538032Speter		{
532638032Speter		  case HES_ER_OK:
532738032Speter			*statp = EX_OK;
532838032Speter			break;
532938032Speter
533038032Speter		  case HES_ER_NOTFOUND:
533138032Speter			*statp = EX_NOTFOUND;
533238032Speter			break;
533338032Speter
533438032Speter		  case HES_ER_CONFIG:
533538032Speter			*statp = EX_UNAVAILABLE;
533638032Speter			break;
533738032Speter
533838032Speter		  case HES_ER_NET:
533938032Speter			*statp = EX_TEMPFAIL;
534038032Speter			break;
534138032Speter		}
534238032Speter		return NULL;
534338032Speter	}
534464562Sgshapiro# endif /* HESIOD_INIT */
534538032Speter
534638032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
534738032Speter		return map_rewrite(map, name, strlen(name), NULL);
534838032Speter	else
534938032Speter		return map_rewrite(map, hp[0], strlen(hp[0]), av);
535038032Speter}
535138032Speter
535264562Sgshapiro#endif /* HESIOD */
535338032Speter/*
535438032Speter**  NeXT NETINFO Modules
535538032Speter*/
535638032Speter
535738032Speter#if NETINFO
535838032Speter
535938032Speter# define NETINFO_DEFAULT_DIR		"/aliases"
536038032Speter# define NETINFO_DEFAULT_PROPERTY	"members"
536138032Speter
536238032Speter/*
536338032Speter**  NI_MAP_OPEN -- open NetInfo Aliases
536438032Speter*/
536538032Speter
536638032Speterbool
536738032Speterni_map_open(map, mode)
536838032Speter	MAP *map;
536938032Speter	int mode;
537038032Speter{
537138032Speter	if (tTd(38, 2))
537264562Sgshapiro		dprintf("ni_map_open(%s, %s, %d)\n",
537338032Speter			map->map_mname, map->map_file, mode);
537438032Speter	mode &= O_ACCMODE;
537538032Speter
537638032Speter	if (*map->map_file == '\0')
537738032Speter		map->map_file = NETINFO_DEFAULT_DIR;
537838032Speter
537938032Speter	if (map->map_valcolnm == NULL)
538038032Speter		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
538138032Speter
538238032Speter	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
538338032Speter		map->map_coldelim = ',';
538438032Speter
538538032Speter	return TRUE;
538638032Speter}
538738032Speter
538838032Speter
538938032Speter/*
539038032Speter**  NI_MAP_LOOKUP -- look up a datum in NetInfo
539138032Speter*/
539238032Speter
539338032Speterchar *
539438032Speterni_map_lookup(map, name, av, statp)
539538032Speter	MAP *map;
539638032Speter	char *name;
539738032Speter	char **av;
539838032Speter	int *statp;
539938032Speter{
540038032Speter	char *res;
540138032Speter	char *propval;
540238032Speter
540338032Speter	if (tTd(38, 20))
540464562Sgshapiro		dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
540538032Speter
540638032Speter	propval = ni_propval(map->map_file, map->map_keycolnm, name,
540738032Speter			     map->map_valcolnm, map->map_coldelim);
540838032Speter
540938032Speter	if (propval == NULL)
541038032Speter		return NULL;
541138032Speter
541238032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
541338032Speter		res = map_rewrite(map, name, strlen(name), NULL);
541438032Speter	else
541538032Speter		res = map_rewrite(map, propval, strlen(propval), av);
541638032Speter	free(propval);
541738032Speter	return res;
541838032Speter}
541938032Speter
542038032Speter
542164562Sgshapirostatic bool
542238032Speterni_getcanonname(name, hbsize, statp)
542338032Speter	char *name;
542438032Speter	int hbsize;
542538032Speter	int *statp;
542638032Speter{
542738032Speter	char *vptr;
542838032Speter	char *ptr;
542938032Speter	char nbuf[MAXNAME + 1];
543038032Speter
543138032Speter	if (tTd(38, 20))
543264562Sgshapiro		dprintf("ni_getcanonname(%s)\n", name);
543338032Speter
543464562Sgshapiro	if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
543538032Speter	{
543638032Speter		*statp = EX_UNAVAILABLE;
543738032Speter		return FALSE;
543838032Speter	}
543973188Sgshapiro	(void) shorten_hostname(nbuf);
544038032Speter
544138032Speter	/* we only accept single token search key */
544238032Speter	if (strchr(nbuf, '.'))
544338032Speter	{
544438032Speter		*statp = EX_NOHOST;
544538032Speter		return FALSE;
544638032Speter	}
544738032Speter
544838032Speter	/* Do the search */
544938032Speter	vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
545038032Speter
545138032Speter	if (vptr == NULL)
545238032Speter	{
545338032Speter		*statp = EX_NOHOST;
545438032Speter		return FALSE;
545538032Speter	}
545638032Speter
545738032Speter	/* Only want the first machine name */
545838032Speter	if ((ptr = strchr(vptr, '\n')) != NULL)
545938032Speter		*ptr = '\0';
546038032Speter
546138032Speter	if (hbsize >= strlen(vptr))
546238032Speter	{
546364562Sgshapiro		(void) strlcpy(name, vptr, hbsize);
546464562Sgshapiro		free(vptr);
546538032Speter		*statp = EX_OK;
546638032Speter		return TRUE;
546738032Speter	}
546838032Speter	*statp = EX_UNAVAILABLE;
546938032Speter	free(vptr);
547038032Speter	return FALSE;
547138032Speter}
547238032Speter
547338032Speter
547438032Speter/*
547538032Speter**  NI_PROPVAL -- NetInfo property value lookup routine
547638032Speter**
547738032Speter**	Parameters:
547838032Speter**		keydir -- the NetInfo directory name in which to search
547938032Speter**			for the key.
548038032Speter**		keyprop -- the name of the property in which to find the
548138032Speter**			property we are interested.  Defaults to "name".
548238032Speter**		keyval -- the value for which we are really searching.
548338032Speter**		valprop -- the property name for the value in which we
548438032Speter**			are interested.
548538032Speter**		sepchar -- if non-nil, this can be multiple-valued, and
548638032Speter**			we should return a string separated by this
548738032Speter**			character.
548838032Speter**
548938032Speter**	Returns:
549038032Speter**		NULL -- if:
549138032Speter**			1. the directory is not found
549238032Speter**			2. the property name is not found
549338032Speter**			3. the property contains multiple values
549464562Sgshapiro**			4. some error occurred
549538032Speter**		else -- the value of the lookup.
549638032Speter**
549738032Speter**	Example:
549838032Speter**		To search for an alias value, use:
549938032Speter**		  ni_propval("/aliases", "name", aliasname, "members", ',')
550038032Speter**
550138032Speter**	Notes:
550264562Sgshapiro**		Caller should free the return value of ni_proval
550338032Speter*/
550438032Speter
550538032Speter# include <netinfo/ni.h>
550638032Speter
550764562Sgshapiro# define LOCAL_NETINFO_DOMAIN	"."
550864562Sgshapiro# define PARENT_NETINFO_DOMAIN	".."
550964562Sgshapiro# define MAX_NI_LEVELS		256
551038032Speter
551138032Speterchar *
551238032Speterni_propval(keydir, keyprop, keyval, valprop, sepchar)
551338032Speter	char *keydir;
551438032Speter	char *keyprop;
551538032Speter	char *keyval;
551638032Speter	char *valprop;
551738032Speter	int sepchar;
551838032Speter{
551938032Speter	char *propval = NULL;
552038032Speter	int i;
552164562Sgshapiro	int j, alen, l;
552238032Speter	void *ni = NULL;
552338032Speter	void *lastni = NULL;
552438032Speter	ni_status nis;
552538032Speter	ni_id nid;
552638032Speter	ni_namelist ninl;
552738032Speter	register char *p;
552838032Speter	char keybuf[1024];
552938032Speter
553038032Speter	/*
553138032Speter	**  Create the full key from the two parts.
553238032Speter	**
553338032Speter	**	Note that directory can end with, e.g., "name=" to specify
553438032Speter	**	an alternate search property.
553538032Speter	*/
553638032Speter
553738032Speter	i = strlen(keydir) + strlen(keyval) + 2;
553838032Speter	if (keyprop != NULL)
553938032Speter		i += strlen(keyprop) + 1;
554064562Sgshapiro	if (i >= sizeof keybuf)
554138032Speter		return NULL;
554264562Sgshapiro	(void) strlcpy(keybuf, keydir, sizeof keybuf);
554364562Sgshapiro	(void) strlcat(keybuf, "/", sizeof keybuf);
554438032Speter	if (keyprop != NULL)
554538032Speter	{
554664562Sgshapiro		(void) strlcat(keybuf, keyprop, sizeof keybuf);
554764562Sgshapiro		(void) strlcat(keybuf, "=", sizeof keybuf);
554838032Speter	}
554964562Sgshapiro	(void) strlcat(keybuf, keyval, sizeof keybuf);
555038032Speter
555138032Speter	if (tTd(38, 21))
555264562Sgshapiro		dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
555338032Speter			keydir, keyprop, keyval, valprop, sepchar, keybuf);
555438032Speter	/*
555538032Speter	**  If the passed directory and property name are found
555638032Speter	**  in one of netinfo domains we need to search (starting
555738032Speter	**  from the local domain moving all the way back to the
555838032Speter	**  root domain) set propval to the property's value
555938032Speter	**  and return it.
556038032Speter	*/
556138032Speter
556238032Speter	for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
556338032Speter	{
556438032Speter		if (i == 0)
556538032Speter		{
556638032Speter			nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
556738032Speter			if (tTd(38, 20))
556864562Sgshapiro				dprintf("ni_open(LOCAL) = %d\n", nis);
556938032Speter		}
557038032Speter		else
557138032Speter		{
557238032Speter			if (lastni != NULL)
557338032Speter				ni_free(lastni);
557438032Speter			lastni = ni;
557538032Speter			nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
557638032Speter			if (tTd(38, 20))
557764562Sgshapiro				dprintf("ni_open(PARENT) = %d\n", nis);
557838032Speter		}
557938032Speter
558038032Speter		/*
558138032Speter		**  Don't bother if we didn't get a handle on a
558238032Speter		**  proper domain.  This is not necessarily an error.
558338032Speter		**  We would get a positive ni_status if, for instance
558438032Speter		**  we never found the directory or property and tried
558538032Speter		**  to open the parent of the root domain!
558638032Speter		*/
558738032Speter
558838032Speter		if (nis != 0)
558938032Speter			break;
559038032Speter
559138032Speter		/*
559238032Speter		**  Find the path to the server information.
559338032Speter		*/
559438032Speter
559538032Speter		if (ni_pathsearch(ni, &nid, keybuf) != 0)
559638032Speter			continue;
559738032Speter
559838032Speter		/*
559938032Speter		**  Find associated value information.
560038032Speter		*/
560138032Speter
560238032Speter		if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
560338032Speter			continue;
560438032Speter
560538032Speter		if (tTd(38, 20))
560664562Sgshapiro			dprintf("ni_lookupprop: len=%d\n",
560764562Sgshapiro				ninl.ni_namelist_len);
560864562Sgshapiro
560938032Speter		/*
561038032Speter		**  See if we have an acceptable number of values.
561138032Speter		*/
561238032Speter
561338032Speter		if (ninl.ni_namelist_len <= 0)
561438032Speter			continue;
561538032Speter
561638032Speter		if (sepchar == '\0' && ninl.ni_namelist_len > 1)
561738032Speter		{
561838032Speter			ni_namelist_free(&ninl);
561938032Speter			continue;
562038032Speter		}
562138032Speter
562238032Speter		/*
562338032Speter		**  Calculate number of bytes needed and build result
562438032Speter		*/
562538032Speter
562638032Speter		alen = 1;
562738032Speter		for (j = 0; j < ninl.ni_namelist_len; j++)
562838032Speter			alen += strlen(ninl.ni_namelist_val[j]) + 1;
562938032Speter		propval = p = xalloc(alen);
563038032Speter		for (j = 0; j < ninl.ni_namelist_len; j++)
563138032Speter		{
563264562Sgshapiro			(void) strlcpy(p, ninl.ni_namelist_val[j], alen);
563364562Sgshapiro			l = strlen(p);
563464562Sgshapiro			p += l;
563538032Speter			*p++ = sepchar;
563664562Sgshapiro			alen -= l + 1;
563738032Speter		}
563838032Speter		*--p = '\0';
563938032Speter
564038032Speter		ni_namelist_free(&ninl);
564138032Speter	}
564238032Speter
564338032Speter	/*
564438032Speter	**  Clean up.
564538032Speter	*/
564638032Speter
564738032Speter	if (ni != NULL)
564838032Speter		ni_free(ni);
564938032Speter	if (lastni != NULL && ni != lastni)
565038032Speter		ni_free(lastni);
565138032Speter	if (tTd(38, 20))
565264562Sgshapiro		dprintf("ni_propval returns: '%s'\n", propval);
565338032Speter
565438032Speter	return propval;
565538032Speter}
565638032Speter
565742575Speter#endif /* NETINFO */
565838032Speter/*
565938032Speter**  TEXT (unindexed text file) Modules
566038032Speter**
566138032Speter**	This code donated by Sun Microsystems.
566238032Speter*/
566338032Speter
566438032Speter#define map_sff		map_lockfd	/* overload field */
566538032Speter
566638032Speter
566738032Speter/*
566838032Speter**  TEXT_MAP_OPEN -- open text table
566938032Speter*/
567038032Speter
567138032Speterbool
567238032Spetertext_map_open(map, mode)
567338032Speter	MAP *map;
567438032Speter	int mode;
567538032Speter{
567664562Sgshapiro	long sff;
567738032Speter	int i;
567838032Speter
567938032Speter	if (tTd(38, 2))
568064562Sgshapiro		dprintf("text_map_open(%s, %s, %d)\n",
568138032Speter			map->map_mname, map->map_file, mode);
568238032Speter
568338032Speter	mode &= O_ACCMODE;
568438032Speter	if (mode != O_RDONLY)
568538032Speter	{
568638032Speter		errno = EPERM;
568738032Speter		return FALSE;
568838032Speter	}
568938032Speter
569038032Speter	if (*map->map_file == '\0')
569138032Speter	{
569238032Speter		syserr("text map \"%s\": file name required",
569338032Speter			map->map_mname);
569438032Speter		return FALSE;
569538032Speter	}
569638032Speter
569738032Speter	if (map->map_file[0] != '/')
569838032Speter	{
569938032Speter		syserr("text map \"%s\": file name must be fully qualified",
570038032Speter			map->map_mname);
570138032Speter		return FALSE;
570238032Speter	}
570338032Speter
570438032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
570564562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
570638032Speter		sff |= SFF_NOWLINK;
570764562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
570838032Speter		sff |= SFF_SAFEDIRPATH;
570938032Speter	if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
571038032Speter			  sff, S_IRUSR, NULL)) != 0)
571138032Speter	{
571264562Sgshapiro		int save_errno = errno;
571364562Sgshapiro
571438032Speter		/* cannot open this map */
571538032Speter		if (tTd(38, 2))
571664562Sgshapiro			dprintf("\tunsafe map file: %d\n", i);
571764562Sgshapiro		errno = save_errno;
571838032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
571938032Speter			syserr("text map \"%s\": unsafe map file %s",
572038032Speter				map->map_mname, map->map_file);
572138032Speter		return FALSE;
572238032Speter	}
572338032Speter
572438032Speter	if (map->map_keycolnm == NULL)
572538032Speter		map->map_keycolno = 0;
572638032Speter	else
572738032Speter	{
572838032Speter		if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
572938032Speter		{
573038032Speter			syserr("text map \"%s\", file %s: -k should specify a number, not %s",
573138032Speter				map->map_mname, map->map_file,
573238032Speter				map->map_keycolnm);
573338032Speter			return FALSE;
573438032Speter		}
573538032Speter		map->map_keycolno = atoi(map->map_keycolnm);
573638032Speter	}
573738032Speter
573838032Speter	if (map->map_valcolnm == NULL)
573938032Speter		map->map_valcolno = 0;
574038032Speter	else
574138032Speter	{
574238032Speter		if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
574338032Speter		{
574438032Speter			syserr("text map \"%s\", file %s: -v should specify a number, not %s",
574538032Speter					map->map_mname, map->map_file,
574638032Speter					map->map_valcolnm);
574738032Speter			return FALSE;
574838032Speter		}
574938032Speter		map->map_valcolno = atoi(map->map_valcolnm);
575038032Speter	}
575138032Speter
575238032Speter	if (tTd(38, 2))
575338032Speter	{
575464562Sgshapiro		dprintf("text_map_open(%s, %s): delimiter = ",
575538032Speter			map->map_mname, map->map_file);
575638032Speter		if (map->map_coldelim == '\0')
575764562Sgshapiro			dprintf("(white space)\n");
575838032Speter		else
575964562Sgshapiro			dprintf("%c\n", map->map_coldelim);
576038032Speter	}
576138032Speter
576238032Speter	map->map_sff = sff;
576338032Speter	return TRUE;
576438032Speter}
576538032Speter
576638032Speter
576738032Speter/*
576838032Speter**  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
576938032Speter*/
577038032Speter
577138032Speterchar *
577238032Spetertext_map_lookup(map, name, av, statp)
577338032Speter	MAP *map;
577438032Speter	char *name;
577538032Speter	char **av;
577638032Speter	int *statp;
577738032Speter{
577838032Speter	char *vp;
577938032Speter	auto int vsize;
578038032Speter	int buflen;
578138032Speter	FILE *f;
578238032Speter	char delim;
578338032Speter	int key_idx;
578438032Speter	bool found_it;
578564562Sgshapiro	long sff = map->map_sff;
578638032Speter	char search_key[MAXNAME + 1];
578738032Speter	char linebuf[MAXLINE];
578838032Speter	char buf[MAXNAME + 1];
578938032Speter
579038032Speter	found_it = FALSE;
579138032Speter	if (tTd(38, 20))
579264562Sgshapiro		dprintf("text_map_lookup(%s, %s)\n", map->map_mname,  name);
579338032Speter
579438032Speter	buflen = strlen(name);
579538032Speter	if (buflen > sizeof search_key - 1)
579638032Speter		buflen = sizeof search_key - 1;
579764562Sgshapiro	memmove(search_key, name, buflen);
579838032Speter	search_key[buflen] = '\0';
579938032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
580038032Speter		makelower(search_key);
580138032Speter
580238032Speter	f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
580338032Speter	if (f == NULL)
580438032Speter	{
580538032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
580638032Speter		*statp = EX_UNAVAILABLE;
580738032Speter		return NULL;
580838032Speter	}
580938032Speter	key_idx = map->map_keycolno;
581038032Speter	delim = map->map_coldelim;
581138032Speter	while (fgets(linebuf, MAXLINE, f) != NULL)
581238032Speter	{
581338032Speter		char *p;
581438032Speter
581538032Speter		/* skip comment line */
581638032Speter		if (linebuf[0] == '#')
581738032Speter			continue;
581838032Speter		p = strchr(linebuf, '\n');
581938032Speter		if (p != NULL)
582038032Speter			*p = '\0';
582138032Speter		p = get_column(linebuf, key_idx, delim, buf, sizeof buf);
582238032Speter		if (p != NULL && strcasecmp(search_key, p) == 0)
582338032Speter		{
582438032Speter			found_it = TRUE;
582538032Speter			break;
582638032Speter		}
582738032Speter	}
582864562Sgshapiro	(void) fclose(f);
582938032Speter	if (!found_it)
583038032Speter	{
583138032Speter		*statp = EX_NOTFOUND;
583238032Speter		return NULL;
583338032Speter	}
583438032Speter	vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof buf);
583542575Speter	if (vp == NULL)
583642575Speter	{
583742575Speter		*statp = EX_NOTFOUND;
583842575Speter		return NULL;
583942575Speter	}
584038032Speter	vsize = strlen(vp);
584138032Speter	*statp = EX_OK;
584238032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
584338032Speter		return map_rewrite(map, name, strlen(name), NULL);
584438032Speter	else
584538032Speter		return map_rewrite(map, vp, vsize, av);
584638032Speter}
584738032Speter
584838032Speter/*
584938032Speter**  TEXT_GETCANONNAME -- look up canonical name in hosts file
585038032Speter*/
585138032Speter
585264562Sgshapirostatic bool
585338032Spetertext_getcanonname(name, hbsize, statp)
585438032Speter	char *name;
585538032Speter	int hbsize;
585638032Speter	int *statp;
585738032Speter{
585838032Speter	bool found;
585973188Sgshapiro	char *dot;
586038032Speter	FILE *f;
586138032Speter	char linebuf[MAXLINE];
586238032Speter	char cbuf[MAXNAME + 1];
586338032Speter	char nbuf[MAXNAME + 1];
586438032Speter
586538032Speter	if (tTd(38, 20))
586664562Sgshapiro		dprintf("text_getcanonname(%s)\n", name);
586738032Speter
586838032Speter	if (strlen(name) >= (SIZE_T) sizeof nbuf)
586938032Speter	{
587038032Speter		*statp = EX_UNAVAILABLE;
587138032Speter		return FALSE;
587238032Speter	}
587364562Sgshapiro	(void) strlcpy(nbuf, name, sizeof nbuf);
587473188Sgshapiro	dot = shorten_hostname(nbuf);
587538032Speter
587638032Speter	f = fopen(HostsFile, "r");
587738032Speter	if (f == NULL)
587838032Speter	{
587938032Speter		*statp = EX_UNAVAILABLE;
588038032Speter		return FALSE;
588138032Speter	}
588238032Speter	found = FALSE;
588338032Speter	while (!found && fgets(linebuf, MAXLINE, f) != NULL)
588438032Speter	{
588538032Speter		char *p = strpbrk(linebuf, "#\n");
588638032Speter
588738032Speter		if (p != NULL)
588838032Speter			*p = '\0';
588938032Speter		if (linebuf[0] != '\0')
589073188Sgshapiro			found = extract_canonname(nbuf, dot, linebuf,
589173188Sgshapiro						  cbuf, sizeof cbuf);
589238032Speter	}
589364562Sgshapiro	(void) fclose(f);
589438032Speter	if (!found)
589538032Speter	{
589638032Speter		*statp = EX_NOHOST;
589738032Speter		return FALSE;
589838032Speter	}
589938032Speter
590038032Speter	if ((SIZE_T) hbsize >= strlen(cbuf))
590138032Speter	{
590264562Sgshapiro		(void) strlcpy(name, cbuf, hbsize);
590338032Speter		*statp = EX_OK;
590438032Speter		return TRUE;
590538032Speter	}
590638032Speter	*statp = EX_UNAVAILABLE;
590738032Speter	return FALSE;
590838032Speter}
590938032Speter/*
591038032Speter**  STAB (Symbol Table) Modules
591138032Speter*/
591238032Speter
591338032Speter
591438032Speter/*
591538032Speter**  STAB_MAP_LOOKUP -- look up alias in symbol table
591638032Speter*/
591738032Speter
591838032Speter/* ARGSUSED2 */
591938032Speterchar *
592038032Speterstab_map_lookup(map, name, av, pstat)
592138032Speter	register MAP *map;
592238032Speter	char *name;
592338032Speter	char **av;
592438032Speter	int *pstat;
592538032Speter{
592638032Speter	register STAB *s;
592738032Speter
592838032Speter	if (tTd(38, 20))
592964562Sgshapiro		dprintf("stab_lookup(%s, %s)\n",
593038032Speter			map->map_mname, name);
593138032Speter
593238032Speter	s = stab(name, ST_ALIAS, ST_FIND);
593338032Speter	if (s != NULL)
593464562Sgshapiro		return s->s_alias;
593564562Sgshapiro	return NULL;
593638032Speter}
593738032Speter
593838032Speter
593938032Speter/*
594038032Speter**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
594138032Speter*/
594238032Speter
594338032Spetervoid
594438032Speterstab_map_store(map, lhs, rhs)
594538032Speter	register MAP *map;
594638032Speter	char *lhs;
594738032Speter	char *rhs;
594838032Speter{
594938032Speter	register STAB *s;
595038032Speter
595138032Speter	s = stab(lhs, ST_ALIAS, ST_ENTER);
595238032Speter	s->s_alias = newstr(rhs);
595338032Speter}
595438032Speter
595538032Speter
595638032Speter/*
595738032Speter**  STAB_MAP_OPEN -- initialize (reads data file)
595838032Speter**
595938032Speter**	This is a wierd case -- it is only intended as a fallback for
596038032Speter**	aliases.  For this reason, opens for write (only during a
596138032Speter**	"newaliases") always fails, and opens for read open the
596238032Speter**	actual underlying text file instead of the database.
596338032Speter*/
596438032Speter
596538032Speterbool
596638032Speterstab_map_open(map, mode)
596738032Speter	register MAP *map;
596838032Speter	int mode;
596938032Speter{
597038032Speter	FILE *af;
597164562Sgshapiro	long sff;
597238032Speter	struct stat st;
597338032Speter
597438032Speter	if (tTd(38, 2))
597564562Sgshapiro		dprintf("stab_map_open(%s, %s, %d)\n",
597638032Speter			map->map_mname, map->map_file, mode);
597738032Speter
597838032Speter	mode &= O_ACCMODE;
597938032Speter	if (mode != O_RDONLY)
598038032Speter	{
598138032Speter		errno = EPERM;
598238032Speter		return FALSE;
598338032Speter	}
598438032Speter
598538032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
598664562Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
598738032Speter		sff |= SFF_NOWLINK;
598864562Sgshapiro	if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
598938032Speter		sff |= SFF_SAFEDIRPATH;
599038032Speter	af = safefopen(map->map_file, O_RDONLY, 0444, sff);
599138032Speter	if (af == NULL)
599238032Speter		return FALSE;
599338032Speter	readaliases(map, af, FALSE, FALSE);
599438032Speter
599538032Speter	if (fstat(fileno(af), &st) >= 0)
599638032Speter		map->map_mtime = st.st_mtime;
599764562Sgshapiro	(void) fclose(af);
599838032Speter
599938032Speter	return TRUE;
600038032Speter}
600138032Speter/*
600238032Speter**  Implicit Modules
600338032Speter**
600438032Speter**	Tries several types.  For back compatibility of aliases.
600538032Speter*/
600638032Speter
600738032Speter
600838032Speter/*
600938032Speter**  IMPL_MAP_LOOKUP -- lookup in best open database
601038032Speter*/
601138032Speter
601238032Speterchar *
601338032Speterimpl_map_lookup(map, name, av, pstat)
601438032Speter	MAP *map;
601538032Speter	char *name;
601638032Speter	char **av;
601738032Speter	int *pstat;
601838032Speter{
601938032Speter	if (tTd(38, 20))
602064562Sgshapiro		dprintf("impl_map_lookup(%s, %s)\n",
602138032Speter			map->map_mname, name);
602238032Speter
602338032Speter#ifdef NEWDB
602438032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
602538032Speter		return db_map_lookup(map, name, av, pstat);
602664562Sgshapiro#endif /* NEWDB */
602738032Speter#ifdef NDBM
602838032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
602938032Speter		return ndbm_map_lookup(map, name, av, pstat);
603064562Sgshapiro#endif /* NDBM */
603138032Speter	return stab_map_lookup(map, name, av, pstat);
603238032Speter}
603338032Speter
603438032Speter/*
603538032Speter**  IMPL_MAP_STORE -- store in open databases
603638032Speter*/
603738032Speter
603838032Spetervoid
603938032Speterimpl_map_store(map, lhs, rhs)
604038032Speter	MAP *map;
604138032Speter	char *lhs;
604238032Speter	char *rhs;
604338032Speter{
604438032Speter	if (tTd(38, 12))
604564562Sgshapiro		dprintf("impl_map_store(%s, %s, %s)\n",
604638032Speter			map->map_mname, lhs, rhs);
604738032Speter#ifdef NEWDB
604838032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
604938032Speter		db_map_store(map, lhs, rhs);
605064562Sgshapiro#endif /* NEWDB */
605138032Speter#ifdef NDBM
605238032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
605338032Speter		ndbm_map_store(map, lhs, rhs);
605464562Sgshapiro#endif /* NDBM */
605538032Speter	stab_map_store(map, lhs, rhs);
605638032Speter}
605738032Speter
605838032Speter/*
605938032Speter**  IMPL_MAP_OPEN -- implicit database open
606038032Speter*/
606138032Speter
606238032Speterbool
606338032Speterimpl_map_open(map, mode)
606438032Speter	MAP *map;
606538032Speter	int mode;
606638032Speter{
606738032Speter	if (tTd(38, 2))
606864562Sgshapiro		dprintf("impl_map_open(%s, %s, %d)\n",
606938032Speter			map->map_mname, map->map_file, mode);
607038032Speter
607138032Speter	mode &= O_ACCMODE;
607238032Speter#ifdef NEWDB
607338032Speter	map->map_mflags |= MF_IMPL_HASH;
607438032Speter	if (hash_map_open(map, mode))
607538032Speter	{
607638032Speter# ifdef NDBM_YP_COMPAT
607738032Speter		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
607864562Sgshapiro# endif /* NDBM_YP_COMPAT */
607938032Speter			return TRUE;
608038032Speter	}
608138032Speter	else
608238032Speter		map->map_mflags &= ~MF_IMPL_HASH;
608364562Sgshapiro#endif /* NEWDB */
608438032Speter#ifdef NDBM
608538032Speter	map->map_mflags |= MF_IMPL_NDBM;
608638032Speter	if (ndbm_map_open(map, mode))
608738032Speter	{
608838032Speter		return TRUE;
608938032Speter	}
609038032Speter	else
609138032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
609264562Sgshapiro#endif /* NDBM */
609338032Speter
609438032Speter#if defined(NEWDB) || defined(NDBM)
609538032Speter	if (Verbose)
609638032Speter		message("WARNING: cannot open alias database %s%s",
609738032Speter			map->map_file,
609838032Speter			mode == O_RDONLY ? "; reading text version" : "");
609964562Sgshapiro#else /* defined(NEWDB) || defined(NDBM) */
610038032Speter	if (mode != O_RDONLY)
610138032Speter		usrerr("Cannot rebuild aliases: no database format defined");
610264562Sgshapiro#endif /* defined(NEWDB) || defined(NDBM) */
610338032Speter
610438032Speter	if (mode == O_RDONLY)
610538032Speter		return stab_map_open(map, mode);
610638032Speter	else
610738032Speter		return FALSE;
610838032Speter}
610938032Speter
611038032Speter
611138032Speter/*
611238032Speter**  IMPL_MAP_CLOSE -- close any open database(s)
611338032Speter*/
611438032Speter
611538032Spetervoid
611638032Speterimpl_map_close(map)
611738032Speter	MAP *map;
611838032Speter{
611938032Speter	if (tTd(38, 9))
612064562Sgshapiro		dprintf("impl_map_close(%s, %s, %lx)\n",
612138032Speter			map->map_mname, map->map_file, map->map_mflags);
612238032Speter#ifdef NEWDB
612338032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
612438032Speter	{
612538032Speter		db_map_close(map);
612638032Speter		map->map_mflags &= ~MF_IMPL_HASH;
612738032Speter	}
612864562Sgshapiro#endif /* NEWDB */
612938032Speter
613038032Speter#ifdef NDBM
613138032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
613238032Speter	{
613338032Speter		ndbm_map_close(map);
613438032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
613538032Speter	}
613664562Sgshapiro#endif /* NDBM */
613738032Speter}
613838032Speter/*
613938032Speter**  User map class.
614038032Speter**
614138032Speter**	Provides access to the system password file.
614238032Speter*/
614338032Speter
614438032Speter/*
614538032Speter**  USER_MAP_OPEN -- open user map
614638032Speter**
614738032Speter**	Really just binds field names to field numbers.
614838032Speter*/
614938032Speter
615038032Speterbool
615138032Speteruser_map_open(map, mode)
615238032Speter	MAP *map;
615338032Speter	int mode;
615438032Speter{
615538032Speter	if (tTd(38, 2))
615664562Sgshapiro		dprintf("user_map_open(%s, %d)\n",
615738032Speter			map->map_mname, mode);
615838032Speter
615938032Speter	mode &= O_ACCMODE;
616038032Speter	if (mode != O_RDONLY)
616138032Speter	{
616238032Speter		/* issue a pseudo-error message */
616338032Speter#ifdef ENOSYS
616438032Speter		errno = ENOSYS;
616564562Sgshapiro#else /* ENOSYS */
616638032Speter# ifdef EFTYPE
616738032Speter		errno = EFTYPE;
616864562Sgshapiro# else /* EFTYPE */
616938032Speter		errno = ENXIO;
617064562Sgshapiro# endif /* EFTYPE */
617164562Sgshapiro#endif /* ENOSYS */
617238032Speter		return FALSE;
617338032Speter	}
617438032Speter	if (map->map_valcolnm == NULL)
617564562Sgshapiro		/* EMPTY */
617638032Speter		/* nothing */ ;
617738032Speter	else if (strcasecmp(map->map_valcolnm, "name") == 0)
617838032Speter		map->map_valcolno = 1;
617938032Speter	else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
618038032Speter		map->map_valcolno = 2;
618138032Speter	else if (strcasecmp(map->map_valcolnm, "uid") == 0)
618238032Speter		map->map_valcolno = 3;
618338032Speter	else if (strcasecmp(map->map_valcolnm, "gid") == 0)
618438032Speter		map->map_valcolno = 4;
618538032Speter	else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
618638032Speter		map->map_valcolno = 5;
618738032Speter	else if (strcasecmp(map->map_valcolnm, "dir") == 0)
618838032Speter		map->map_valcolno = 6;
618938032Speter	else if (strcasecmp(map->map_valcolnm, "shell") == 0)
619038032Speter		map->map_valcolno = 7;
619138032Speter	else
619238032Speter	{
619338032Speter		syserr("User map %s: unknown column name %s",
619438032Speter			map->map_mname, map->map_valcolnm);
619538032Speter		return FALSE;
619638032Speter	}
619738032Speter	return TRUE;
619838032Speter}
619938032Speter
620038032Speter
620138032Speter/*
620238032Speter**  USER_MAP_LOOKUP -- look up a user in the passwd file.
620338032Speter*/
620438032Speter
620538032Speter/* ARGSUSED3 */
620638032Speterchar *
620738032Speteruser_map_lookup(map, key, av, statp)
620838032Speter	MAP *map;
620938032Speter	char *key;
621038032Speter	char **av;
621138032Speter	int *statp;
621238032Speter{
621338032Speter	struct passwd *pw;
621438032Speter	auto bool fuzzy;
621538032Speter
621638032Speter	if (tTd(38, 20))
621764562Sgshapiro		dprintf("user_map_lookup(%s, %s)\n",
621838032Speter			map->map_mname, key);
621938032Speter
622038032Speter	pw = finduser(key, &fuzzy);
622138032Speter	if (pw == NULL)
622238032Speter		return NULL;
622338032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
622438032Speter		return map_rewrite(map, key, strlen(key), NULL);
622538032Speter	else
622638032Speter	{
622738032Speter		char *rwval = NULL;
622838032Speter		char buf[30];
622938032Speter
623038032Speter		switch (map->map_valcolno)
623138032Speter		{
623238032Speter		  case 0:
623338032Speter		  case 1:
623438032Speter			rwval = pw->pw_name;
623538032Speter			break;
623638032Speter
623738032Speter		  case 2:
623838032Speter			rwval = pw->pw_passwd;
623938032Speter			break;
624038032Speter
624138032Speter		  case 3:
624264562Sgshapiro			snprintf(buf, sizeof buf, "%d", (int) pw->pw_uid);
624338032Speter			rwval = buf;
624438032Speter			break;
624538032Speter
624638032Speter		  case 4:
624764562Sgshapiro			snprintf(buf, sizeof buf, "%d", (int) pw->pw_gid);
624838032Speter			rwval = buf;
624938032Speter			break;
625038032Speter
625138032Speter		  case 5:
625238032Speter			rwval = pw->pw_gecos;
625338032Speter			break;
625438032Speter
625538032Speter		  case 6:
625638032Speter			rwval = pw->pw_dir;
625738032Speter			break;
625838032Speter
625938032Speter		  case 7:
626038032Speter			rwval = pw->pw_shell;
626138032Speter			break;
626238032Speter		}
626338032Speter		return map_rewrite(map, rwval, strlen(rwval), av);
626438032Speter	}
626538032Speter}
626638032Speter/*
626738032Speter**  Program map type.
626838032Speter**
626938032Speter**	This provides access to arbitrary programs.  It should be used
627038032Speter**	only very sparingly, since there is no way to bound the cost
627138032Speter**	of invoking an arbitrary program.
627238032Speter*/
627338032Speter
627438032Speterchar *
627538032Speterprog_map_lookup(map, name, av, statp)
627638032Speter	MAP *map;
627738032Speter	char *name;
627838032Speter	char **av;
627938032Speter	int *statp;
628038032Speter{
628138032Speter	int i;
628264562Sgshapiro	int save_errno;
628338032Speter	int fd;
628464562Sgshapiro	int status;
628538032Speter	auto pid_t pid;
628664562Sgshapiro	register char *p;
628738032Speter	char *rval;
628838032Speter	char *argv[MAXPV + 1];
628938032Speter	char buf[MAXLINE];
629038032Speter
629138032Speter	if (tTd(38, 20))
629264562Sgshapiro		dprintf("prog_map_lookup(%s, %s) %s\n",
629338032Speter			map->map_mname, name, map->map_file);
629438032Speter
629538032Speter	i = 0;
629638032Speter	argv[i++] = map->map_file;
629738032Speter	if (map->map_rebuild != NULL)
629838032Speter	{
629938032Speter		snprintf(buf, sizeof buf, "%s", map->map_rebuild);
630038032Speter		for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
630138032Speter		{
630238032Speter			if (i >= MAXPV - 1)
630338032Speter				break;
630438032Speter			argv[i++] = p;
630538032Speter		}
630638032Speter	}
630738032Speter	argv[i++] = name;
630838032Speter	argv[i] = NULL;
630938032Speter	if (tTd(38, 21))
631038032Speter	{
631164562Sgshapiro		dprintf("prog_open:");
631238032Speter		for (i = 0; argv[i] != NULL; i++)
631364562Sgshapiro			dprintf(" %s", argv[i]);
631464562Sgshapiro		dprintf("\n");
631538032Speter	}
631638032Speter	(void) blocksignal(SIGCHLD);
631738032Speter	pid = prog_open(argv, &fd, CurEnv);
631838032Speter	if (pid < 0)
631938032Speter	{
632038032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
632138032Speter			syserr("prog_map_lookup(%s) failed (%s) -- closing",
632238032Speter				map->map_mname, errstring(errno));
632338032Speter		else if (tTd(38, 9))
632464562Sgshapiro			dprintf("prog_map_lookup(%s) failed (%s) -- closing",
632538032Speter				map->map_mname, errstring(errno));
632638032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
632738032Speter		*statp = EX_OSFILE;
632838032Speter		return NULL;
632938032Speter	}
633038032Speter	i = read(fd, buf, sizeof buf - 1);
633138032Speter	if (i < 0)
633238032Speter	{
633338032Speter		syserr("prog_map_lookup(%s): read error %s\n",
633438032Speter			map->map_mname, errstring(errno));
633538032Speter		rval = NULL;
633638032Speter	}
633738032Speter	else if (i == 0)
633838032Speter	{
633938032Speter		if (tTd(38, 20))
634064562Sgshapiro			dprintf("prog_map_lookup(%s): empty answer\n",
634138032Speter				map->map_mname);
634238032Speter		rval = NULL;
634338032Speter	}
634438032Speter	else
634538032Speter	{
634638032Speter		buf[i] = '\0';
634738032Speter		p = strchr(buf, '\n');
634838032Speter		if (p != NULL)
634938032Speter			*p = '\0';
635038032Speter
635138032Speter		/* collect the return value */
635238032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
635338032Speter			rval = map_rewrite(map, name, strlen(name), NULL);
635438032Speter		else
635538032Speter			rval = map_rewrite(map, buf, strlen(buf), NULL);
635638032Speter
635738032Speter		/* now flush any additional output */
635838032Speter		while ((i = read(fd, buf, sizeof buf)) > 0)
635938032Speter			continue;
636038032Speter	}
636138032Speter
636238032Speter	/* wait for the process to terminate */
636364562Sgshapiro	(void) close(fd);
636464562Sgshapiro	status = waitfor(pid);
636564562Sgshapiro	save_errno = errno;
636638032Speter	(void) releasesignal(SIGCHLD);
636764562Sgshapiro	errno = save_errno;
636838032Speter
636964562Sgshapiro	if (status == -1)
637038032Speter	{
637138032Speter		syserr("prog_map_lookup(%s): wait error %s\n",
637238032Speter			map->map_mname, errstring(errno));
637338032Speter		*statp = EX_SOFTWARE;
637438032Speter		rval = NULL;
637538032Speter	}
637664562Sgshapiro	else if (WIFEXITED(status))
637738032Speter	{
637864562Sgshapiro		if ((*statp = WEXITSTATUS(status)) != EX_OK)
637938032Speter			rval = NULL;
638038032Speter	}
638138032Speter	else
638238032Speter	{
638338032Speter		syserr("prog_map_lookup(%s): child died on signal %d",
638464562Sgshapiro			map->map_mname, status);
638538032Speter		*statp = EX_UNAVAILABLE;
638638032Speter		rval = NULL;
638738032Speter	}
638838032Speter	return rval;
638938032Speter}
639038032Speter/*
639138032Speter**  Sequenced map type.
639238032Speter**
639338032Speter**	Tries each map in order until something matches, much like
639438032Speter**	implicit.  Stores go to the first map in the list that can
639538032Speter**	support storing.
639638032Speter**
639738032Speter**	This is slightly unusual in that there are two interfaces.
639838032Speter**	The "sequence" interface lets you stack maps arbitrarily.
639938032Speter**	The "switch" interface builds a sequence map by looking
640038032Speter**	at a system-dependent configuration file such as
640138032Speter**	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
640238032Speter**
640338032Speter**	We don't need an explicit open, since all maps are
640438032Speter**	opened during startup, including underlying maps.
640538032Speter*/
640638032Speter
640738032Speter/*
640838032Speter**  SEQ_MAP_PARSE -- Sequenced map parsing
640938032Speter*/
641038032Speter
641138032Speterbool
641238032Speterseq_map_parse(map, ap)
641338032Speter	MAP *map;
641438032Speter	char *ap;
641538032Speter{
641638032Speter	int maxmap;
641738032Speter
641838032Speter	if (tTd(38, 2))
641964562Sgshapiro		dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
642038032Speter	maxmap = 0;
642138032Speter	while (*ap != '\0')
642238032Speter	{
642338032Speter		register char *p;
642438032Speter		STAB *s;
642538032Speter
642638032Speter		/* find beginning of map name */
642738032Speter		while (isascii(*ap) && isspace(*ap))
642838032Speter			ap++;
642964562Sgshapiro		for (p = ap;
643064562Sgshapiro		     (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
643164562Sgshapiro		     p++)
643238032Speter			continue;
643338032Speter		if (*p != '\0')
643438032Speter			*p++ = '\0';
643538032Speter		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
643638032Speter			p++;
643738032Speter		if (*ap == '\0')
643838032Speter		{
643938032Speter			ap = p;
644038032Speter			continue;
644138032Speter		}
644238032Speter		s = stab(ap, ST_MAP, ST_FIND);
644338032Speter		if (s == NULL)
644438032Speter		{
644538032Speter			syserr("Sequence map %s: unknown member map %s",
644638032Speter				map->map_mname, ap);
644738032Speter		}
644838032Speter		else if (maxmap == MAXMAPSTACK)
644938032Speter		{
645038032Speter			syserr("Sequence map %s: too many member maps (%d max)",
645138032Speter				map->map_mname, MAXMAPSTACK);
645238032Speter			maxmap++;
645338032Speter		}
645438032Speter		else if (maxmap < MAXMAPSTACK)
645538032Speter		{
645638032Speter			map->map_stack[maxmap++] = &s->s_map;
645738032Speter		}
645838032Speter		ap = p;
645938032Speter	}
646038032Speter	return TRUE;
646138032Speter}
646238032Speter
646338032Speter
646438032Speter/*
646538032Speter**  SWITCH_MAP_OPEN -- open a switched map
646638032Speter**
646738032Speter**	This looks at the system-dependent configuration and builds
646838032Speter**	a sequence map that does the same thing.
646938032Speter**
647038032Speter**	Every system must define a switch_map_find routine in conf.c
647138032Speter**	that will return the list of service types associated with a
647238032Speter**	given service class.
647338032Speter*/
647438032Speter
647538032Speterbool
647638032Speterswitch_map_open(map, mode)
647738032Speter	MAP *map;
647838032Speter	int mode;
647938032Speter{
648038032Speter	int mapno;
648138032Speter	int nmaps;
648238032Speter	char *maptype[MAXMAPSTACK];
648338032Speter
648438032Speter	if (tTd(38, 2))
648564562Sgshapiro		dprintf("switch_map_open(%s, %s, %d)\n",
648638032Speter			map->map_mname, map->map_file, mode);
648738032Speter
648838032Speter	mode &= O_ACCMODE;
648938032Speter	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
649038032Speter	if (tTd(38, 19))
649138032Speter	{
649264562Sgshapiro		dprintf("\tswitch_map_find => %d\n", nmaps);
649338032Speter		for (mapno = 0; mapno < nmaps; mapno++)
649464562Sgshapiro			dprintf("\t\t%s\n", maptype[mapno]);
649538032Speter	}
649638032Speter	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
649738032Speter		return FALSE;
649838032Speter
649938032Speter	for (mapno = 0; mapno < nmaps; mapno++)
650038032Speter	{
650138032Speter		register STAB *s;
650238032Speter		char nbuf[MAXNAME + 1];
650338032Speter
650438032Speter		if (maptype[mapno] == NULL)
650538032Speter			continue;
650638032Speter		(void) snprintf(nbuf, sizeof nbuf, "%s.%s",
650738032Speter			map->map_mname, maptype[mapno]);
650838032Speter		s = stab(nbuf, ST_MAP, ST_FIND);
650938032Speter		if (s == NULL)
651038032Speter		{
651138032Speter			syserr("Switch map %s: unknown member map %s",
651238032Speter				map->map_mname, nbuf);
651338032Speter		}
651438032Speter		else
651538032Speter		{
651638032Speter			map->map_stack[mapno] = &s->s_map;
651738032Speter			if (tTd(38, 4))
651864562Sgshapiro				dprintf("\tmap_stack[%d] = %s:%s\n",
651938032Speter					mapno, s->s_map.map_class->map_cname,
652038032Speter					nbuf);
652138032Speter		}
652238032Speter	}
652338032Speter	return TRUE;
652438032Speter}
652538032Speter
652638032Speter
652738032Speter/*
652838032Speter**  SEQ_MAP_CLOSE -- close all underlying maps
652938032Speter*/
653038032Speter
653138032Spetervoid
653238032Speterseq_map_close(map)
653338032Speter	MAP *map;
653438032Speter{
653538032Speter	int mapno;
653638032Speter
653738032Speter	if (tTd(38, 9))
653864562Sgshapiro		dprintf("seq_map_close(%s)\n", map->map_mname);
653938032Speter
654038032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
654138032Speter	{
654238032Speter		MAP *mm = map->map_stack[mapno];
654338032Speter
654438032Speter		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
654538032Speter			continue;
654638032Speter		mm->map_class->map_close(mm);
654738032Speter		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
654838032Speter	}
654938032Speter}
655038032Speter
655138032Speter
655238032Speter/*
655338032Speter**  SEQ_MAP_LOOKUP -- sequenced map lookup
655438032Speter*/
655538032Speter
655638032Speterchar *
655738032Speterseq_map_lookup(map, key, args, pstat)
655838032Speter	MAP *map;
655938032Speter	char *key;
656038032Speter	char **args;
656138032Speter	int *pstat;
656238032Speter{
656338032Speter	int mapno;
656438032Speter	int mapbit = 0x01;
656538032Speter	bool tempfail = FALSE;
656638032Speter
656738032Speter	if (tTd(38, 20))
656864562Sgshapiro		dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
656938032Speter
657038032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
657138032Speter	{
657238032Speter		MAP *mm = map->map_stack[mapno];
657338032Speter		char *rv;
657438032Speter
657538032Speter		if (mm == NULL)
657638032Speter			continue;
657764562Sgshapiro		if (!bitset(MF_OPEN, mm->map_mflags) &&
657864562Sgshapiro		    !openmap(mm))
657938032Speter		{
658038032Speter			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
658138032Speter			{
658238032Speter				*pstat = EX_UNAVAILABLE;
658338032Speter				return NULL;
658438032Speter			}
658538032Speter			continue;
658638032Speter		}
658738032Speter		*pstat = EX_OK;
658838032Speter		rv = mm->map_class->map_lookup(mm, key, args, pstat);
658938032Speter		if (rv != NULL)
659038032Speter			return rv;
659138032Speter		if (*pstat == EX_TEMPFAIL)
659238032Speter		{
659338032Speter			if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
659438032Speter				return NULL;
659538032Speter			tempfail = TRUE;
659638032Speter		}
659738032Speter		else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
659838032Speter			break;
659938032Speter	}
660038032Speter	if (tempfail)
660138032Speter		*pstat = EX_TEMPFAIL;
660238032Speter	else if (*pstat == EX_OK)
660338032Speter		*pstat = EX_NOTFOUND;
660438032Speter	return NULL;
660538032Speter}
660638032Speter
660738032Speter
660838032Speter/*
660938032Speter**  SEQ_MAP_STORE -- sequenced map store
661038032Speter*/
661138032Speter
661238032Spetervoid
661338032Speterseq_map_store(map, key, val)
661438032Speter	MAP *map;
661538032Speter	char *key;
661638032Speter	char *val;
661738032Speter{
661838032Speter	int mapno;
661938032Speter
662038032Speter	if (tTd(38, 12))
662164562Sgshapiro		dprintf("seq_map_store(%s, %s, %s)\n",
662238032Speter			map->map_mname, key, val);
662338032Speter
662438032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
662538032Speter	{
662638032Speter		MAP *mm = map->map_stack[mapno];
662738032Speter
662838032Speter		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
662938032Speter			continue;
663038032Speter
663138032Speter		mm->map_class->map_store(mm, key, val);
663238032Speter		return;
663338032Speter	}
663438032Speter	syserr("seq_map_store(%s, %s, %s): no writable map",
663538032Speter		map->map_mname, key, val);
663638032Speter}
663738032Speter/*
663838032Speter**  NULL stubs
663938032Speter*/
664038032Speter
664138032Speter/* ARGSUSED */
664238032Speterbool
664338032Speternull_map_open(map, mode)
664438032Speter	MAP *map;
664538032Speter	int mode;
664638032Speter{
664738032Speter	return TRUE;
664838032Speter}
664938032Speter
665038032Speter/* ARGSUSED */
665138032Spetervoid
665238032Speternull_map_close(map)
665338032Speter	MAP *map;
665438032Speter{
665538032Speter	return;
665638032Speter}
665738032Speter
665838032Speterchar *
665938032Speternull_map_lookup(map, key, args, pstat)
666038032Speter	MAP *map;
666138032Speter	char *key;
666238032Speter	char **args;
666338032Speter	int *pstat;
666438032Speter{
666538032Speter	*pstat = EX_NOTFOUND;
666638032Speter	return NULL;
666738032Speter}
666838032Speter
666938032Speter/* ARGSUSED */
667038032Spetervoid
667138032Speternull_map_store(map, key, val)
667238032Speter	MAP *map;
667338032Speter	char *key;
667438032Speter	char *val;
667538032Speter{
667638032Speter	return;
667738032Speter}
667838032Speter
667938032Speter
668038032Speter/*
668138032Speter**  BOGUS stubs
668238032Speter*/
668338032Speter
668438032Speterchar *
668538032Speterbogus_map_lookup(map, key, args, pstat)
668638032Speter	MAP *map;
668738032Speter	char *key;
668838032Speter	char **args;
668938032Speter	int *pstat;
669038032Speter{
669138032Speter	*pstat = EX_TEMPFAIL;
669238032Speter	return NULL;
669338032Speter}
669438032Speter
669538032SpeterMAPCLASS	BogusMapClass =
669638032Speter{
669738032Speter	"bogus-map",		NULL,		0,
669838032Speter	NULL,		bogus_map_lookup,	null_map_store,
669938032Speter	null_map_open,	null_map_close,
670038032Speter};
670138032Speter/*
670264562Sgshapiro**  MACRO modules
670364562Sgshapiro*/
670464562Sgshapiro
670564562Sgshapirochar *
670664562Sgshapiromacro_map_lookup(map, name, av, statp)
670764562Sgshapiro	MAP *map;
670864562Sgshapiro	char *name;
670964562Sgshapiro	char **av;
671064562Sgshapiro	int *statp;
671164562Sgshapiro{
671264562Sgshapiro	int mid;
671364562Sgshapiro
671464562Sgshapiro	if (tTd(38, 20))
671564562Sgshapiro		dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
671664562Sgshapiro			name == NULL ? "NULL" : name);
671764562Sgshapiro
671864562Sgshapiro	if (name == NULL ||
671964562Sgshapiro	    *name == '\0' ||
672064562Sgshapiro	    (mid = macid(name, NULL)) == '\0')
672164562Sgshapiro	{
672264562Sgshapiro		*statp = EX_CONFIG;
672364562Sgshapiro		return NULL;
672464562Sgshapiro	}
672564562Sgshapiro
672664562Sgshapiro	if (av[1] == NULL)
672764562Sgshapiro		define(mid, NULL, CurEnv);
672864562Sgshapiro	else
672964562Sgshapiro		define(mid, newstr(av[1]), CurEnv);
673064562Sgshapiro
673164562Sgshapiro	*statp = EX_OK;
673264562Sgshapiro	return "";
673364562Sgshapiro}
673464562Sgshapiro/*
673538032Speter**  REGEX modules
673638032Speter*/
673738032Speter
673838032Speter#ifdef MAP_REGEX
673938032Speter
674038032Speter# include <regex.h>
674138032Speter
674238032Speter# define DEFAULT_DELIM	CONDELSE
674338032Speter
674438032Speter# define END_OF_FIELDS	-1
674538032Speter
674638032Speter# define ERRBUF_SIZE	80
674738032Speter# define MAX_MATCH	32
674838032Speter
674964562Sgshapiro# define xnalloc(s)	memset(xalloc(s), '\0', s);
675038032Speter
675138032Speterstruct regex_map
675238032Speter{
675371345Sgshapiro	regex_t	*regex_pattern_buf;	/* xalloc it */
675438032Speter	int	*regex_subfields;	/* move to type MAP */
675564562Sgshapiro	char	*regex_delim;		/* move to type MAP */
675638032Speter};
675738032Speter
675838032Speterstatic int
675938032Speterparse_fields(s, ibuf, blen, nr_substrings)
676038032Speter	char *s;
676138032Speter	int *ibuf;		/* array */
676238032Speter	int blen;		/* number of elements in ibuf */
676338032Speter	int nr_substrings;	/* number of substrings in the pattern */
676438032Speter{
676538032Speter	register char *cp;
676638032Speter	int i = 0;
676738032Speter	bool lastone = FALSE;
676838032Speter
676938032Speter	blen--;		/* for terminating END_OF_FIELDS */
677038032Speter	cp = s;
677138032Speter	do
677238032Speter	{
677338032Speter		for (;; cp++)
677438032Speter		{
677538032Speter			if (*cp == ',')
677638032Speter			{
677738032Speter				*cp = '\0';
677838032Speter				break;
677938032Speter			}
678038032Speter			if (*cp == '\0')
678138032Speter			{
678238032Speter				lastone = TRUE;
678338032Speter				break;
678438032Speter			}
678538032Speter		}
678638032Speter		if (i < blen)
678738032Speter		{
678838032Speter			int val = atoi(s);
678938032Speter
679038032Speter			if (val < 0 || val >= nr_substrings)
679138032Speter			{
679238032Speter				syserr("field (%d) out of range, only %d substrings in pattern",
679338032Speter				       val, nr_substrings);
679438032Speter				return -1;
679538032Speter			}
679638032Speter			ibuf[i++] = val;
679738032Speter		}
679838032Speter		else
679938032Speter		{
680038032Speter			syserr("too many fields, %d max\n", blen);
680138032Speter			return -1;
680238032Speter		}
680338032Speter		s = ++cp;
680438032Speter	} while (!lastone);
680538032Speter	ibuf[i] = END_OF_FIELDS;
680638032Speter	return i;
680738032Speter}
680838032Speter
680938032Speterbool
681038032Speterregex_map_init(map, ap)
681138032Speter	MAP *map;
681238032Speter	char *ap;
681338032Speter{
681438032Speter	int regerr;
681538032Speter	struct regex_map *map_p;
681638032Speter	register char *p;
681738032Speter	char *sub_param = NULL;
681838032Speter	int pflags;
681938032Speter	static char defdstr[] = { (char)DEFAULT_DELIM, '\0' };
682038032Speter
682138032Speter	if (tTd(38, 2))
682264562Sgshapiro		dprintf("regex_map_init: mapname '%s', args '%s'\n",
682364562Sgshapiro			map->map_mname, ap);
682438032Speter
682538032Speter	pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
682638032Speter
682738032Speter	p = ap;
682838032Speter
682964562Sgshapiro	map_p = (struct regex_map *) xnalloc(sizeof *map_p);
683071345Sgshapiro	map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t));
683138032Speter
683238032Speter	for (;;)
683364562Sgshapiro	{
683438032Speter		while (isascii(*p) && isspace(*p))
683538032Speter			p++;
683638032Speter		if (*p != '-')
683738032Speter			break;
683838032Speter		switch (*++p)
683938032Speter		{
684038032Speter		  case 'n':	/* not */
684138032Speter			map->map_mflags |= MF_REGEX_NOT;
684238032Speter			break;
684338032Speter
684438032Speter		  case 'f':	/* case sensitive */
684538032Speter			map->map_mflags |= MF_NOFOLDCASE;
684638032Speter			pflags &= ~REG_ICASE;
684738032Speter			break;
684838032Speter
684938032Speter		  case 'b':	/* basic regular expressions */
685038032Speter			pflags &= ~REG_EXTENDED;
685138032Speter			break;
685238032Speter
685338032Speter		  case 's':	/* substring match () syntax */
685438032Speter			sub_param = ++p;
685538032Speter			pflags &= ~REG_NOSUB;
685638032Speter			break;
685738032Speter
685838032Speter		  case 'd':	/* delimiter */
685964562Sgshapiro			map_p->regex_delim = ++p;
686038032Speter			break;
686138032Speter
686238032Speter		  case 'a':	/* map append */
686338032Speter			map->map_app = ++p;
686438032Speter			break;
686538032Speter
686638032Speter		  case 'm':	/* matchonly */
686738032Speter			map->map_mflags |= MF_MATCHONLY;
686838032Speter			break;
686938032Speter
687064562Sgshapiro		  case 'S':
687164562Sgshapiro			map->map_spacesub = *++p;
687264562Sgshapiro			break;
687364562Sgshapiro
687464562Sgshapiro		  case 'D':
687564562Sgshapiro			map->map_mflags |= MF_DEFER;
687664562Sgshapiro			break;
687764562Sgshapiro
687838032Speter		}
687964562Sgshapiro		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
688064562Sgshapiro			p++;
688164562Sgshapiro		if (*p != '\0')
688264562Sgshapiro			*p++ = '\0';
688338032Speter	}
688438032Speter	if (tTd(38, 3))
688564562Sgshapiro		dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
688638032Speter
688771345Sgshapiro	if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0)
688838032Speter	{
688938032Speter		/* Errorhandling */
689038032Speter		char errbuf[ERRBUF_SIZE];
689138032Speter
689271345Sgshapiro		(void) regerror(regerr, map_p->regex_pattern_buf,
689364562Sgshapiro			 errbuf, ERRBUF_SIZE);
689438032Speter		syserr("pattern-compile-error: %s\n", errbuf);
689571345Sgshapiro		free(map_p->regex_pattern_buf);
689638032Speter		free(map_p);
689738032Speter		return FALSE;
689838032Speter	}
689938032Speter
690038032Speter	if (map->map_app != NULL)
690138032Speter		map->map_app = newstr(map->map_app);
690264562Sgshapiro	if (map_p->regex_delim != NULL)
690364562Sgshapiro		map_p->regex_delim = newstr(map_p->regex_delim);
690438032Speter	else
690564562Sgshapiro		map_p->regex_delim = defdstr;
690638032Speter
690738032Speter	if (!bitset(REG_NOSUB, pflags))
690838032Speter	{
690938032Speter		/* substring matching */
691038032Speter		int substrings;
691164562Sgshapiro		int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
691238032Speter
691371345Sgshapiro		substrings = map_p->regex_pattern_buf->re_nsub + 1;
691438032Speter
691538032Speter		if (tTd(38, 3))
691664562Sgshapiro			dprintf("regex_map_init: nr of substrings %d\n",
691764562Sgshapiro				substrings);
691838032Speter
691938032Speter		if (substrings >= MAX_MATCH)
692038032Speter		{
692138032Speter			syserr("too many substrings, %d max\n", MAX_MATCH);
692271345Sgshapiro			free(map_p->regex_pattern_buf);
692338032Speter			free(map_p);
692438032Speter			return FALSE;
692538032Speter		}
692638032Speter		if (sub_param != NULL && sub_param[0] != '\0')
692738032Speter		{
692838032Speter			/* optional parameter -sfields */
692938032Speter			if (parse_fields(sub_param, fields,
693038032Speter					 MAX_MATCH + 1, substrings) == -1)
693138032Speter				return FALSE;
693238032Speter		}
693338032Speter		else
693438032Speter		{
693564562Sgshapiro			/* set default fields */
693638032Speter			int i;
693738032Speter
693838032Speter			for (i = 0; i < substrings; i++)
693938032Speter				fields[i] = i;
694038032Speter			fields[i] = END_OF_FIELDS;
694138032Speter		}
694238032Speter		map_p->regex_subfields = fields;
694338032Speter		if (tTd(38, 3))
694438032Speter		{
694538032Speter			int *ip;
694638032Speter
694764562Sgshapiro			dprintf("regex_map_init: subfields");
694838032Speter			for (ip = fields; *ip != END_OF_FIELDS; ip++)
694964562Sgshapiro				dprintf(" %d", *ip);
695064562Sgshapiro			dprintf("\n");
695138032Speter		}
695238032Speter	}
695338032Speter	map->map_db1 = (ARBPTR_T)map_p;	/* dirty hack */
695438032Speter
695538032Speter	return TRUE;
695638032Speter}
695738032Speter
695838032Speterstatic char *
695938032Speterregex_map_rewrite(map, s, slen, av)
696038032Speter	MAP *map;
696138032Speter	const char *s;
696238032Speter	size_t slen;
696338032Speter	char **av;
696438032Speter{
696538032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
696638032Speter		return map_rewrite(map, av[0], strlen(av[0]), NULL);
696738032Speter	else
696838032Speter		return map_rewrite(map, s, slen, NULL);
696938032Speter}
697038032Speter
697138032Speterchar *
697238032Speterregex_map_lookup(map, name, av, statp)
697338032Speter	MAP *map;
697438032Speter	char *name;
697538032Speter	char **av;
697638032Speter	int *statp;
697738032Speter{
697838032Speter	int reg_res;
697938032Speter	struct regex_map *map_p;
698038032Speter	regmatch_t pmatch[MAX_MATCH];
698138032Speter
698238032Speter	if (tTd(38, 20))
698338032Speter	{
698438032Speter		char **cpp;
698538032Speter
698664562Sgshapiro		dprintf("regex_map_lookup: key '%s'\n", name);
698764562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
698864562Sgshapiro			dprintf("regex_map_lookup: arg '%s'\n", *cpp);
698938032Speter	}
699038032Speter
699138032Speter	map_p = (struct regex_map *)(map->map_db1);
699271345Sgshapiro	reg_res = regexec(map_p->regex_pattern_buf,
699364562Sgshapiro			  name, MAX_MATCH, pmatch, 0);
699438032Speter
699538032Speter	if (bitset(MF_REGEX_NOT, map->map_mflags))
699638032Speter	{
699738032Speter		/* option -n */
699838032Speter		if (reg_res == REG_NOMATCH)
699938032Speter			return regex_map_rewrite(map, "", (size_t)0, av);
700038032Speter		else
700138032Speter			return NULL;
700238032Speter	}
700338032Speter	if (reg_res == REG_NOMATCH)
700438032Speter		return NULL;
700538032Speter
700638032Speter	if (map_p->regex_subfields != NULL)
700738032Speter	{
700838032Speter		/* option -s */
700938032Speter		static char retbuf[MAXNAME];
701038032Speter		int fields[MAX_MATCH + 1];
701138032Speter		bool first = TRUE;
701238032Speter		int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
701338032Speter		bool quotemode = FALSE, bslashmode = FALSE;
701438032Speter		register char *dp, *sp;
701538032Speter		char *endp, *ldp;
701638032Speter		int *ip;
701738032Speter
701838032Speter		dp = retbuf;
701938032Speter		ldp = retbuf + sizeof(retbuf) - 1;
702038032Speter
702138032Speter		if (av[1] != NULL)
702238032Speter		{
702338032Speter			if (parse_fields(av[1], fields, MAX_MATCH + 1,
702471345Sgshapiro					 (int) map_p->regex_pattern_buf->re_nsub + 1) == -1)
702538032Speter			{
702638032Speter				*statp = EX_CONFIG;
702738032Speter				return NULL;
702838032Speter			}
702938032Speter			ip = fields;
703038032Speter		}
703138032Speter		else
703238032Speter			ip = map_p->regex_subfields;
703338032Speter
703438032Speter		for ( ; *ip != END_OF_FIELDS; ip++)
703538032Speter		{
703638032Speter			if (!first)
703738032Speter			{
703864562Sgshapiro				for (sp = map_p->regex_delim; *sp; sp++)
703938032Speter				{
704038032Speter					if (dp < ldp)
704138032Speter						*dp++ = *sp;
704238032Speter				}
704338032Speter			}
704438032Speter			else
704538032Speter				first = FALSE;
704638032Speter
704738032Speter
704871345Sgshapiro			if (*ip >= MAX_MATCH ||
704971345Sgshapiro			    pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
705038032Speter				continue;
705138032Speter
705238032Speter			sp = name + pmatch[*ip].rm_so;
705338032Speter			endp = name + pmatch[*ip].rm_eo;
705438032Speter			for (; endp > sp; sp++)
705538032Speter			{
705638032Speter				if (dp < ldp)
705738032Speter				{
705864562Sgshapiro					if (bslashmode)
705964562Sgshapiro					{
706038032Speter						*dp++ = *sp;
706138032Speter						bslashmode = FALSE;
706238032Speter					}
706364562Sgshapiro					else if (quotemode && *sp != '"' &&
706438032Speter						*sp != '\\')
706538032Speter					{
706638032Speter						*dp++ = *sp;
706738032Speter					}
706838032Speter					else switch(*dp++ = *sp)
706938032Speter					{
707038032Speter						case '\\':
707138032Speter						bslashmode = TRUE;
707238032Speter						break;
707338032Speter
707438032Speter						case '(':
707538032Speter						cmntcnt++;
707638032Speter						break;
707738032Speter
707838032Speter						case ')':
707938032Speter						cmntcnt--;
708038032Speter						break;
708138032Speter
708238032Speter						case '<':
708338032Speter						anglecnt++;
708438032Speter						break;
708538032Speter
708638032Speter						case '>':
708738032Speter						anglecnt--;
708838032Speter						break;
708938032Speter
709038032Speter						case ' ':
709138032Speter						spacecnt++;
709238032Speter						break;
709338032Speter
709438032Speter						case '"':
709538032Speter						quotemode = !quotemode;
709638032Speter						break;
709738032Speter					}
709838032Speter				}
709938032Speter			}
710038032Speter		}
710138032Speter		if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
710238032Speter		    bslashmode || spacecnt != 0)
710338032Speter		{
710464562Sgshapiro			sm_syslog(LOG_WARNING, NOQID,
710564562Sgshapiro				  "Warning: regex may cause prescan() failure map=%s lookup=%s",
710664562Sgshapiro				  map->map_mname, name);
710738032Speter			return NULL;
710838032Speter		}
710938032Speter
711038032Speter		*dp = '\0';
711138032Speter
711238032Speter		return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
711338032Speter	}
711438032Speter	return regex_map_rewrite(map, "", (size_t)0, av);
711538032Speter}
711638032Speter#endif /* MAP_REGEX */
711764562Sgshapiro/*
711864562Sgshapiro**  NSD modules
711964562Sgshapiro*/
712064562Sgshapiro#ifdef MAP_NSD
712164562Sgshapiro
712264562Sgshapiro# include <ndbm.h>
712364562Sgshapiro# define _DATUM_DEFINED
712464562Sgshapiro# include <ns_api.h>
712564562Sgshapiro
712664562Sgshapirotypedef struct ns_map_list
712764562Sgshapiro{
712864562Sgshapiro	ns_map_t *map;
712964562Sgshapiro	char *mapname;
713064562Sgshapiro	struct ns_map_list *next;
713164562Sgshapiro} ns_map_list_t;
713264562Sgshapiro
713364562Sgshapirostatic ns_map_t *
713464562Sgshapirons_map_t_find(mapname)
713564562Sgshapiro	char *mapname;
713664562Sgshapiro{
713764562Sgshapiro	static ns_map_list_t *ns_maps = NULL;
713864562Sgshapiro	ns_map_list_t *ns_map;
713964562Sgshapiro
714064562Sgshapiro	/* walk the list of maps looking for the correctly named map */
714164562Sgshapiro	for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
714264562Sgshapiro	{
714364562Sgshapiro		if (strcmp(ns_map->mapname, mapname) == 0)
714464562Sgshapiro			break;
714564562Sgshapiro	}
714664562Sgshapiro
714764562Sgshapiro	/* if we are looking at a NULL ns_map_list_t, then create a new one */
714864562Sgshapiro	if (ns_map == NULL)
714964562Sgshapiro	{
715064562Sgshapiro		ns_map = (ns_map_list_t *) xalloc(sizeof *ns_map);
715164562Sgshapiro		ns_map->mapname = newstr(mapname);
715264562Sgshapiro		ns_map->map = (ns_map_t *) xalloc(sizeof *ns_map->map);
715364562Sgshapiro		ns_map->next = ns_maps;
715464562Sgshapiro		ns_maps = ns_map;
715564562Sgshapiro	}
715664562Sgshapiro	return ns_map->map;
715764562Sgshapiro}
715864562Sgshapiro
715964562Sgshapirochar *
716064562Sgshapironsd_map_lookup(map, name, av, statp)
716164562Sgshapiro	MAP *map;
716264562Sgshapiro	char *name;
716364562Sgshapiro	char **av;
716464562Sgshapiro	int *statp;
716564562Sgshapiro{
716671345Sgshapiro	int buflen, r;
716764562Sgshapiro	char *p;
716864562Sgshapiro	ns_map_t *ns_map;
716964562Sgshapiro	char keybuf[MAXNAME + 1];
717064562Sgshapiro	char buf[MAXLINE];
717164562Sgshapiro
717264562Sgshapiro	if (tTd(38, 20))
717364562Sgshapiro		dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
717464562Sgshapiro
717564562Sgshapiro	buflen = strlen(name);
717664562Sgshapiro	if (buflen > sizeof keybuf - 1)
717764562Sgshapiro		buflen = sizeof keybuf - 1;
717864562Sgshapiro	memmove(keybuf, name, buflen);
717964562Sgshapiro	keybuf[buflen] = '\0';
718064562Sgshapiro	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
718164562Sgshapiro		makelower(keybuf);
718264562Sgshapiro
718364562Sgshapiro	ns_map = ns_map_t_find(map->map_file);
718464562Sgshapiro	if (ns_map == NULL)
718564562Sgshapiro	{
718664562Sgshapiro		if (tTd(38, 20))
718764562Sgshapiro			dprintf("nsd_map_t_find failed\n");
718871345Sgshapiro		*statp = EX_UNAVAILABLE;
718964562Sgshapiro		return NULL;
719064562Sgshapiro	}
719171345Sgshapiro	r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL, buf, MAXLINE);
719271345Sgshapiro	if (r == NS_UNAVAIL || r == NS_TRYAGAIN)
719371345Sgshapiro	{
719471345Sgshapiro		*statp = EX_TEMPFAIL;
719564562Sgshapiro		return NULL;
719671345Sgshapiro	}
719771345Sgshapiro	if (r == NS_BADREQ || r == NS_NOPERM)
719871345Sgshapiro	{
719971345Sgshapiro		*statp = EX_CONFIG;
720071345Sgshapiro		return NULL;
720171345Sgshapiro	}
720271345Sgshapiro	if (r != NS_SUCCESS)
720371345Sgshapiro	{
720471345Sgshapiro		*statp = EX_NOTFOUND;
720571345Sgshapiro		return NULL;
720671345Sgshapiro	}
720764562Sgshapiro
720871345Sgshapiro	*statp = EX_OK;
720971345Sgshapiro
721064562Sgshapiro	/* Null out trailing \n */
721164562Sgshapiro	if ((p = strchr(buf, '\n')) != NULL)
721264562Sgshapiro		*p = '\0';
721364562Sgshapiro
721464562Sgshapiro	return map_rewrite(map, buf, strlen(buf), av);
721564562Sgshapiro}
721664562Sgshapiro#endif /* MAP_NSD */
721764562Sgshapiro
721864562Sgshapirochar *
721964562Sgshapiroarith_map_lookup(map, name, av, statp)
722064562Sgshapiro	MAP *map;
722164562Sgshapiro	char *name;
722264562Sgshapiro	char **av;
722364562Sgshapiro	int *statp;
722464562Sgshapiro{
722564562Sgshapiro	long r;
722664562Sgshapiro	long v[2];
722764562Sgshapiro	bool res = FALSE;
722864562Sgshapiro	bool boolres;
722964562Sgshapiro	static char result[16];
723064562Sgshapiro	char **cpp;
723164562Sgshapiro
723264562Sgshapiro	if (tTd(38, 2))
723364562Sgshapiro	{
723464562Sgshapiro		dprintf("arith_map_lookup: key '%s'\n", name);
723564562Sgshapiro		for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
723664562Sgshapiro			dprintf("arith_map_lookup: arg '%s'\n", *cpp);
723764562Sgshapiro	}
723864562Sgshapiro	r = 0;
723964562Sgshapiro	boolres = FALSE;
724064562Sgshapiro	cpp = av;
724164562Sgshapiro	*statp = EX_OK;
724264562Sgshapiro
724364562Sgshapiro	/*
724464562Sgshapiro	**  read arguments for arith map
724564562Sgshapiro	**  - no check is made whether they are really numbers
724664562Sgshapiro	**  - just ignores args after the second
724764562Sgshapiro	*/
724864562Sgshapiro	for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
724964562Sgshapiro		v[r++] = strtol(*cpp, NULL, 0);
725064562Sgshapiro
725164562Sgshapiro	/* operator and (at least) two operands given? */
725264562Sgshapiro	if (name != NULL && r == 2)
725364562Sgshapiro	{
725464562Sgshapiro		switch(*name)
725564562Sgshapiro		{
725664562Sgshapiro#if _FFR_ARITH
725764562Sgshapiro		  case '|':
725864562Sgshapiro			r = v[0] | v[1];
725964562Sgshapiro			break;
726064562Sgshapiro
726164562Sgshapiro		  case '&':
726264562Sgshapiro			r = v[0] & v[1];
726364562Sgshapiro			break;
726464562Sgshapiro
726564562Sgshapiro		  case '%':
726664562Sgshapiro			if (v[1] == 0)
726764562Sgshapiro				return NULL;
726864562Sgshapiro			r = v[0] % v[1];
726964562Sgshapiro			break;
727064562Sgshapiro#endif /* _FFR_ARITH */
727164562Sgshapiro
727264562Sgshapiro		  case '+':
727364562Sgshapiro			r = v[0] + v[1];
727464562Sgshapiro			break;
727564562Sgshapiro
727664562Sgshapiro		  case '-':
727764562Sgshapiro			r = v[0] - v[1];
727864562Sgshapiro			break;
727964562Sgshapiro
728064562Sgshapiro		  case '*':
728164562Sgshapiro			r = v[0] * v[1];
728264562Sgshapiro			break;
728364562Sgshapiro
728464562Sgshapiro		  case '/':
728564562Sgshapiro			if (v[1] == 0)
728664562Sgshapiro				return NULL;
728764562Sgshapiro			r = v[0] / v[1];
728864562Sgshapiro			break;
728964562Sgshapiro
729064562Sgshapiro		  case 'l':
729164562Sgshapiro			res = v[0] < v[1];
729264562Sgshapiro			boolres = TRUE;
729364562Sgshapiro			break;
729464562Sgshapiro
729564562Sgshapiro		  case '=':
729664562Sgshapiro			res = v[0] == v[1];
729764562Sgshapiro			boolres = TRUE;
729864562Sgshapiro			break;
729964562Sgshapiro
730064562Sgshapiro		  default:
730164562Sgshapiro			/* XXX */
730264562Sgshapiro			*statp = EX_CONFIG;
730364562Sgshapiro			if (LogLevel > 10)
730464562Sgshapiro				sm_syslog(LOG_WARNING, NOQID,
730564562Sgshapiro					  "arith_map: unknown operator %c",
730664562Sgshapiro					  isprint(*name) ? *name : '?');
730764562Sgshapiro			return NULL;
730864562Sgshapiro		}
730964562Sgshapiro		if (boolres)
731064562Sgshapiro			snprintf(result, sizeof result, res ? "TRUE" : "FALSE");
731164562Sgshapiro		else
731264562Sgshapiro			snprintf(result, sizeof result, "%ld", r);
731364562Sgshapiro		return result;
731464562Sgshapiro	}
731564562Sgshapiro	*statp = EX_CONFIG;
731664562Sgshapiro	return NULL;
731764562Sgshapiro}
7318