map.c revision 38032
138032Speter/*
238032Speter * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
338032Speter * Copyright (c) 1992, 1995-1997 Eric P. Allman.  All rights reserved.
438032Speter * Copyright (c) 1992, 1993
538032Speter *	The Regents of the University of California.  All rights reserved.
638032Speter *
738032Speter * By using this file, you agree to the terms and conditions set
838032Speter * forth in the LICENSE file which can be found at the top level of
938032Speter * the sendmail distribution.
1038032Speter *
1138032Speter */
1238032Speter
1338032Speter#ifndef lint
1438032Speterstatic char sccsid[] = "@(#)map.c	8.239 (Berkeley) 6/5/98";
1538032Speter#endif /* not lint */
1638032Speter
1738032Speter#include "sendmail.h"
1838032Speter
1938032Speter#ifdef NDBM
2038032Speter# include <ndbm.h>
2138032Speter# ifdef R_FIRST
2238032Speter  ERROR README:	You are running the Berkeley DB version of ndbm.h.  See
2338032Speter  ERROR README:	the README file about tweaking Berkeley DB so it can
2438032Speter  ERROR README:	coexist with NDBM, or delete -DNDBM from the Makefile
2538032Speter  ERROR README: and use -DNEWDB instead.
2638032Speter# endif
2738032Speter#endif
2838032Speter#ifdef NEWDB
2938032Speter# include <db.h>
3038032Speter# ifndef DB_VERSION_MAJOR
3138032Speter#  define DB_VERSION_MAJOR 1
3238032Speter# endif
3338032Speter#endif
3438032Speter#ifdef NIS
3538032Speter  struct dom_binding;	/* forward reference needed on IRIX */
3638032Speter# include <rpcsvc/ypclnt.h>
3738032Speter# ifdef NDBM
3838032Speter#  define NDBM_YP_COMPAT	/* create YP-compatible NDBM files */
3938032Speter# endif
4038032Speter#endif
4138032Speter
4238032Speter/*
4338032Speter**  MAP.C -- implementations for various map classes.
4438032Speter**
4538032Speter**	Each map class implements a series of functions:
4638032Speter**
4738032Speter**	bool map_parse(MAP *map, char *args)
4838032Speter**		Parse the arguments from the config file.  Return TRUE
4938032Speter**		if they were ok, FALSE otherwise.  Fill in map with the
5038032Speter**		values.
5138032Speter**
5238032Speter**	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
5338032Speter**		Look up the key in the given map.  If found, do any
5438032Speter**		rewriting the map wants (including "args" if desired)
5538032Speter**		and return the value.  Set *pstat to the appropriate status
5638032Speter**		on error and return NULL.  Args will be NULL if called
5738032Speter**		from the alias routines, although this should probably
5838032Speter**		not be relied upon.  It is suggested you call map_rewrite
5938032Speter**		to return the results -- it takes care of null termination
6038032Speter**		and uses a dynamically expanded buffer as needed.
6138032Speter**
6238032Speter**	void map_store(MAP *map, char *key, char *value)
6338032Speter**		Store the key:value pair in the map.
6438032Speter**
6538032Speter**	bool map_open(MAP *map, int mode)
6638032Speter**		Open the map for the indicated mode.  Mode should
6738032Speter**		be either O_RDONLY or O_RDWR.  Return TRUE if it
6838032Speter**		was opened successfully, FALSE otherwise.  If the open
6938032Speter**		failed an the MF_OPTIONAL flag is not set, it should
7038032Speter**		also print an error.  If the MF_ALIAS bit is set
7138032Speter**		and this map class understands the @:@ convention, it
7238032Speter**		should call aliaswait() before returning.
7338032Speter**
7438032Speter**	void map_close(MAP *map)
7538032Speter**		Close the map.
7638032Speter**
7738032Speter**	This file also includes the implementation for getcanonname.
7838032Speter**	It is currently implemented in a pretty ad-hoc manner; it ought
7938032Speter**	to be more properly integrated into the map structure.
8038032Speter*/
8138032Speter
8238032Speter#define DBMMODE		0644
8338032Speter
8438032Speter#ifndef EX_NOTFOUND
8538032Speter# define EX_NOTFOUND	EX_NOHOST
8638032Speter#endif
8738032Speter
8838032Speterextern bool	aliaswait __P((MAP *, char *, int));
8938032Speterextern bool	extract_canonname __P((char *, char *, char[], int));
9038032Speter
9138032Speter#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
9238032Speter# define LOCK_ON_OPEN	1	/* we can open/create a locked file */
9338032Speter#else
9438032Speter# define LOCK_ON_OPEN	0	/* no such luck -- bend over backwards */
9538032Speter#endif
9638032Speter
9738032Speter#ifndef O_ACCMODE
9838032Speter# define O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR)
9938032Speter#endif
10038032Speter/*
10138032Speter**  MAP_PARSEARGS -- parse config line arguments for database lookup
10238032Speter**
10338032Speter**	This is a generic version of the map_parse method.
10438032Speter**
10538032Speter**	Parameters:
10638032Speter**		map -- the map being initialized.
10738032Speter**		ap -- a pointer to the args on the config line.
10838032Speter**
10938032Speter**	Returns:
11038032Speter**		TRUE -- if everything parsed OK.
11138032Speter**		FALSE -- otherwise.
11238032Speter**
11338032Speter**	Side Effects:
11438032Speter**		null terminates the filename; stores it in map
11538032Speter*/
11638032Speter
11738032Speterbool
11838032Spetermap_parseargs(map, ap)
11938032Speter	MAP *map;
12038032Speter	char *ap;
12138032Speter{
12238032Speter	register char *p = ap;
12338032Speter
12438032Speter	map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
12538032Speter	for (;;)
12638032Speter	{
12738032Speter		while (isascii(*p) && isspace(*p))
12838032Speter			p++;
12938032Speter		if (*p != '-')
13038032Speter			break;
13138032Speter		switch (*++p)
13238032Speter		{
13338032Speter		  case 'N':
13438032Speter			map->map_mflags |= MF_INCLNULL;
13538032Speter			map->map_mflags &= ~MF_TRY0NULL;
13638032Speter			break;
13738032Speter
13838032Speter		  case 'O':
13938032Speter			map->map_mflags &= ~MF_TRY1NULL;
14038032Speter			break;
14138032Speter
14238032Speter		  case 'o':
14338032Speter			map->map_mflags |= MF_OPTIONAL;
14438032Speter			break;
14538032Speter
14638032Speter		  case 'f':
14738032Speter			map->map_mflags |= MF_NOFOLDCASE;
14838032Speter			break;
14938032Speter
15038032Speter		  case 'm':
15138032Speter			map->map_mflags |= MF_MATCHONLY;
15238032Speter			break;
15338032Speter
15438032Speter		  case 'A':
15538032Speter			map->map_mflags |= MF_APPEND;
15638032Speter			break;
15738032Speter
15838032Speter		  case 'q':
15938032Speter			map->map_mflags |= MF_KEEPQUOTES;
16038032Speter			break;
16138032Speter
16238032Speter		  case 'a':
16338032Speter			map->map_app = ++p;
16438032Speter			break;
16538032Speter
16638032Speter		  case 'T':
16738032Speter			map->map_tapp = ++p;
16838032Speter			break;
16938032Speter
17038032Speter		  case 'k':
17138032Speter			while (isascii(*++p) && isspace(*p))
17238032Speter				continue;
17338032Speter			map->map_keycolnm = p;
17438032Speter			break;
17538032Speter
17638032Speter		  case 'v':
17738032Speter			while (isascii(*++p) && isspace(*p))
17838032Speter				continue;
17938032Speter			map->map_valcolnm = p;
18038032Speter			break;
18138032Speter
18238032Speter		  case 'z':
18338032Speter			if (*++p != '\\')
18438032Speter				map->map_coldelim = *p;
18538032Speter			else
18638032Speter			{
18738032Speter				switch (*++p)
18838032Speter				{
18938032Speter				  case 'n':
19038032Speter					map->map_coldelim = '\n';
19138032Speter					break;
19238032Speter
19338032Speter				  case 't':
19438032Speter					map->map_coldelim = '\t';
19538032Speter					break;
19638032Speter
19738032Speter				  default:
19838032Speter					map->map_coldelim = '\\';
19938032Speter				}
20038032Speter			}
20138032Speter			break;
20238032Speter
20338032Speter		  case 't':
20438032Speter			map->map_mflags |= MF_NODEFER;
20538032Speter			break;
20638032Speter
20738032Speter#ifdef RESERVED_FOR_SUN
20838032Speter		  case 'd':
20938032Speter			map->map_mflags |= MF_DOMAIN_WIDE;
21038032Speter			break;
21138032Speter
21238032Speter		  case 's':
21338032Speter			/* info type */
21438032Speter			break;
21538032Speter#endif
21638032Speter		}
21738032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
21838032Speter			p++;
21938032Speter		if (*p != '\0')
22038032Speter			*p++ = '\0';
22138032Speter	}
22238032Speter	if (map->map_app != NULL)
22338032Speter		map->map_app = newstr(map->map_app);
22438032Speter	if (map->map_tapp != NULL)
22538032Speter		map->map_tapp = newstr(map->map_tapp);
22638032Speter	if (map->map_keycolnm != NULL)
22738032Speter		map->map_keycolnm = newstr(map->map_keycolnm);
22838032Speter	if (map->map_valcolnm != NULL)
22938032Speter		map->map_valcolnm = newstr(map->map_valcolnm);
23038032Speter
23138032Speter	if (*p != '\0')
23238032Speter	{
23338032Speter		map->map_file = p;
23438032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
23538032Speter			p++;
23638032Speter		if (*p != '\0')
23738032Speter			*p++ = '\0';
23838032Speter		map->map_file = newstr(map->map_file);
23938032Speter	}
24038032Speter
24138032Speter	while (*p != '\0' && isascii(*p) && isspace(*p))
24238032Speter		p++;
24338032Speter	if (*p != '\0')
24438032Speter		map->map_rebuild = newstr(p);
24538032Speter
24638032Speter	if (map->map_file == NULL &&
24738032Speter	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
24838032Speter	{
24938032Speter		syserr("No file name for %s map %s",
25038032Speter			map->map_class->map_cname, map->map_mname);
25138032Speter		return FALSE;
25238032Speter	}
25338032Speter	return TRUE;
25438032Speter}
25538032Speter/*
25638032Speter**  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
25738032Speter**
25838032Speter**	It also adds the map_app string.  It can be used as a utility
25938032Speter**	in the map_lookup method.
26038032Speter**
26138032Speter**	Parameters:
26238032Speter**		map -- the map that causes this.
26338032Speter**		s -- the string to rewrite, NOT necessarily null terminated.
26438032Speter**		slen -- the length of s.
26538032Speter**		av -- arguments to interpolate into buf.
26638032Speter**
26738032Speter**	Returns:
26838032Speter**		Pointer to rewritten result.  This is static data that
26938032Speter**		should be copied if it is to be saved!
27038032Speter**
27138032Speter**	Side Effects:
27238032Speter**		none.
27338032Speter*/
27438032Speter
27538032Speterchar *
27638032Spetermap_rewrite(map, s, slen, av)
27738032Speter	register MAP *map;
27838032Speter	register const char *s;
27938032Speter	size_t slen;
28038032Speter	char **av;
28138032Speter{
28238032Speter	register char *bp;
28338032Speter	register char c;
28438032Speter	char **avp;
28538032Speter	register char *ap;
28638032Speter	size_t l;
28738032Speter	size_t len;
28838032Speter	static size_t buflen = 0;
28938032Speter	static char *buf = NULL;
29038032Speter
29138032Speter	if (tTd(39, 1))
29238032Speter	{
29338032Speter		printf("map_rewrite(%.*s), av =", (int)slen, s);
29438032Speter		if (av == NULL)
29538032Speter			printf(" (nullv)");
29638032Speter		else
29738032Speter		{
29838032Speter			for (avp = av; *avp != NULL; avp++)
29938032Speter				printf("\n\t%s", *avp);
30038032Speter		}
30138032Speter		printf("\n");
30238032Speter	}
30338032Speter
30438032Speter	/* count expected size of output (can safely overestimate) */
30538032Speter	l = len = slen;
30638032Speter	if (av != NULL)
30738032Speter	{
30838032Speter		const char *sp = s;
30938032Speter
31038032Speter		while (l-- > 0 && (c = *sp++) != '\0')
31138032Speter		{
31238032Speter			if (c != '%')
31338032Speter				continue;
31438032Speter			if (l-- <= 0)
31538032Speter				break;
31638032Speter			c = *sp++;
31738032Speter			if (!(isascii(c) && isdigit(c)))
31838032Speter				continue;
31938032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
32038032Speter				continue;
32138032Speter			if (*avp == NULL)
32238032Speter				continue;
32338032Speter			len += strlen(*avp);
32438032Speter		}
32538032Speter	}
32638032Speter	if (map->map_app != NULL)
32738032Speter		len += strlen(map->map_app);
32838032Speter	if (buflen < ++len)
32938032Speter	{
33038032Speter		/* need to malloc additional space */
33138032Speter		buflen = len;
33238032Speter		if (buf != NULL)
33338032Speter			free(buf);
33438032Speter		buf = xalloc(buflen);
33538032Speter	}
33638032Speter
33738032Speter	bp = buf;
33838032Speter	if (av == NULL)
33938032Speter	{
34038032Speter		bcopy(s, bp, slen);
34138032Speter		bp += slen;
34238032Speter	}
34338032Speter	else
34438032Speter	{
34538032Speter		while (slen-- > 0 && (c = *s++) != '\0')
34638032Speter		{
34738032Speter			if (c != '%')
34838032Speter			{
34938032Speter  pushc:
35038032Speter				*bp++ = c;
35138032Speter				continue;
35238032Speter			}
35338032Speter			if (slen-- <= 0 || (c = *s++) == '\0')
35438032Speter				c = '%';
35538032Speter			if (c == '%')
35638032Speter				goto pushc;
35738032Speter			if (!(isascii(c) && isdigit(c)))
35838032Speter			{
35938032Speter				*bp++ = '%';
36038032Speter				goto pushc;
36138032Speter			}
36238032Speter			for (avp = av; --c >= '0' && *avp != NULL; avp++)
36338032Speter				continue;
36438032Speter			if (*avp == NULL)
36538032Speter				continue;
36638032Speter
36738032Speter			/* transliterate argument into output string */
36838032Speter			for (ap = *avp; (c = *ap++) != '\0'; )
36938032Speter				*bp++ = c;
37038032Speter		}
37138032Speter	}
37238032Speter	if (map->map_app != NULL)
37338032Speter		strcpy(bp, map->map_app);
37438032Speter	else
37538032Speter		*bp = '\0';
37638032Speter	if (tTd(39, 1))
37738032Speter		printf("map_rewrite => %s\n", buf);
37838032Speter	return buf;
37938032Speter}
38038032Speter/*
38138032Speter**  INITMAPS -- initialize for aliasing
38238032Speter**
38338032Speter**	Parameters:
38438032Speter**		rebuild -- if TRUE, this rebuilds the cached versions.
38538032Speter**		e -- current envelope.
38638032Speter**
38738032Speter**	Returns:
38838032Speter**		none.
38938032Speter**
39038032Speter**	Side Effects:
39138032Speter**		initializes aliases:
39238032Speter**		if alias database:  opens the database.
39338032Speter**		if no database available: reads aliases into the symbol table.
39438032Speter*/
39538032Speter
39638032Spetervoid
39738032Speterinitmaps(rebuild, e)
39838032Speter	bool rebuild;
39938032Speter	register ENVELOPE *e;
40038032Speter{
40138032Speter	extern void map_init __P((STAB *, int));
40238032Speter
40338032Speter#if XDEBUG
40438032Speter	checkfd012("entering initmaps");
40538032Speter#endif
40638032Speter	CurEnv = e;
40738032Speter
40838032Speter	stabapply(map_init, 0);
40938032Speter	stabapply(map_init, rebuild ? 2 : 1);
41038032Speter#if XDEBUG
41138032Speter	checkfd012("exiting initmaps");
41238032Speter#endif
41338032Speter}
41438032Speter
41538032Spetervoid
41638032Spetermap_init(s, pass)
41738032Speter	register STAB *s;
41838032Speter	int pass;
41938032Speter{
42038032Speter	bool rebuildable;
42138032Speter	register MAP *map;
42238032Speter
42338032Speter	/* has to be a map */
42438032Speter	if (s->s_type != ST_MAP)
42538032Speter		return;
42638032Speter
42738032Speter	map = &s->s_map;
42838032Speter	if (!bitset(MF_VALID, map->map_mflags))
42938032Speter		return;
43038032Speter
43138032Speter	if (tTd(38, 2))
43238032Speter		printf("map_init(%s:%s, %s, %d)\n",
43338032Speter			map->map_class->map_cname == NULL ? "NULL" :
43438032Speter				map->map_class->map_cname,
43538032Speter			map->map_mname == NULL ? "NULL" : map->map_mname,
43638032Speter			map->map_file == NULL ? "NULL" : map->map_file,
43738032Speter			pass);
43838032Speter
43938032Speter	/*
44038032Speter	** Pass 0 opens all non-rebuildable maps.
44138032Speter	** Pass 1 opens all rebuildable maps for read.
44238032Speter	** Pass 2 rebuilds all rebuildable maps.
44338032Speter	*/
44438032Speter
44538032Speter	rebuildable = (bitset(MF_ALIAS, map->map_mflags) &&
44638032Speter		       bitset(MCF_REBUILDABLE, map->map_class->map_cflags));
44738032Speter
44838032Speter	if ((pass == 0 && rebuildable) ||
44938032Speter	    ((pass == 1 || pass == 2) && !rebuildable))
45038032Speter	{
45138032Speter		if (tTd(38, 3))
45238032Speter			printf("\twrong pass (pass = %d, rebuildable = %d)\n",
45338032Speter			       pass, rebuildable);
45438032Speter		return;
45538032Speter	}
45638032Speter
45738032Speter	/* if already open, close it (for nested open) */
45838032Speter	if (bitset(MF_OPEN, map->map_mflags))
45938032Speter	{
46038032Speter		map->map_class->map_close(map);
46138032Speter		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
46238032Speter	}
46338032Speter
46438032Speter	if (pass == 2)
46538032Speter	{
46638032Speter		(void) rebuildaliases(map, FALSE);
46738032Speter		return;
46838032Speter	}
46938032Speter
47038032Speter	if (map->map_class->map_open(map, O_RDONLY))
47138032Speter	{
47238032Speter		if (tTd(38, 4))
47338032Speter			printf("\t%s:%s %s: valid\n",
47438032Speter				map->map_class->map_cname == NULL ? "NULL" :
47538032Speter					map->map_class->map_cname,
47638032Speter				map->map_mname == NULL ? "NULL" :
47738032Speter					map->map_mname,
47838032Speter				map->map_file == NULL ? "NULL" :
47938032Speter					map->map_file);
48038032Speter		map->map_mflags |= MF_OPEN;
48138032Speter	}
48238032Speter	else
48338032Speter	{
48438032Speter		if (tTd(38, 4))
48538032Speter			printf("\t%s:%s %s: invalid: %s\n",
48638032Speter				map->map_class->map_cname == NULL ? "NULL" :
48738032Speter					map->map_class->map_cname,
48838032Speter				map->map_mname == NULL ? "NULL" :
48938032Speter					map->map_mname,
49038032Speter				map->map_file == NULL ? "NULL" :
49138032Speter					map->map_file,
49238032Speter				errstring(errno));
49338032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
49438032Speter		{
49538032Speter			extern MAPCLASS BogusMapClass;
49638032Speter
49738032Speter			map->map_class = &BogusMapClass;
49838032Speter			map->map_mflags |= MF_OPEN;
49938032Speter		}
50038032Speter	}
50138032Speter}
50238032Speter/*
50338032Speter**  GETCANONNAME -- look up name using service switch
50438032Speter**
50538032Speter**	Parameters:
50638032Speter**		host -- the host name to look up.
50738032Speter**		hbsize -- the size of the host buffer.
50838032Speter**		trymx -- if set, try MX records.
50938032Speter**
51038032Speter**	Returns:
51138032Speter**		TRUE -- if the host was found.
51238032Speter**		FALSE -- otherwise.
51338032Speter*/
51438032Speter
51538032Speterbool
51638032Spetergetcanonname(host, hbsize, trymx)
51738032Speter	char *host;
51838032Speter	int hbsize;
51938032Speter	bool trymx;
52038032Speter{
52138032Speter	int nmaps;
52238032Speter	int mapno;
52338032Speter	bool found = FALSE;
52438032Speter	bool got_tempfail = FALSE;
52538032Speter	auto int stat;
52638032Speter	char *maptype[MAXMAPSTACK];
52738032Speter	short mapreturn[MAXMAPACTIONS];
52838032Speter
52938032Speter	nmaps = switch_map_find("hosts", maptype, mapreturn);
53038032Speter	for (mapno = 0; mapno < nmaps; mapno++)
53138032Speter	{
53238032Speter		int i;
53338032Speter
53438032Speter		if (tTd(38, 20))
53538032Speter			printf("getcanonname(%s), trying %s\n",
53638032Speter				host, maptype[mapno]);
53738032Speter		if (strcmp("files", maptype[mapno]) == 0)
53838032Speter		{
53938032Speter			extern bool text_getcanonname __P((char *, int, int *));
54038032Speter
54138032Speter			found = text_getcanonname(host, hbsize, &stat);
54238032Speter		}
54338032Speter#ifdef NIS
54438032Speter		else if (strcmp("nis", maptype[mapno]) == 0)
54538032Speter		{
54638032Speter			extern bool nis_getcanonname __P((char *, int, int *));
54738032Speter
54838032Speter			found = nis_getcanonname(host, hbsize, &stat);
54938032Speter		}
55038032Speter#endif
55138032Speter#ifdef NISPLUS
55238032Speter		else if (strcmp("nisplus", maptype[mapno]) == 0)
55338032Speter		{
55438032Speter			extern bool nisplus_getcanonname __P((char *, int, int *));
55538032Speter
55638032Speter			found = nisplus_getcanonname(host, hbsize, &stat);
55738032Speter		}
55838032Speter#endif
55938032Speter#if NAMED_BIND
56038032Speter		else if (strcmp("dns", maptype[mapno]) == 0)
56138032Speter		{
56238032Speter			extern bool dns_getcanonname __P((char *, int, bool, int *));
56338032Speter
56438032Speter			found = dns_getcanonname(host, hbsize, trymx, &stat);
56538032Speter		}
56638032Speter#endif
56738032Speter#if NETINFO
56838032Speter		else if (strcmp("netinfo", maptype[mapno]) == 0)
56938032Speter		{
57038032Speter			extern bool ni_getcanonname __P((char *, int, int *));
57138032Speter
57238032Speter			found = ni_getcanonname(host, hbsize, &stat);
57338032Speter		}
57438032Speter#endif
57538032Speter		else
57638032Speter		{
57738032Speter			found = FALSE;
57838032Speter			stat = EX_UNAVAILABLE;
57938032Speter		}
58038032Speter
58138032Speter		/*
58238032Speter		**  Heuristic: if $m is not set, we are running during system
58338032Speter		**  startup.  In this case, when a name is apparently found
58438032Speter		**  but has no dot, treat is as not found.  This avoids
58538032Speter		**  problems if /etc/hosts has no FQDN but is listed first
58638032Speter		**  in the service switch.
58738032Speter		*/
58838032Speter
58938032Speter		if (found &&
59038032Speter		    (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
59138032Speter			break;
59238032Speter
59338032Speter		/* see if we should continue */
59438032Speter		if (stat == EX_TEMPFAIL)
59538032Speter		{
59638032Speter			i = MA_TRYAGAIN;
59738032Speter			got_tempfail = TRUE;
59838032Speter		}
59938032Speter		else if (stat == EX_NOTFOUND)
60038032Speter			i = MA_NOTFOUND;
60138032Speter		else
60238032Speter			i = MA_UNAVAIL;
60338032Speter		if (bitset(1 << mapno, mapreturn[i]))
60438032Speter			break;
60538032Speter	}
60638032Speter
60738032Speter	if (found)
60838032Speter	{
60938032Speter		char *d;
61038032Speter
61138032Speter		if (tTd(38, 20))
61238032Speter			printf("getcanonname(%s), found\n", host);
61338032Speter
61438032Speter		/*
61538032Speter		**  If returned name is still single token, compensate
61638032Speter		**  by tagging on $m.  This is because some sites set
61738032Speter		**  up their DNS or NIS databases wrong.
61838032Speter		*/
61938032Speter
62038032Speter		if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
62138032Speter		{
62238032Speter			d = macvalue('m', CurEnv);
62338032Speter			if (d != NULL &&
62438032Speter			    hbsize > (int) (strlen(host) + strlen(d) + 1))
62538032Speter			{
62638032Speter				if (host[strlen(host) - 1] != '.')
62738032Speter					strcat(host, ".");
62838032Speter				strcat(host, d);
62938032Speter			}
63038032Speter			else
63138032Speter			{
63238032Speter				return FALSE;
63338032Speter			}
63438032Speter		}
63538032Speter		return TRUE;
63638032Speter	}
63738032Speter
63838032Speter	if (tTd(38, 20))
63938032Speter		printf("getcanonname(%s), failed, stat=%d\n", host, stat);
64038032Speter
64138032Speter#if NAMED_BIND
64238032Speter	if (got_tempfail)
64338032Speter		h_errno = TRY_AGAIN;
64438032Speter	else
64538032Speter		h_errno = HOST_NOT_FOUND;
64638032Speter#endif
64738032Speter
64838032Speter	return FALSE;
64938032Speter}
65038032Speter/*
65138032Speter**  EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
65238032Speter**
65338032Speter**	Parameters:
65438032Speter**		name -- the name against which to match.
65538032Speter**		line -- the /etc/hosts line.
65638032Speter**		cbuf -- the location to store the result.
65738032Speter**		cbuflen -- the size of cbuf.
65838032Speter**
65938032Speter**	Returns:
66038032Speter**		TRUE -- if the line matched the desired name.
66138032Speter**		FALSE -- otherwise.
66238032Speter*/
66338032Speter
66438032Speterbool
66538032Speterextract_canonname(name, line, cbuf, cbuflen)
66638032Speter	char *name;
66738032Speter	char *line;
66838032Speter	char cbuf[];
66938032Speter	int cbuflen;
67038032Speter{
67138032Speter	int i;
67238032Speter	char *p;
67338032Speter	bool found = FALSE;
67438032Speter	extern char *get_column __P((char *, int, char, char *, int));
67538032Speter
67638032Speter	cbuf[0] = '\0';
67738032Speter	if (line[0] == '#')
67838032Speter		return FALSE;
67938032Speter
68038032Speter	for (i = 1; ; i++)
68138032Speter	{
68238032Speter		char nbuf[MAXNAME + 1];
68338032Speter
68438032Speter		p = get_column(line, i, '\0', nbuf, sizeof nbuf);
68538032Speter		if (p == NULL)
68638032Speter			break;
68738032Speter		if (*p == '\0')
68838032Speter			continue;
68938032Speter		if (cbuf[0] == '\0' ||
69038032Speter		    (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
69138032Speter		{
69238032Speter			snprintf(cbuf, cbuflen, "%s", p);
69338032Speter		}
69438032Speter		if (strcasecmp(name, p) == 0)
69538032Speter			found = TRUE;
69638032Speter	}
69738032Speter	if (found && strchr(cbuf, '.') == NULL)
69838032Speter	{
69938032Speter		/* try to add a domain on the end of the name */
70038032Speter		char *domain = macvalue('m', CurEnv);
70138032Speter
70238032Speter		if (domain != NULL &&
70338032Speter		    strlen(domain) + strlen(cbuf) + 1 < cbuflen)
70438032Speter		{
70538032Speter			p = &cbuf[strlen(cbuf)];
70638032Speter			*p++ = '.';
70738032Speter			strcpy(p, domain);
70838032Speter		}
70938032Speter	}
71038032Speter	return found;
71138032Speter}
71238032Speter/*
71338032Speter**  NDBM modules
71438032Speter*/
71538032Speter
71638032Speter#ifdef NDBM
71738032Speter
71838032Speter/*
71938032Speter**  NDBM_MAP_OPEN -- DBM-style map open
72038032Speter*/
72138032Speter
72238032Speterbool
72338032Speterndbm_map_open(map, mode)
72438032Speter	MAP *map;
72538032Speter	int mode;
72638032Speter{
72738032Speter	register DBM *dbm;
72838032Speter	struct stat st;
72938032Speter	int dfd;
73038032Speter	int pfd;
73138032Speter	int sff;
73238032Speter	int ret;
73338032Speter	int smode = S_IREAD;
73438032Speter	char dirfile[MAXNAME + 1];
73538032Speter	char pagfile[MAXNAME + 1];
73638032Speter	struct stat std, stp;
73738032Speter
73838032Speter	if (tTd(38, 2))
73938032Speter		printf("ndbm_map_open(%s, %s, %d)\n",
74038032Speter			map->map_mname, map->map_file, mode);
74138032Speter	map->map_lockfd = -1;
74238032Speter	mode &= O_ACCMODE;
74338032Speter
74438032Speter	/* do initial file and directory checks */
74538032Speter	snprintf(dirfile, sizeof dirfile, "%s.dir", map->map_file);
74638032Speter	snprintf(pagfile, sizeof pagfile, "%s.pag", map->map_file);
74738032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
74838032Speter	if (mode == O_RDWR)
74938032Speter	{
75038032Speter		sff |= SFF_CREAT;
75138032Speter		if (!bitset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
75238032Speter			sff |= SFF_NOSLINK;
75338032Speter		if (!bitset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
75438032Speter			sff |= SFF_NOHLINK;
75538032Speter		smode = S_IWRITE;
75638032Speter	}
75738032Speter	else
75838032Speter	{
75938032Speter		if (!bitset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
76038032Speter			sff |= SFF_NOWLINK;
76138032Speter	}
76238032Speter	if (!bitset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
76338032Speter		sff |= SFF_SAFEDIRPATH;
76438032Speter	ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
76538032Speter			    sff, smode, &std);
76638032Speter	if (ret == 0)
76738032Speter		ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
76838032Speter			       sff, smode, &stp);
76938032Speter	if (ret == ENOENT && AutoRebuild &&
77038032Speter	    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
77138032Speter	    (bitset(MF_IMPL_NDBM, map->map_mflags) ||
77238032Speter	     bitset(MF_ALIAS, map->map_mflags)) &&
77338032Speter	    mode == O_RDONLY)
77438032Speter	{
77538032Speter		bool impl = bitset(MF_IMPL_NDBM, map->map_mflags);
77638032Speter		extern bool impl_map_open __P((MAP *, int));
77738032Speter
77838032Speter		/* may be able to rebuild */
77938032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
78038032Speter		if (!rebuildaliases(map, TRUE))
78138032Speter			return FALSE;
78238032Speter		if (impl)
78338032Speter			return impl_map_open(map, O_RDONLY);
78438032Speter		else
78538032Speter			return ndbm_map_open(map, O_RDONLY);
78638032Speter	}
78738032Speter	if (ret != 0)
78838032Speter	{
78938032Speter		char *prob = "unsafe";
79038032Speter
79138032Speter		/* cannot open this map */
79238032Speter		if (ret == ENOENT)
79338032Speter			prob = "missing";
79438032Speter		if (tTd(38, 2))
79538032Speter			printf("\t%s map file: %d\n", prob, ret);
79638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
79738032Speter			syserr("dbm map \"%s\": %s map file %s",
79838032Speter				map->map_mname, prob, map->map_file);
79938032Speter		return FALSE;
80038032Speter	}
80138032Speter	if (std.st_mode == ST_MODE_NOFILE)
80238032Speter		mode |= O_CREAT|O_EXCL;
80338032Speter
80438032Speter#if LOCK_ON_OPEN
80538032Speter	if (mode == O_RDONLY)
80638032Speter		mode |= O_SHLOCK;
80738032Speter	else
80838032Speter		mode |= O_TRUNC|O_EXLOCK;
80938032Speter#else
81038032Speter	if ((mode & O_ACCMODE) == O_RDWR)
81138032Speter	{
81238032Speter# if NOFTRUNCATE
81338032Speter		/*
81438032Speter		**  Warning: race condition.  Try to lock the file as
81538032Speter		**  quickly as possible after opening it.
81638032Speter		**	This may also have security problems on some systems,
81738032Speter		**	but there isn't anything we can do about it.
81838032Speter		*/
81938032Speter
82038032Speter		mode |= O_TRUNC;
82138032Speter# else
82238032Speter		/*
82338032Speter		**  This ugly code opens the map without truncating it,
82438032Speter		**  locks the file, then truncates it.  Necessary to
82538032Speter		**  avoid race conditions.
82638032Speter		*/
82738032Speter
82838032Speter		int dirfd;
82938032Speter		int pagfd;
83038032Speter		int sff = SFF_CREAT|SFF_OPENASROOT;
83138032Speter
83238032Speter		if (!bitset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
83338032Speter			sff |= SFF_NOSLINK;
83438032Speter		if (!bitset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
83538032Speter			sff |= SFF_NOHLINK;
83638032Speter
83738032Speter		dirfd = safeopen(dirfile, mode, DBMMODE, sff);
83838032Speter		pagfd = safeopen(pagfile, mode, DBMMODE, sff);
83938032Speter
84038032Speter		if (dirfd < 0 || pagfd < 0)
84138032Speter		{
84238032Speter			int save_errno = errno;
84338032Speter
84438032Speter			if (dirfd >= 0)
84538032Speter				(void) close(dirfd);
84638032Speter			if (pagfd >= 0)
84738032Speter				(void) close(pagfd);
84838032Speter			errno = save_errno;
84938032Speter			syserr("ndbm_map_open: cannot create database %s",
85038032Speter				map->map_file);
85138032Speter			return FALSE;
85238032Speter		}
85338032Speter		if (ftruncate(dirfd, (off_t) 0) < 0 ||
85438032Speter		    ftruncate(pagfd, (off_t) 0) < 0)
85538032Speter		{
85638032Speter			int save_errno = errno;
85738032Speter
85838032Speter			(void) close(dirfd);
85938032Speter			(void) close(pagfd);
86038032Speter			errno = save_errno;
86138032Speter			syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
86238032Speter				map->map_file);
86338032Speter			return FALSE;
86438032Speter		}
86538032Speter
86638032Speter		/* if new file, get "before" bits for later filechanged check */
86738032Speter		if (std.st_mode == ST_MODE_NOFILE &&
86838032Speter		    (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
86938032Speter		{
87038032Speter			int save_errno = errno;
87138032Speter
87238032Speter			(void) close(dirfd);
87338032Speter			(void) close(pagfd);
87438032Speter			errno = save_errno;
87538032Speter			syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
87638032Speter				map->map_file);
87738032Speter			return FALSE;
87838032Speter		}
87938032Speter
88038032Speter		/* have to save the lock for the duration (bletch) */
88138032Speter		map->map_lockfd = dirfd;
88238032Speter		close(pagfd);
88338032Speter
88438032Speter		/* twiddle bits for dbm_open */
88538032Speter		mode &= ~(O_CREAT|O_EXCL);
88638032Speter# endif
88738032Speter	}
88838032Speter#endif
88938032Speter
89038032Speter	/* open the database */
89138032Speter	dbm = dbm_open(map->map_file, mode, DBMMODE);
89238032Speter	if (dbm == NULL)
89338032Speter	{
89438032Speter		int save_errno = errno;
89538032Speter
89638032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
89738032Speter		    aliaswait(map, ".pag", FALSE))
89838032Speter			return TRUE;
89938032Speter#if !LOCK_ON_OPEN && !NOFTRUNCATE
90038032Speter		if (map->map_lockfd >= 0)
90138032Speter			close(map->map_lockfd);
90238032Speter#endif
90338032Speter		errno = save_errno;
90438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
90538032Speter			syserr("Cannot open DBM database %s", map->map_file);
90638032Speter		return FALSE;
90738032Speter	}
90838032Speter	dfd = dbm_dirfno(dbm);
90938032Speter	pfd = dbm_pagfno(dbm);
91038032Speter	if (dfd == pfd)
91138032Speter	{
91238032Speter		/* heuristic: if files are linked, this is actually gdbm */
91338032Speter		dbm_close(dbm);
91438032Speter#if !LOCK_ON_OPEN && !NOFTRUNCATE
91538032Speter		if (map->map_lockfd >= 0)
91638032Speter			close(map->map_lockfd);
91738032Speter#endif
91838032Speter		errno = 0;
91938032Speter		syserr("dbm map \"%s\": cannot support GDBM",
92038032Speter			map->map_mname);
92138032Speter		return FALSE;
92238032Speter	}
92338032Speter
92438032Speter	if (filechanged(dirfile, dfd, &std) ||
92538032Speter	    filechanged(pagfile, pfd, &stp))
92638032Speter	{
92738032Speter		int save_errno = errno;
92838032Speter
92938032Speter		dbm_close(dbm);
93038032Speter#if !LOCK_ON_OPEN && !NOFTRUNCATE
93138032Speter		if (map->map_lockfd >= 0)
93238032Speter			close(map->map_lockfd);
93338032Speter#endif
93438032Speter		errno = save_errno;
93538032Speter		syserr("ndbm_map_open(%s): file changed after open",
93638032Speter			map->map_file);
93738032Speter		return FALSE;
93838032Speter	}
93938032Speter
94038032Speter	map->map_db1 = (ARBPTR_T) dbm;
94138032Speter	if (mode == O_RDONLY)
94238032Speter	{
94338032Speter#if LOCK_ON_OPEN
94438032Speter		if (dfd >= 0)
94538032Speter			(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
94638032Speter		if (pfd >= 0)
94738032Speter			(void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
94838032Speter#endif
94938032Speter		if (bitset(MF_ALIAS, map->map_mflags) &&
95038032Speter		    !aliaswait(map, ".pag", TRUE))
95138032Speter			return FALSE;
95238032Speter	}
95338032Speter	else
95438032Speter	{
95538032Speter		map->map_mflags |= MF_LOCKED;
95638032Speter		if (geteuid() == 0 && TrustedFileUid != 0)
95738032Speter		{
95838032Speter			if (fchown(dfd, TrustedFileUid, -1) < 0 ||
95938032Speter			    fchown(pfd, TrustedFileUid, -1) < 0)
96038032Speter			{
96138032Speter				int err = errno;
96238032Speter
96338032Speter				sm_syslog(LOG_ALERT, NOQID,
96438032Speter					  "ownership change on %s failed: %s",
96538032Speter					  map->map_file, errstring(err));
96638032Speter				message("050 ownership change on %s failed: %s",
96738032Speter					map->map_file, errstring(err));
96838032Speter			}
96938032Speter		}
97038032Speter	}
97138032Speter	if (fstat(dfd, &st) >= 0)
97238032Speter		map->map_mtime = st.st_mtime;
97338032Speter	return TRUE;
97438032Speter}
97538032Speter
97638032Speter
97738032Speter/*
97838032Speter**  NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
97938032Speter*/
98038032Speter
98138032Speterchar *
98238032Speterndbm_map_lookup(map, name, av, statp)
98338032Speter	MAP *map;
98438032Speter	char *name;
98538032Speter	char **av;
98638032Speter	int *statp;
98738032Speter{
98838032Speter	datum key, val;
98938032Speter	int fd;
99038032Speter	char keybuf[MAXNAME + 1];
99138032Speter	struct stat stbuf;
99238032Speter
99338032Speter	if (tTd(38, 20))
99438032Speter		printf("ndbm_map_lookup(%s, %s)\n",
99538032Speter			map->map_mname, name);
99638032Speter
99738032Speter	key.dptr = name;
99838032Speter	key.dsize = strlen(name);
99938032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
100038032Speter	{
100138032Speter		if (key.dsize > sizeof keybuf - 1)
100238032Speter			key.dsize = sizeof keybuf - 1;
100338032Speter		bcopy(key.dptr, keybuf, key.dsize);
100438032Speter		keybuf[key.dsize] = '\0';
100538032Speter		makelower(keybuf);
100638032Speter		key.dptr = keybuf;
100738032Speter	}
100838032Speterlockdbm:
100938032Speter	fd = dbm_dirfno((DBM *) map->map_db1);
101038032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
101138032Speter		(void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
101238032Speter	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
101338032Speter	{
101438032Speter		/* Reopen the database to sync the cache */
101538032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
101638032Speter								 : O_RDONLY;
101738032Speter
101838032Speter		map->map_class->map_close(map);
101938032Speter		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
102038032Speter		if (map->map_class->map_open(map, omode))
102138032Speter		{
102238032Speter			map->map_mflags |= MF_OPEN;
102338032Speter			if ((omode && O_ACCMODE) == O_RDWR)
102438032Speter				map->map_mflags |= MF_WRITABLE;
102538032Speter			goto lockdbm;
102638032Speter		}
102738032Speter		else
102838032Speter		{
102938032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
103038032Speter			{
103138032Speter				extern MAPCLASS BogusMapClass;
103238032Speter
103338032Speter				*statp = EX_TEMPFAIL;
103438032Speter				map->map_class = &BogusMapClass;
103538032Speter				map->map_mflags |= MF_OPEN;
103638032Speter				syserr("Cannot reopen NDBM database %s",
103738032Speter					map->map_file);
103838032Speter			}
103938032Speter			return NULL;
104038032Speter		}
104138032Speter	}
104238032Speter	val.dptr = NULL;
104338032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
104438032Speter	{
104538032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
104638032Speter		if (val.dptr != NULL)
104738032Speter			map->map_mflags &= ~MF_TRY1NULL;
104838032Speter	}
104938032Speter	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
105038032Speter	{
105138032Speter		key.dsize++;
105238032Speter		val = dbm_fetch((DBM *) map->map_db1, key);
105338032Speter		if (val.dptr != NULL)
105438032Speter			map->map_mflags &= ~MF_TRY0NULL;
105538032Speter	}
105638032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
105738032Speter		(void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
105838032Speter	if (val.dptr == NULL)
105938032Speter		return NULL;
106038032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
106138032Speter		return map_rewrite(map, name, strlen(name), NULL);
106238032Speter	else
106338032Speter		return map_rewrite(map, val.dptr, val.dsize, av);
106438032Speter}
106538032Speter
106638032Speter
106738032Speter/*
106838032Speter**  NDBM_MAP_STORE -- store a datum in the database
106938032Speter*/
107038032Speter
107138032Spetervoid
107238032Speterndbm_map_store(map, lhs, rhs)
107338032Speter	register MAP *map;
107438032Speter	char *lhs;
107538032Speter	char *rhs;
107638032Speter{
107738032Speter	datum key;
107838032Speter	datum data;
107938032Speter	int stat;
108038032Speter	char keybuf[MAXNAME + 1];
108138032Speter
108238032Speter	if (tTd(38, 12))
108338032Speter		printf("ndbm_map_store(%s, %s, %s)\n",
108438032Speter			map->map_mname, lhs, rhs);
108538032Speter
108638032Speter	key.dsize = strlen(lhs);
108738032Speter	key.dptr = lhs;
108838032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
108938032Speter	{
109038032Speter		if (key.dsize > sizeof keybuf - 1)
109138032Speter			key.dsize = sizeof keybuf - 1;
109238032Speter		bcopy(key.dptr, keybuf, key.dsize);
109338032Speter		keybuf[key.dsize] = '\0';
109438032Speter		makelower(keybuf);
109538032Speter		key.dptr = keybuf;
109638032Speter	}
109738032Speter
109838032Speter	data.dsize = strlen(rhs);
109938032Speter	data.dptr = rhs;
110038032Speter
110138032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
110238032Speter	{
110338032Speter		key.dsize++;
110438032Speter		data.dsize++;
110538032Speter	}
110638032Speter
110738032Speter	stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
110838032Speter	if (stat > 0)
110938032Speter	{
111038032Speter		if (!bitset(MF_APPEND, map->map_mflags))
111138032Speter			message("050 Warning: duplicate alias name %s", lhs);
111238032Speter		else
111338032Speter		{
111438032Speter			static char *buf = NULL;
111538032Speter			static int bufsiz = 0;
111638032Speter			auto int xstat;
111738032Speter			datum old;
111838032Speter
111938032Speter			old.dptr = ndbm_map_lookup(map, key.dptr,
112038032Speter						   (char **)NULL, &xstat);
112138032Speter			if (old.dptr != NULL && *(char *) old.dptr != '\0')
112238032Speter			{
112338032Speter				old.dsize = strlen(old.dptr);
112438032Speter				if (data.dsize + old.dsize + 2 > bufsiz)
112538032Speter				{
112638032Speter					if (buf != NULL)
112738032Speter						(void) free(buf);
112838032Speter					bufsiz = data.dsize + old.dsize + 2;
112938032Speter					buf = xalloc(bufsiz);
113038032Speter				}
113138032Speter				snprintf(buf, bufsiz, "%s,%s",
113238032Speter					data.dptr, old.dptr);
113338032Speter				data.dsize = data.dsize + old.dsize + 1;
113438032Speter				data.dptr = buf;
113538032Speter				if (tTd(38, 9))
113638032Speter					printf("ndbm_map_store append=%s\n", data.dptr);
113738032Speter			}
113838032Speter		}
113938032Speter		stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
114038032Speter	}
114138032Speter	if (stat != 0)
114238032Speter		syserr("readaliases: dbm put (%s)", lhs);
114338032Speter}
114438032Speter
114538032Speter
114638032Speter/*
114738032Speter**  NDBM_MAP_CLOSE -- close the database
114838032Speter*/
114938032Speter
115038032Spetervoid
115138032Speterndbm_map_close(map)
115238032Speter	register MAP  *map;
115338032Speter{
115438032Speter	if (tTd(38, 9))
115538032Speter		printf("ndbm_map_close(%s, %s, %lx)\n",
115638032Speter			map->map_mname, map->map_file, map->map_mflags);
115738032Speter
115838032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
115938032Speter	{
116038032Speter#ifdef NDBM_YP_COMPAT
116138032Speter		bool inclnull;
116238032Speter		char buf[200];
116338032Speter
116438032Speter		inclnull = bitset(MF_INCLNULL, map->map_mflags);
116538032Speter		map->map_mflags &= ~MF_INCLNULL;
116638032Speter
116738032Speter		if (strstr(map->map_file, "/yp/") != NULL)
116838032Speter		{
116938032Speter			long save_mflags = map->map_mflags;
117038032Speter
117138032Speter			map->map_mflags |= MF_NOFOLDCASE;
117238032Speter
117338032Speter			(void) snprintf(buf, sizeof buf, "%010ld", curtime());
117438032Speter			ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
117538032Speter
117638032Speter			(void) gethostname(buf, sizeof buf);
117738032Speter			ndbm_map_store(map, "YP_MASTER_NAME", buf);
117838032Speter
117938032Speter			map->map_mflags = save_mflags;
118038032Speter		}
118138032Speter
118238032Speter		if (inclnull)
118338032Speter			map->map_mflags |= MF_INCLNULL;
118438032Speter#endif
118538032Speter
118638032Speter		/* write out the distinguished alias */
118738032Speter		ndbm_map_store(map, "@", "@");
118838032Speter	}
118938032Speter	dbm_close((DBM *) map->map_db1);
119038032Speter
119138032Speter	/* release lock (if needed) */
119238032Speter#if !LOCK_ON_OPEN
119338032Speter	if (map->map_lockfd >= 0)
119438032Speter		(void) close(map->map_lockfd);
119538032Speter#endif
119638032Speter}
119738032Speter
119838032Speter#endif
119938032Speter/*
120038032Speter**  NEWDB (Hash and BTree) Modules
120138032Speter*/
120238032Speter
120338032Speter#ifdef NEWDB
120438032Speter
120538032Speter/*
120638032Speter**  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
120738032Speter**
120838032Speter**	These do rather bizarre locking.  If you can lock on open,
120938032Speter**	do that to avoid the condition of opening a database that
121038032Speter**	is being rebuilt.  If you don't, we'll try to fake it, but
121138032Speter**	there will be a race condition.  If opening for read-only,
121238032Speter**	we immediately release the lock to avoid freezing things up.
121338032Speter**	We really ought to hold the lock, but guarantee that we won't
121438032Speter**	be pokey about it.  That's hard to do.
121538032Speter*/
121638032Speter
121738032Speter#if DB_VERSION_MAJOR < 2
121838032Speterextern bool	db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
121938032Speter#else
122038032Speterextern bool	db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
122138032Speter#endif
122238032Speter
122338032Speter/* these should be K line arguments */
122438032Speter#if DB_VERSION_MAJOR < 2
122538032Speter# define db_cachesize	cachesize
122638032Speter# define h_nelem	nelem
122738032Speter# ifndef DB_CACHE_SIZE
122838032Speter#  define DB_CACHE_SIZE	(1024 * 1024)	/* database memory cache size */
122938032Speter# endif
123038032Speter# ifndef DB_HASH_NELEM
123138032Speter#  define DB_HASH_NELEM	4096		/* (starting) size of hash table */
123238032Speter# endif
123338032Speter#endif
123438032Speter
123538032Speterbool
123638032Speterbt_map_open(map, mode)
123738032Speter	MAP *map;
123838032Speter	int mode;
123938032Speter{
124038032Speter#if DB_VERSION_MAJOR < 2
124138032Speter	BTREEINFO btinfo;
124238032Speter#else
124338032Speter	DB_INFO btinfo;
124438032Speter#endif
124538032Speter
124638032Speter	if (tTd(38, 2))
124738032Speter		printf("bt_map_open(%s, %s, %d)\n",
124838032Speter			map->map_mname, map->map_file, mode);
124938032Speter
125038032Speter	bzero(&btinfo, sizeof btinfo);
125138032Speter#ifdef DB_CACHE_SIZE
125238032Speter	btinfo.db_cachesize = DB_CACHE_SIZE;
125338032Speter#endif
125438032Speter	return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
125538032Speter}
125638032Speter
125738032Speterbool
125838032Speterhash_map_open(map, mode)
125938032Speter	MAP *map;
126038032Speter	int mode;
126138032Speter{
126238032Speter#if DB_VERSION_MAJOR < 2
126338032Speter	HASHINFO hinfo;
126438032Speter#else
126538032Speter	DB_INFO hinfo;
126638032Speter#endif
126738032Speter
126838032Speter	if (tTd(38, 2))
126938032Speter		printf("hash_map_open(%s, %s, %d)\n",
127038032Speter			map->map_mname, map->map_file, mode);
127138032Speter
127238032Speter	bzero(&hinfo, sizeof hinfo);
127338032Speter#ifdef DB_HASH_NELEM
127438032Speter	hinfo.h_nelem = DB_HASH_NELEM;
127538032Speter#endif
127638032Speter#ifdef DB_CACHE_SIZE
127738032Speter	hinfo.db_cachesize = DB_CACHE_SIZE;
127838032Speter#endif
127938032Speter	return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
128038032Speter}
128138032Speter
128238032Speterbool
128338032Speterdb_map_open(map, mode, mapclassname, dbtype, openinfo)
128438032Speter	MAP *map;
128538032Speter	int mode;
128638032Speter	char *mapclassname;
128738032Speter	DBTYPE dbtype;
128838032Speter#if DB_VERSION_MAJOR < 2
128938032Speter	const void *openinfo;
129038032Speter#else
129138032Speter	DB_INFO *openinfo;
129238032Speter#endif
129338032Speter{
129438032Speter	DB *db = NULL;
129538032Speter	int i;
129638032Speter	int omode;
129738032Speter	int smode = S_IREAD;
129838032Speter	int fd;
129938032Speter	int sff;
130038032Speter	int saveerrno;
130138032Speter	struct stat st;
130238032Speter	char buf[MAXNAME + 1];
130338032Speter
130438032Speter	/* do initial file and directory checks */
130538032Speter	snprintf(buf, sizeof buf - 3, "%s", map->map_file);
130638032Speter	i = strlen(buf);
130738032Speter	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
130838032Speter		(void) strcat(buf, ".db");
130938032Speter
131038032Speter	mode &= O_ACCMODE;
131138032Speter	omode = mode;
131238032Speter
131338032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
131438032Speter	if (mode == O_RDWR)
131538032Speter	{
131638032Speter		sff |= SFF_CREAT;
131738032Speter		if (!bitset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
131838032Speter			sff |= SFF_NOSLINK;
131938032Speter		if (!bitset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
132038032Speter			sff |= SFF_NOHLINK;
132138032Speter		smode = S_IWRITE;
132238032Speter	}
132338032Speter	else
132438032Speter	{
132538032Speter		if (!bitset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
132638032Speter			sff |= SFF_NOWLINK;
132738032Speter	}
132838032Speter	if (!bitset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
132938032Speter		sff |= SFF_SAFEDIRPATH;
133038032Speter	i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
133138032Speter	if (i == ENOENT && AutoRebuild &&
133238032Speter	    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
133338032Speter	    (bitset(MF_IMPL_HASH, map->map_mflags) ||
133438032Speter	     bitset(MF_ALIAS, map->map_mflags)) &&
133538032Speter	    mode == O_RDONLY)
133638032Speter	{
133738032Speter		bool impl = bitset(MF_IMPL_HASH, map->map_mflags);
133838032Speter		extern bool impl_map_open __P((MAP *, int));
133938032Speter
134038032Speter		/* may be able to rebuild */
134138032Speter		map->map_mflags &= ~MF_IMPL_HASH;
134238032Speter		if (!rebuildaliases(map, TRUE))
134338032Speter			return FALSE;
134438032Speter		if (impl)
134538032Speter			return impl_map_open(map, O_RDONLY);
134638032Speter		else
134738032Speter			return db_map_open(map, O_RDONLY, mapclassname,
134838032Speter					   dbtype, openinfo);
134938032Speter	}
135038032Speter
135138032Speter	if (i != 0)
135238032Speter	{
135338032Speter		char *prob = "unsafe";
135438032Speter
135538032Speter		/* cannot open this map */
135638032Speter		if (i == ENOENT)
135738032Speter			prob = "missing";
135838032Speter		if (tTd(38, 2))
135938032Speter			printf("\t%s map file: %s\n", prob, errstring(i));
136038032Speter		errno = i;
136138032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
136238032Speter			syserr("%s map \"%s\": %s map file %s",
136338032Speter				mapclassname, map->map_mname, prob, buf);
136438032Speter		return FALSE;
136538032Speter	}
136638032Speter	if (st.st_mode == ST_MODE_NOFILE)
136738032Speter		omode |= O_CREAT|O_EXCL;
136838032Speter
136938032Speter	map->map_lockfd = -1;
137038032Speter
137138032Speter#if LOCK_ON_OPEN
137238032Speter	if (mode == O_RDWR)
137338032Speter		omode |= O_TRUNC|O_EXLOCK;
137438032Speter	else
137538032Speter		omode |= O_SHLOCK;
137638032Speter#else
137738032Speter	/*
137838032Speter	**  Pre-lock the file to avoid race conditions.  In particular,
137938032Speter	**  since dbopen returns NULL if the file is zero length, we
138038032Speter	**  must have a locked instance around the dbopen.
138138032Speter	*/
138238032Speter
138338032Speter	fd = open(buf, omode, DBMMODE);
138438032Speter	if (fd < 0)
138538032Speter	{
138638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
138738032Speter			syserr("db_map_open: cannot pre-open database %s", buf);
138838032Speter		return FALSE;
138938032Speter	}
139038032Speter
139138032Speter	/* make sure no baddies slipped in just before the open... */
139238032Speter	if (filechanged(buf, fd, &st))
139338032Speter	{
139438032Speter		int save_errno = errno;
139538032Speter
139638032Speter		(void) close(fd);
139738032Speter		errno = save_errno;
139838032Speter		syserr("db_map_open(%s): file changed after pre-open", buf);
139938032Speter		return FALSE;
140038032Speter	}
140138032Speter
140238032Speter	/* if new file, get the "before" bits for later filechanged check */
140338032Speter	if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
140438032Speter	{
140538032Speter		int save_errno = errno;
140638032Speter
140738032Speter		(void) close(fd);
140838032Speter		errno = save_errno;
140938032Speter		syserr("db_map_open(%s): cannot fstat pre-opened file",
141038032Speter			buf);
141138032Speter		return FALSE;
141238032Speter	}
141338032Speter
141438032Speter	/* actually lock the pre-opened file */
141538032Speter	if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
141638032Speter		syserr("db_map_open: cannot lock %s", buf);
141738032Speter
141838032Speter	/* set up mode bits for dbopen */
141938032Speter	if (mode == O_RDWR)
142038032Speter		omode |= O_TRUNC;
142138032Speter	omode &= ~(O_EXCL|O_CREAT);
142238032Speter#endif
142338032Speter
142438032Speter#if DB_VERSION_MAJOR < 2
142538032Speter	db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
142638032Speter#else
142738032Speter	{
142838032Speter		int flags = 0;
142938032Speter
143038032Speter		if (mode == O_RDONLY)
143138032Speter			flags |= DB_RDONLY;
143238032Speter		if (bitset(O_CREAT, omode))
143338032Speter			flags |= DB_CREATE;
143438032Speter		if (bitset(O_TRUNC, omode))
143538032Speter			flags |= DB_TRUNCATE;
143638032Speter
143738032Speter		errno = db_open(buf, dbtype, flags, DBMMODE,
143838032Speter				NULL, openinfo, &db);
143938032Speter	}
144038032Speter#endif
144138032Speter	saveerrno = errno;
144238032Speter
144338032Speter#if !LOCK_ON_OPEN
144438032Speter	if (mode == O_RDWR)
144538032Speter		map->map_lockfd = fd;
144638032Speter	else
144738032Speter		(void) close(fd);
144838032Speter#endif
144938032Speter
145038032Speter	if (db == NULL)
145138032Speter	{
145238032Speter		if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
145338032Speter		    aliaswait(map, ".db", FALSE))
145438032Speter			return TRUE;
145538032Speter#if !LOCK_ON_OPEN
145638032Speter		if (map->map_lockfd >= 0)
145738032Speter			(void) close(map->map_lockfd);
145838032Speter#endif
145938032Speter		errno = saveerrno;
146038032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
146138032Speter			syserr("Cannot open %s database %s",
146238032Speter				mapclassname, buf);
146338032Speter		return FALSE;
146438032Speter	}
146538032Speter
146638032Speter#if DB_VERSION_MAJOR < 2
146738032Speter	fd = db->fd(db);
146838032Speter#else
146938032Speter	fd = -1;
147038032Speter	errno = db->fd(db, &fd);
147138032Speter#endif
147238032Speter	if (filechanged(buf, fd, &st))
147338032Speter	{
147438032Speter		int save_errno = errno;
147538032Speter
147638032Speter#if DB_VERSION_MAJOR < 2
147738032Speter		db->close(db);
147838032Speter#else
147938032Speter		errno = db->close(db, 0);
148038032Speter#endif
148138032Speter#if !LOCK_ON_OPEN
148238032Speter		if (map->map_lockfd >= 0)
148338032Speter			close(map->map_lockfd);
148438032Speter#endif
148538032Speter		errno = save_errno;
148638032Speter		syserr("db_map_open(%s): file changed after open", buf);
148738032Speter		return FALSE;
148838032Speter	}
148938032Speter
149038032Speter	if (mode == O_RDWR)
149138032Speter		map->map_mflags |= MF_LOCKED;
149238032Speter#if LOCK_ON_OPEN
149338032Speter	if (fd >= 0 && mode == O_RDONLY)
149438032Speter	{
149538032Speter		(void) lockfile(fd, buf, NULL, LOCK_UN);
149638032Speter	}
149738032Speter#endif
149838032Speter
149938032Speter	/* try to make sure that at least the database header is on disk */
150038032Speter	if (mode == O_RDWR)
150138032Speter	{
150238032Speter		(void) db->sync(db, 0);
150338032Speter		if (geteuid() == 0 && TrustedFileUid != 0)
150438032Speter		{
150538032Speter			if (fchown(fd, TrustedFileUid, -1) < 0)
150638032Speter			{
150738032Speter				int err = errno;
150838032Speter
150938032Speter				sm_syslog(LOG_ALERT, NOQID,
151038032Speter					  "ownership change on %s failed: %s",
151138032Speter					  buf, errstring(err));
151238032Speter				message("050 ownership change on %s failed: %s",
151338032Speter					buf, errstring(err));
151438032Speter			}
151538032Speter		}
151638032Speter	}
151738032Speter
151838032Speter	if (fd >= 0 && fstat(fd, &st) >= 0)
151938032Speter		map->map_mtime = st.st_mtime;
152038032Speter
152138032Speter	map->map_db2 = (ARBPTR_T) db;
152238032Speter	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
152338032Speter	    !aliaswait(map, ".db", TRUE))
152438032Speter		return FALSE;
152538032Speter	return TRUE;
152638032Speter}
152738032Speter
152838032Speter
152938032Speter/*
153038032Speter**  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
153138032Speter*/
153238032Speter
153338032Speterchar *
153438032Speterdb_map_lookup(map, name, av, statp)
153538032Speter	MAP *map;
153638032Speter	char *name;
153738032Speter	char **av;
153838032Speter	int *statp;
153938032Speter{
154038032Speter	DBT key, val;
154138032Speter	register DB *db = (DB *) map->map_db2;
154238032Speter	int i;
154338032Speter	int st;
154438032Speter	int saveerrno;
154538032Speter	int fd;
154638032Speter	struct stat stbuf;
154738032Speter	char keybuf[MAXNAME + 1];
154838032Speter	char buf[MAXNAME + 1];
154938032Speter
155038032Speter	bzero(&key, sizeof key);
155138032Speter	bzero(&val, sizeof val);
155238032Speter
155338032Speter	if (tTd(38, 20))
155438032Speter		printf("db_map_lookup(%s, %s)\n",
155538032Speter			map->map_mname, name);
155638032Speter
155738032Speter	i = strlen(map->map_file);
155838032Speter	if (i > MAXNAME)
155938032Speter		i = MAXNAME;
156038032Speter	strncpy(buf, map->map_file, i);
156138032Speter	buf[i] = '\0';
156238032Speter	if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
156338032Speter		buf[i - 3] = '\0';
156438032Speter
156538032Speter	key.size = strlen(name);
156638032Speter	if (key.size > sizeof keybuf - 1)
156738032Speter		key.size = sizeof keybuf - 1;
156838032Speter	key.data = keybuf;
156938032Speter	bcopy(name, keybuf, key.size);
157038032Speter	keybuf[key.size] = '\0';
157138032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
157238032Speter		makelower(keybuf);
157338032Speter  lockdb:
157438032Speter#if DB_VERSION_MAJOR < 2
157538032Speter	fd = db->fd(db);
157638032Speter#else
157738032Speter	fd = -1;
157838032Speter	errno = db->fd(db, &fd);
157938032Speter#endif
158038032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
158138032Speter		(void) lockfile(fd, buf, ".db", LOCK_SH);
158238032Speter	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
158338032Speter	{
158438032Speter		/* Reopen the database to sync the cache */
158538032Speter		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
158638032Speter								 : O_RDONLY;
158738032Speter
158838032Speter		map->map_class->map_close(map);
158938032Speter		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
159038032Speter		if (map->map_class->map_open(map, omode))
159138032Speter		{
159238032Speter			map->map_mflags |= MF_OPEN;
159338032Speter			if ((omode && O_ACCMODE) == O_RDWR)
159438032Speter				map->map_mflags |= MF_WRITABLE;
159538032Speter			db = (DB *) map->map_db2;
159638032Speter			goto lockdb;
159738032Speter		}
159838032Speter		else
159938032Speter		{
160038032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
160138032Speter			{
160238032Speter				extern MAPCLASS BogusMapClass;
160338032Speter
160438032Speter				*statp = EX_TEMPFAIL;
160538032Speter				map->map_class = &BogusMapClass;
160638032Speter				map->map_mflags |= MF_OPEN;
160738032Speter				syserr("Cannot reopen DB database %s",
160838032Speter					map->map_file);
160938032Speter			}
161038032Speter			return NULL;
161138032Speter		}
161238032Speter	}
161338032Speter
161438032Speter	st = 1;
161538032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
161638032Speter	{
161738032Speter#if DB_VERSION_MAJOR < 2
161838032Speter		st = db->get(db, &key, &val, 0);
161938032Speter#else
162038032Speter		errno = db->get(db, NULL, &key, &val, 0);
162138032Speter		switch (errno)
162238032Speter		{
162338032Speter		  case DB_NOTFOUND:
162438032Speter		  case DB_KEYEMPTY:
162538032Speter			st = 1;
162638032Speter			break;
162738032Speter
162838032Speter		  case 0:
162938032Speter			st = 0;
163038032Speter			break;
163138032Speter
163238032Speter		  default:
163338032Speter			st = -1;
163438032Speter			break;
163538032Speter		}
163638032Speter#endif
163738032Speter		if (st == 0)
163838032Speter			map->map_mflags &= ~MF_TRY1NULL;
163938032Speter	}
164038032Speter	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
164138032Speter	{
164238032Speter		key.size++;
164338032Speter#if DB_VERSION_MAJOR < 2
164438032Speter		st = db->get(db, &key, &val, 0);
164538032Speter#else
164638032Speter		errno = db->get(db, NULL, &key, &val, 0);
164738032Speter		switch (errno)
164838032Speter		{
164938032Speter		  case DB_NOTFOUND:
165038032Speter		  case DB_KEYEMPTY:
165138032Speter			st = 1;
165238032Speter			break;
165338032Speter
165438032Speter		  case 0:
165538032Speter			st = 0;
165638032Speter			break;
165738032Speter
165838032Speter		  default:
165938032Speter			st = -1;
166038032Speter			break;
166138032Speter		}
166238032Speter#endif
166338032Speter		if (st == 0)
166438032Speter			map->map_mflags &= ~MF_TRY0NULL;
166538032Speter	}
166638032Speter	saveerrno = errno;
166738032Speter	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
166838032Speter		(void) lockfile(fd, buf, ".db", LOCK_UN);
166938032Speter	if (st != 0)
167038032Speter	{
167138032Speter		errno = saveerrno;
167238032Speter		if (st < 0)
167338032Speter			syserr("db_map_lookup: get (%s)", name);
167438032Speter		return NULL;
167538032Speter	}
167638032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
167738032Speter		return map_rewrite(map, name, strlen(name), NULL);
167838032Speter	else
167938032Speter		return map_rewrite(map, val.data, val.size, av);
168038032Speter}
168138032Speter
168238032Speter
168338032Speter/*
168438032Speter**  DB_MAP_STORE -- store a datum in the NEWDB database
168538032Speter*/
168638032Speter
168738032Spetervoid
168838032Speterdb_map_store(map, lhs, rhs)
168938032Speter	register MAP *map;
169038032Speter	char *lhs;
169138032Speter	char *rhs;
169238032Speter{
169338032Speter	int stat;
169438032Speter	DBT key;
169538032Speter	DBT data;
169638032Speter	register DB *db = map->map_db2;
169738032Speter	char keybuf[MAXNAME + 1];
169838032Speter
169938032Speter	bzero(&key, sizeof key);
170038032Speter	bzero(&data, sizeof data);
170138032Speter
170238032Speter	if (tTd(38, 12))
170338032Speter		printf("db_map_store(%s, %s, %s)\n",
170438032Speter			map->map_mname, lhs, rhs);
170538032Speter
170638032Speter	key.size = strlen(lhs);
170738032Speter	key.data = lhs;
170838032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
170938032Speter	{
171038032Speter		if (key.size > sizeof keybuf - 1)
171138032Speter			key.size = sizeof keybuf - 1;
171238032Speter		bcopy(key.data, keybuf, key.size);
171338032Speter		keybuf[key.size] = '\0';
171438032Speter		makelower(keybuf);
171538032Speter		key.data = keybuf;
171638032Speter	}
171738032Speter
171838032Speter	data.size = strlen(rhs);
171938032Speter	data.data = rhs;
172038032Speter
172138032Speter	if (bitset(MF_INCLNULL, map->map_mflags))
172238032Speter	{
172338032Speter		key.size++;
172438032Speter		data.size++;
172538032Speter	}
172638032Speter
172738032Speter#if DB_VERSION_MAJOR < 2
172838032Speter	stat = db->put(db, &key, &data, R_NOOVERWRITE);
172938032Speter#else
173038032Speter	errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE);
173138032Speter	switch (errno)
173238032Speter	{
173338032Speter	  case DB_KEYEXIST:
173438032Speter		stat = 1;
173538032Speter		break;
173638032Speter
173738032Speter	  case 0:
173838032Speter		stat = 0;
173938032Speter		break;
174038032Speter
174138032Speter	  default:
174238032Speter		stat = -1;
174338032Speter		break;
174438032Speter	}
174538032Speter#endif
174638032Speter	if (stat > 0)
174738032Speter	{
174838032Speter		if (!bitset(MF_APPEND, map->map_mflags))
174938032Speter			message("050 Warning: duplicate alias name %s", lhs);
175038032Speter		else
175138032Speter		{
175238032Speter			static char *buf = NULL;
175338032Speter			static int bufsiz = 0;
175438032Speter			DBT old;
175538032Speter
175638032Speter			bzero(&old, sizeof old);
175738032Speter
175838032Speter			old.data = db_map_lookup(map, key.data,
175938032Speter						 (char **)NULL, &stat);
176038032Speter			if (old.data != NULL)
176138032Speter			{
176238032Speter				old.size = strlen(old.data);
176338032Speter				if (data.size + old.size + 2 > bufsiz)
176438032Speter				{
176538032Speter					if (buf != NULL)
176638032Speter						(void) free(buf);
176738032Speter					bufsiz = data.size + old.size + 2;
176838032Speter					buf = xalloc(bufsiz);
176938032Speter				}
177038032Speter				snprintf(buf, bufsiz, "%s,%s",
177138032Speter					(char *) data.data, (char *) old.data);
177238032Speter				data.size = data.size + old.size + 1;
177338032Speter				data.data = buf;
177438032Speter				if (tTd(38, 9))
177538032Speter					printf("db_map_store append=%s\n",
177638032Speter					       (char *) data.data);
177738032Speter			}
177838032Speter		}
177938032Speter#if DB_VERSION_MAJOR < 2
178038032Speter		stat = db->put(db, &key, &data, 0);
178138032Speter#else
178238032Speter		stat = errno = db->put(db, NULL, &key, &data, 0);
178338032Speter#endif
178438032Speter	}
178538032Speter	if (stat != 0)
178638032Speter		syserr("readaliases: db put (%s)", lhs);
178738032Speter}
178838032Speter
178938032Speter
179038032Speter/*
179138032Speter**  DB_MAP_CLOSE -- add distinguished entries and close the database
179238032Speter*/
179338032Speter
179438032Spetervoid
179538032Speterdb_map_close(map)
179638032Speter	MAP *map;
179738032Speter{
179838032Speter	register DB *db = map->map_db2;
179938032Speter
180038032Speter	if (tTd(38, 9))
180138032Speter		printf("db_map_close(%s, %s, %lx)\n",
180238032Speter			map->map_mname, map->map_file, map->map_mflags);
180338032Speter
180438032Speter	if (bitset(MF_WRITABLE, map->map_mflags))
180538032Speter	{
180638032Speter		/* write out the distinguished alias */
180738032Speter		db_map_store(map, "@", "@");
180838032Speter	}
180938032Speter
181038032Speter	(void) db->sync(db, 0);
181138032Speter
181238032Speter#if !LOCK_ON_OPEN
181338032Speter	if (map->map_lockfd >= 0)
181438032Speter		(void) close(map->map_lockfd);
181538032Speter#endif
181638032Speter
181738032Speter#if DB_VERSION_MAJOR < 2
181838032Speter	if (db->close(db) != 0)
181938032Speter#else
182038032Speter	if ((errno = db->close(db, 0)) != 0)
182138032Speter#endif
182238032Speter		syserr("readaliases: db close failure");
182338032Speter}
182438032Speter
182538032Speter#endif
182638032Speter/*
182738032Speter**  NIS Modules
182838032Speter*/
182938032Speter
183038032Speter# ifdef NIS
183138032Speter
183238032Speter# ifndef YPERR_BUSY
183338032Speter#  define YPERR_BUSY	16
183438032Speter# endif
183538032Speter
183638032Speter/*
183738032Speter**  NIS_MAP_OPEN -- open DBM map
183838032Speter*/
183938032Speter
184038032Speterbool
184138032Speternis_map_open(map, mode)
184238032Speter	MAP *map;
184338032Speter	int mode;
184438032Speter{
184538032Speter	int yperr;
184638032Speter	register char *p;
184738032Speter	auto char *vp;
184838032Speter	auto int vsize;
184938032Speter
185038032Speter	if (tTd(38, 2))
185138032Speter		printf("nis_map_open(%s, %s, %d)\n",
185238032Speter			map->map_mname, map->map_file, mode);
185338032Speter
185438032Speter	mode &= O_ACCMODE;
185538032Speter	if (mode != O_RDONLY)
185638032Speter	{
185738032Speter		/* issue a pseudo-error message */
185838032Speter#ifdef ENOSYS
185938032Speter		errno = ENOSYS;
186038032Speter#else
186138032Speter# ifdef EFTYPE
186238032Speter		errno = EFTYPE;
186338032Speter# else
186438032Speter		errno = ENXIO;
186538032Speter# endif
186638032Speter#endif
186738032Speter		return FALSE;
186838032Speter	}
186938032Speter
187038032Speter	p = strchr(map->map_file, '@');
187138032Speter	if (p != NULL)
187238032Speter	{
187338032Speter		*p++ = '\0';
187438032Speter		if (*p != '\0')
187538032Speter			map->map_domain = p;
187638032Speter	}
187738032Speter
187838032Speter	if (*map->map_file == '\0')
187938032Speter		map->map_file = "mail.aliases";
188038032Speter
188138032Speter	if (map->map_domain == NULL)
188238032Speter	{
188338032Speter		yperr = yp_get_default_domain(&map->map_domain);
188438032Speter		if (yperr != 0)
188538032Speter		{
188638032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
188738032Speter				syserr("421 NIS map %s specified, but NIS not running",
188838032Speter					map->map_file);
188938032Speter			return FALSE;
189038032Speter		}
189138032Speter	}
189238032Speter
189338032Speter	/* check to see if this map actually exists */
189438032Speter	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
189538032Speter			&vp, &vsize);
189638032Speter	if (tTd(38, 10))
189738032Speter		printf("nis_map_open: yp_match(@, %s, %s) => %s\n",
189838032Speter			map->map_domain, map->map_file, yperr_string(yperr));
189938032Speter	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
190038032Speter	{
190138032Speter		/*
190238032Speter		**  We ought to be calling aliaswait() here if this is an
190338032Speter		**  alias file, but powerful HP-UX NIS servers  apparently
190438032Speter		**  don't insert the @:@ token into the alias map when it
190538032Speter		**  is rebuilt, so aliaswait() just hangs.  I hate HP-UX.
190638032Speter		*/
190738032Speter
190838032Speter#if 0
190938032Speter		if (!bitset(MF_ALIAS, map->map_mflags) ||
191038032Speter		    aliaswait(map, NULL, TRUE))
191138032Speter#endif
191238032Speter			return TRUE;
191338032Speter	}
191438032Speter
191538032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
191638032Speter	{
191738032Speter		syserr("421 Cannot bind to map %s in domain %s: %s",
191838032Speter			map->map_file, map->map_domain, yperr_string(yperr));
191938032Speter	}
192038032Speter
192138032Speter	return FALSE;
192238032Speter}
192338032Speter
192438032Speter
192538032Speter/*
192638032Speter**  NIS_MAP_LOOKUP -- look up a datum in a NIS map
192738032Speter*/
192838032Speter
192938032Speter/* ARGSUSED3 */
193038032Speterchar *
193138032Speternis_map_lookup(map, name, av, statp)
193238032Speter	MAP *map;
193338032Speter	char *name;
193438032Speter	char **av;
193538032Speter	int *statp;
193638032Speter{
193738032Speter	char *vp;
193838032Speter	auto int vsize;
193938032Speter	int buflen;
194038032Speter	int yperr;
194138032Speter	char keybuf[MAXNAME + 1];
194238032Speter
194338032Speter	if (tTd(38, 20))
194438032Speter		printf("nis_map_lookup(%s, %s)\n",
194538032Speter			map->map_mname, name);
194638032Speter
194738032Speter	buflen = strlen(name);
194838032Speter	if (buflen > sizeof keybuf - 1)
194938032Speter		buflen = sizeof keybuf - 1;
195038032Speter	bcopy(name, keybuf, buflen);
195138032Speter	keybuf[buflen] = '\0';
195238032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
195338032Speter		makelower(keybuf);
195438032Speter	yperr = YPERR_KEY;
195538032Speter	if (bitset(MF_TRY0NULL, map->map_mflags))
195638032Speter	{
195738032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
195838032Speter			     &vp, &vsize);
195938032Speter		if (yperr == 0)
196038032Speter			map->map_mflags &= ~MF_TRY1NULL;
196138032Speter	}
196238032Speter	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
196338032Speter	{
196438032Speter		buflen++;
196538032Speter		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
196638032Speter			     &vp, &vsize);
196738032Speter		if (yperr == 0)
196838032Speter			map->map_mflags &= ~MF_TRY0NULL;
196938032Speter	}
197038032Speter	if (yperr != 0)
197138032Speter	{
197238032Speter		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
197338032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
197438032Speter		return NULL;
197538032Speter	}
197638032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
197738032Speter		return map_rewrite(map, name, strlen(name), NULL);
197838032Speter	else
197938032Speter		return map_rewrite(map, vp, vsize, av);
198038032Speter}
198138032Speter
198238032Speter
198338032Speter/*
198438032Speter**  NIS_GETCANONNAME -- look up canonical name in NIS
198538032Speter*/
198638032Speter
198738032Speterbool
198838032Speternis_getcanonname(name, hbsize, statp)
198938032Speter	char *name;
199038032Speter	int hbsize;
199138032Speter	int *statp;
199238032Speter{
199338032Speter	char *vp;
199438032Speter	auto int vsize;
199538032Speter	int keylen;
199638032Speter	int yperr;
199738032Speter	static bool try0null = TRUE;
199838032Speter	static bool try1null = TRUE;
199938032Speter	static char *yp_domain = NULL;
200038032Speter	char host_record[MAXLINE];
200138032Speter	char cbuf[MAXNAME];
200238032Speter	char nbuf[MAXNAME + 1];
200338032Speter
200438032Speter	if (tTd(38, 20))
200538032Speter		printf("nis_getcanonname(%s)\n", name);
200638032Speter
200738032Speter	if (strlen(name) >= sizeof nbuf)
200838032Speter	{
200938032Speter		*statp = EX_UNAVAILABLE;
201038032Speter		return FALSE;
201138032Speter	}
201238032Speter	(void) strcpy(nbuf, name);
201338032Speter	shorten_hostname(nbuf);
201438032Speter	keylen = strlen(nbuf);
201538032Speter
201638032Speter	if (yp_domain == NULL)
201738032Speter		yp_get_default_domain(&yp_domain);
201838032Speter	makelower(nbuf);
201938032Speter	yperr = YPERR_KEY;
202038032Speter	if (try0null)
202138032Speter	{
202238032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
202338032Speter			     &vp, &vsize);
202438032Speter		if (yperr == 0)
202538032Speter			try1null = FALSE;
202638032Speter	}
202738032Speter	if (yperr == YPERR_KEY && try1null)
202838032Speter	{
202938032Speter		keylen++;
203038032Speter		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
203138032Speter			     &vp, &vsize);
203238032Speter		if (yperr == 0)
203338032Speter			try0null = FALSE;
203438032Speter	}
203538032Speter	if (yperr != 0)
203638032Speter	{
203738032Speter		if (yperr == YPERR_KEY)
203838032Speter			*statp = EX_NOHOST;
203938032Speter		else if (yperr == YPERR_BUSY)
204038032Speter			*statp = EX_TEMPFAIL;
204138032Speter		else
204238032Speter			*statp = EX_UNAVAILABLE;
204338032Speter		return FALSE;
204438032Speter	}
204538032Speter	if (vsize >= sizeof host_record)
204638032Speter		vsize = sizeof host_record - 1;
204738032Speter	strncpy(host_record, vp, vsize);
204838032Speter	host_record[vsize] = '\0';
204938032Speter	if (tTd(38, 44))
205038032Speter		printf("got record `%s'\n", host_record);
205138032Speter	if (!extract_canonname(nbuf, host_record, cbuf, sizeof cbuf))
205238032Speter	{
205338032Speter		/* this should not happen, but.... */
205438032Speter		*statp = EX_NOHOST;
205538032Speter		return FALSE;
205638032Speter	}
205738032Speter	if (hbsize < strlen(cbuf))
205838032Speter	{
205938032Speter		*statp = EX_UNAVAILABLE;
206038032Speter		return FALSE;
206138032Speter	}
206238032Speter	strcpy(name, cbuf);
206338032Speter	*statp = EX_OK;
206438032Speter	return TRUE;
206538032Speter}
206638032Speter
206738032Speter#endif
206838032Speter/*
206938032Speter**  NISPLUS Modules
207038032Speter**
207138032Speter**	This code donated by Sun Microsystems.
207238032Speter*/
207338032Speter
207438032Speter#ifdef NISPLUS
207538032Speter
207638032Speter#undef NIS		/* symbol conflict in nis.h */
207738032Speter#undef T_UNSPEC		/* symbol conflict in nis.h -> ... -> sys/tiuser.h */
207838032Speter#include <rpcsvc/nis.h>
207938032Speter#include <rpcsvc/nislib.h>
208038032Speter
208138032Speter#define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
208238032Speter#define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
208338032Speter#define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
208438032Speter#define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
208538032Speter
208638032Speter/*
208738032Speter**  NISPLUS_MAP_OPEN -- open nisplus table
208838032Speter*/
208938032Speter
209038032Speterbool
209138032Speternisplus_map_open(map, mode)
209238032Speter	MAP *map;
209338032Speter	int mode;
209438032Speter{
209538032Speter	nis_result *res = NULL;
209638032Speter	int retry_cnt, max_col, i;
209738032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
209838032Speter
209938032Speter	if (tTd(38, 2))
210038032Speter		printf("nisplus_map_open(%s, %s, %d)\n",
210138032Speter			map->map_mname, map->map_file, mode);
210238032Speter
210338032Speter	mode &= O_ACCMODE;
210438032Speter	if (mode != O_RDONLY)
210538032Speter	{
210638032Speter		errno = EPERM;
210738032Speter		return FALSE;
210838032Speter	}
210938032Speter
211038032Speter	if (*map->map_file == '\0')
211138032Speter		map->map_file = "mail_aliases.org_dir";
211238032Speter
211338032Speter	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
211438032Speter	{
211538032Speter		/* set default NISPLUS Domain to $m */
211638032Speter		extern char *nisplus_default_domain __P((void));
211738032Speter
211838032Speter		map->map_domain = newstr(nisplus_default_domain());
211938032Speter		if (tTd(38, 2))
212038032Speter			printf("nisplus_map_open(%s): using domain %s\n",
212138032Speter				 map->map_file, map->map_domain);
212238032Speter	}
212338032Speter	if (!PARTIAL_NAME(map->map_file))
212438032Speter	{
212538032Speter		map->map_domain = newstr("");
212638032Speter		snprintf(qbuf, sizeof qbuf, "%s", map->map_file);
212738032Speter	}
212838032Speter	else
212938032Speter	{
213038032Speter		/* check to see if this map actually exists */
213138032Speter		snprintf(qbuf, sizeof qbuf, "%s.%s",
213238032Speter			map->map_file, map->map_domain);
213338032Speter	}
213438032Speter
213538032Speter	retry_cnt = 0;
213638032Speter	while (res == NULL || res->status != NIS_SUCCESS)
213738032Speter	{
213838032Speter		res = nis_lookup(qbuf, FOLLOW_LINKS);
213938032Speter		switch (res->status)
214038032Speter		{
214138032Speter		  case NIS_SUCCESS:
214238032Speter			break;
214338032Speter
214438032Speter		  case NIS_TRYAGAIN:
214538032Speter		  case NIS_RPCERROR:
214638032Speter		  case NIS_NAMEUNREACHABLE:
214738032Speter			if (retry_cnt++ > 4)
214838032Speter			{
214938032Speter				errno = EAGAIN;
215038032Speter				return FALSE;
215138032Speter			}
215238032Speter			/* try not to overwhelm hosed server */
215338032Speter			sleep(2);
215438032Speter			break;
215538032Speter
215638032Speter		  default:		/* all other nisplus errors */
215738032Speter#if 0
215838032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
215938032Speter				syserr("421 Cannot find table %s.%s: %s",
216038032Speter					map->map_file, map->map_domain,
216138032Speter					nis_sperrno(res->status));
216238032Speter#endif
216338032Speter			errno = EAGAIN;
216438032Speter			return FALSE;
216538032Speter		}
216638032Speter	}
216738032Speter
216838032Speter	if (NIS_RES_NUMOBJ(res) != 1 ||
216938032Speter	    (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
217038032Speter	{
217138032Speter		if (tTd(38, 10))
217238032Speter			printf("nisplus_map_open: %s is not a table\n", qbuf);
217338032Speter#if 0
217438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
217538032Speter			syserr("421 %s.%s: %s is not a table",
217638032Speter				map->map_file, map->map_domain,
217738032Speter				nis_sperrno(res->status));
217838032Speter#endif
217938032Speter		errno = EBADF;
218038032Speter		return FALSE;
218138032Speter	}
218238032Speter	/* default key column is column 0 */
218338032Speter	if (map->map_keycolnm == NULL)
218438032Speter		map->map_keycolnm = newstr(COL_NAME(res,0));
218538032Speter
218638032Speter	max_col = COL_MAX(res);
218738032Speter
218838032Speter	/* verify the key column exist */
218938032Speter	for (i=0; i< max_col; i++)
219038032Speter	{
219138032Speter		if (!strcmp(map->map_keycolnm, COL_NAME(res,i)))
219238032Speter			break;
219338032Speter	}
219438032Speter	if (i == max_col)
219538032Speter	{
219638032Speter		if (tTd(38, 2))
219738032Speter			printf("nisplus_map_open(%s): can not find key column %s\n",
219838032Speter				map->map_file, map->map_keycolnm);
219938032Speter		errno = ENOENT;
220038032Speter		return FALSE;
220138032Speter	}
220238032Speter
220338032Speter	/* default value column is the last column */
220438032Speter	if (map->map_valcolnm == NULL)
220538032Speter	{
220638032Speter		map->map_valcolno = max_col - 1;
220738032Speter		return TRUE;
220838032Speter	}
220938032Speter
221038032Speter	for (i=0; i< max_col; i++)
221138032Speter	{
221238032Speter		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
221338032Speter		{
221438032Speter			map->map_valcolno = i;
221538032Speter			return TRUE;
221638032Speter		}
221738032Speter	}
221838032Speter
221938032Speter	if (tTd(38, 2))
222038032Speter		printf("nisplus_map_open(%s): can not find column %s\n",
222138032Speter			 map->map_file, map->map_keycolnm);
222238032Speter	errno = ENOENT;
222338032Speter	return FALSE;
222438032Speter}
222538032Speter
222638032Speter
222738032Speter/*
222838032Speter**  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
222938032Speter*/
223038032Speter
223138032Speterchar *
223238032Speternisplus_map_lookup(map, name, av, statp)
223338032Speter	MAP *map;
223438032Speter	char *name;
223538032Speter	char **av;
223638032Speter	int *statp;
223738032Speter{
223838032Speter	char *p;
223938032Speter	auto int vsize;
224038032Speter	char *skp;
224138032Speter	int skleft;
224238032Speter	char search_key[MAXNAME + 4];
224338032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
224438032Speter	nis_result *result;
224538032Speter
224638032Speter	if (tTd(38, 20))
224738032Speter		printf("nisplus_map_lookup(%s, %s)\n",
224838032Speter			map->map_mname, name);
224938032Speter
225038032Speter	if (!bitset(MF_OPEN, map->map_mflags))
225138032Speter	{
225238032Speter		if (nisplus_map_open(map, O_RDONLY))
225338032Speter			map->map_mflags |= MF_OPEN;
225438032Speter		else
225538032Speter		{
225638032Speter			*statp = EX_UNAVAILABLE;
225738032Speter			return NULL;
225838032Speter		}
225938032Speter	}
226038032Speter
226138032Speter	/*
226238032Speter	**  Copy the name to the key buffer, escaping double quote characters
226338032Speter	**  by doubling them and quoting "]" and "," to avoid having the
226438032Speter	**  NIS+ parser choke on them.
226538032Speter	*/
226638032Speter
226738032Speter	skleft = sizeof search_key - 4;
226838032Speter	skp = search_key;
226938032Speter	for (p = name; *p != '\0' && skleft > 0; p++)
227038032Speter	{
227138032Speter		switch (*p)
227238032Speter		{
227338032Speter		  case ']':
227438032Speter		  case ',':
227538032Speter			/* quote the character */
227638032Speter			*skp++ = '"';
227738032Speter			*skp++ = *p;
227838032Speter			*skp++ = '"';
227938032Speter			skleft -= 3;
228038032Speter			break;
228138032Speter
228238032Speter		  case '"':
228338032Speter			/* double the quote */
228438032Speter			*skp++ = '"';
228538032Speter			skleft--;
228638032Speter			/* fall through... */
228738032Speter
228838032Speter		  default:
228938032Speter			*skp++ = *p;
229038032Speter			skleft--;
229138032Speter			break;
229238032Speter		}
229338032Speter	}
229438032Speter	*skp = '\0';
229538032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
229638032Speter		makelower(search_key);
229738032Speter
229838032Speter	/* construct the query */
229938032Speter	if (PARTIAL_NAME(map->map_file))
230038032Speter		snprintf(qbuf, sizeof qbuf, "[%s=%s],%s.%s",
230138032Speter			map->map_keycolnm, search_key, map->map_file,
230238032Speter			map->map_domain);
230338032Speter	else
230438032Speter		snprintf(qbuf, sizeof qbuf, "[%s=%s],%s",
230538032Speter			map->map_keycolnm, search_key, map->map_file);
230638032Speter
230738032Speter	if (tTd(38, 20))
230838032Speter		printf("qbuf=%s\n", qbuf);
230938032Speter	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
231038032Speter	if (result->status == NIS_SUCCESS)
231138032Speter	{
231238032Speter		int count;
231338032Speter		char *str;
231438032Speter
231538032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
231638032Speter		{
231738032Speter			if (LogLevel > 10)
231838032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
231938032Speter				  "%s: lookup error, expected 1 entry, got %d",
232038032Speter				    map->map_file, count);
232138032Speter
232238032Speter			/* ignore second entry */
232338032Speter			if (tTd(38, 20))
232438032Speter				printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
232538032Speter					name, count);
232638032Speter		}
232738032Speter
232838032Speter		p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
232938032Speter		/* set the length of the result */
233038032Speter		if (p == NULL)
233138032Speter			p = "";
233238032Speter		vsize = strlen(p);
233338032Speter		if (tTd(38, 20))
233438032Speter			printf("nisplus_map_lookup(%s), found %s\n",
233538032Speter				name, p);
233638032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
233738032Speter			str = map_rewrite(map, name, strlen(name), NULL);
233838032Speter		else
233938032Speter			str = map_rewrite(map, p, vsize, av);
234038032Speter		nis_freeresult(result);
234138032Speter		*statp = EX_OK;
234238032Speter		return str;
234338032Speter	}
234438032Speter	else
234538032Speter	{
234638032Speter		if (result->status == NIS_NOTFOUND)
234738032Speter			*statp = EX_NOTFOUND;
234838032Speter		else if (result->status == NIS_TRYAGAIN)
234938032Speter			*statp = EX_TEMPFAIL;
235038032Speter		else
235138032Speter		{
235238032Speter			*statp = EX_UNAVAILABLE;
235338032Speter			map->map_mflags &= ~(MF_VALID|MF_OPEN);
235438032Speter		}
235538032Speter	}
235638032Speter	if (tTd(38, 20))
235738032Speter		printf("nisplus_map_lookup(%s), failed\n", name);
235838032Speter	nis_freeresult(result);
235938032Speter	return NULL;
236038032Speter}
236138032Speter
236238032Speter
236338032Speter
236438032Speter/*
236538032Speter**  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
236638032Speter*/
236738032Speter
236838032Speterbool
236938032Speternisplus_getcanonname(name, hbsize, statp)
237038032Speter	char *name;
237138032Speter	int hbsize;
237238032Speter	int *statp;
237338032Speter{
237438032Speter	char *vp;
237538032Speter	auto int vsize;
237638032Speter	nis_result *result;
237738032Speter	char *p;
237838032Speter	char nbuf[MAXNAME + 1];
237938032Speter	char qbuf[MAXLINE + NIS_MAXNAMELEN];
238038032Speter
238138032Speter	if (strlen(name) >= sizeof nbuf)
238238032Speter	{
238338032Speter		*statp = EX_UNAVAILABLE;
238438032Speter		return FALSE;
238538032Speter	}
238638032Speter	(void) strcpy(nbuf, name);
238738032Speter	shorten_hostname(nbuf);
238838032Speter
238938032Speter	p = strchr(nbuf, '.');
239038032Speter	if (p == NULL)
239138032Speter	{
239238032Speter		/* single token */
239338032Speter		snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir", nbuf);
239438032Speter	}
239538032Speter	else if (p[1] != '\0')
239638032Speter	{
239738032Speter		/* multi token -- take only first token in nbuf */
239838032Speter		*p = '\0';
239938032Speter		snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir.%s",
240038032Speter			nbuf, &p[1]);
240138032Speter	}
240238032Speter	else
240338032Speter	{
240438032Speter		*statp = EX_NOHOST;
240538032Speter		return FALSE;
240638032Speter	}
240738032Speter
240838032Speter	if (tTd(38, 20))
240938032Speter		printf("\nnisplus_getcanoname(%s), qbuf=%s\n",
241038032Speter			 name, qbuf);
241138032Speter
241238032Speter	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
241338032Speter		NULL, NULL);
241438032Speter
241538032Speter	if (result->status == NIS_SUCCESS)
241638032Speter	{
241738032Speter		int count;
241838032Speter		char *domain;
241938032Speter
242038032Speter		if ((count = NIS_RES_NUMOBJ(result)) != 1)
242138032Speter		{
242238032Speter			if (LogLevel > 10)
242338032Speter				sm_syslog(LOG_WARNING, CurEnv->e_id,
242438032Speter				       "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
242538032Speter				       count);
242638032Speter
242738032Speter			/* ignore second entry */
242838032Speter			if (tTd(38, 20))
242938032Speter				printf("nisplus_getcanoname(%s), got %d entries, all but first ignored\n",
243038032Speter					name, count);
243138032Speter		}
243238032Speter
243338032Speter		if (tTd(38, 20))
243438032Speter			printf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
243538032Speter			       name, (NIS_RES_OBJECT(result))->zo_domain);
243638032Speter
243738032Speter
243838032Speter		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
243938032Speter		vsize = strlen(vp);
244038032Speter		if (tTd(38, 20))
244138032Speter			printf("nisplus_getcanonname(%s), found %s\n",
244238032Speter				name, vp);
244338032Speter		if (strchr(vp, '.') != NULL)
244438032Speter		{
244538032Speter			domain = "";
244638032Speter		}
244738032Speter		else
244838032Speter		{
244938032Speter			domain = macvalue('m', CurEnv);
245038032Speter			if (domain == NULL)
245138032Speter				domain = "";
245238032Speter		}
245338032Speter		if (hbsize > vsize + (int) strlen(domain) + 1)
245438032Speter		{
245538032Speter			if (domain[0] == '\0')
245638032Speter				strcpy(name, vp);
245738032Speter			else
245838032Speter				snprintf(name, hbsize, "%s.%s", vp, domain);
245938032Speter			*statp = EX_OK;
246038032Speter		}
246138032Speter		else
246238032Speter			*statp = EX_NOHOST;
246338032Speter		nis_freeresult(result);
246438032Speter		return TRUE;
246538032Speter	}
246638032Speter	else
246738032Speter	{
246838032Speter		if (result->status == NIS_NOTFOUND)
246938032Speter			*statp = EX_NOHOST;
247038032Speter		else if (result->status == NIS_TRYAGAIN)
247138032Speter			*statp = EX_TEMPFAIL;
247238032Speter		else
247338032Speter			*statp = EX_UNAVAILABLE;
247438032Speter	}
247538032Speter	if (tTd(38, 20))
247638032Speter		printf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
247738032Speter			name, result->status, *statp);
247838032Speter	nis_freeresult(result);
247938032Speter	return FALSE;
248038032Speter}
248138032Speter
248238032Speter
248338032Speterchar *
248438032Speternisplus_default_domain()
248538032Speter{
248638032Speter	static char default_domain[MAXNAME + 1] = "";
248738032Speter	char *p;
248838032Speter
248938032Speter	if (default_domain[0] != '\0')
249038032Speter		return(default_domain);
249138032Speter
249238032Speter	p = nis_local_directory();
249338032Speter	snprintf(default_domain, sizeof default_domain, "%s", p);
249438032Speter	return default_domain;
249538032Speter}
249638032Speter
249738032Speter#endif /* NISPLUS */
249838032Speter/*
249938032Speter**  LDAP Modules
250038032Speter**
250138032Speter**	Contributed by Booker C. Bense <bbense@networking.stanford.edu>.
250238032Speter**	Get your support from him.
250338032Speter*/
250438032Speter
250538032Speter#ifdef LDAPMAP
250638032Speter
250738032Speter# undef NEEDGETOPT		/* used for something else in LDAP */
250838032Speter
250938032Speter# include <lber.h>
251038032Speter# include <ldap.h>
251138032Speter# include "ldap_map.h"
251238032Speter
251338032Speter/*
251438032Speter**  LDAP_MAP_OPEN -- open LDAP map
251538032Speter**
251638032Speter**	Since LDAP is TCP-based there is not much we can or should do
251738032Speter**	here.  It might be a good idea to attempt an open/close here.
251838032Speter*/
251938032Speter
252038032Speterbool
252138032Speterldap_map_open(map, mode)
252238032Speter	MAP *map;
252338032Speter	int mode;
252438032Speter{
252538032Speter	if (tTd(38, 2))
252638032Speter		printf("ldap_map_open(%s, %d)\n", map->map_mname, mode);
252738032Speter
252838032Speter	mode &= O_ACCMODE;
252938032Speter	if (mode != O_RDONLY)
253038032Speter	{
253138032Speter		/* issue a pseudo-error message */
253238032Speter#ifdef ENOSYS
253338032Speter		errno = ENOSYS;
253438032Speter#else
253538032Speter# ifdef EFTYPE
253638032Speter		errno = EFTYPE;
253738032Speter# else
253838032Speter		errno = ENXIO;
253938032Speter# endif
254038032Speter#endif
254138032Speter		return FALSE;
254238032Speter	}
254338032Speter	return TRUE;
254438032Speter}
254538032Speter
254638032Speter
254738032Speter/*
254838032Speter**  LDAP_MAP_START -- actually open LDAP map
254938032Speter**
255038032Speter**	Caching should be investigated.
255138032Speter*/
255238032Speter
255338032Speterstatic jmp_buf	LDAPTimeout;
255438032Speter
255538032Speterstatic void
255638032Speterldaptimeout(sig_no)
255738032Speter	int sig_no;
255838032Speter{
255938032Speter	longjmp(LDAPTimeout, 1);
256038032Speter}
256138032Speter
256238032Speterbool
256338032Speterldap_map_start(map)
256438032Speter	MAP *map;
256538032Speter{
256638032Speter	LDAP_MAP_STRUCT *lmap;
256738032Speter	LDAP *ld;
256838032Speter	register EVENT *ev = NULL;
256938032Speter
257038032Speter	if (tTd(38, 2))
257138032Speter		printf("ldap_map_start(%s)\n", map->map_mname);
257238032Speter
257338032Speter	lmap = (LDAP_MAP_STRUCT *) map->map_db1;
257438032Speter
257538032Speter	if (tTd(38,9))
257638032Speter		printf("ldap_open(%s, %d)\n", lmap->ldaphost, lmap->ldapport);
257738032Speter
257838032Speter	/* Need to set an alarm here, ldap_open is hopelessly broken. */
257938032Speter
258038032Speter	/* set the timeout */
258138032Speter	if (lmap->timeout.tv_sec != 0)
258238032Speter	{
258338032Speter		if (setjmp(LDAPTimeout) != 0)
258438032Speter		{
258538032Speter			if (LogLevel > 1)
258638032Speter				sm_syslog(LOG_NOTICE, CurEnv->e_id,
258738032Speter				       "timeout waiting for ldap_open to %.100s",
258838032Speter				       lmap->ldaphost);
258938032Speter			return (FALSE);
259038032Speter		}
259138032Speter		ev = setevent(lmap->timeout.tv_sec, ldaptimeout, 0);
259238032Speter	}
259338032Speter
259438032Speter	if ((ld = ldap_open(lmap->ldaphost,lmap->ldapport)) == NULL)
259538032Speter	{
259638032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
259738032Speter		{
259838032Speter			syserr("ldapopen failed to %s in map %s",
259938032Speter				lmap->ldaphost, map->map_mname);
260038032Speter		}
260138032Speter		return FALSE;
260238032Speter	}
260338032Speter
260438032Speter	/* clear the event if it has not sprung */
260538032Speter	clrevent(ev);
260638032Speter	/* From here on in we can use ldap internal timelimits */
260738032Speter	ld->ld_deref = lmap->deref;
260838032Speter	ld->ld_timelimit = lmap->timelimit;
260938032Speter	ld->ld_sizelimit = lmap->sizelimit;
261038032Speter	ld->ld_options = lmap->ldap_options;
261138032Speter
261238032Speter	if (ldap_bind_s(ld, lmap->binddn,lmap->passwd,lmap->method) != LDAP_SUCCESS)
261338032Speter	{
261438032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
261538032Speter		{
261638032Speter			syserr("421 Cannot bind to map %s in ldap server %s",
261738032Speter				map->map_mname, lmap->ldaphost);
261838032Speter		}
261938032Speter	}
262038032Speter	else
262138032Speter	{
262238032Speter		/* We need to cast ld into the map structure */
262338032Speter		lmap->ld = ld;
262438032Speter		return TRUE;
262538032Speter	}
262638032Speter
262738032Speter	return FALSE;
262838032Speter}
262938032Speter
263038032Speter
263138032Speter/*
263238032Speter** LDAP_MAP_CLOSE -- close ldap map
263338032Speter*/
263438032Speter
263538032Spetervoid
263638032Speterldap_map_close(map)
263738032Speter	MAP *map;
263838032Speter{
263938032Speter	LDAP_MAP_STRUCT *lmap ;
264038032Speter	lmap = (LDAP_MAP_STRUCT *) map->map_db1;
264138032Speter	if (lmap->ld != NULL)
264238032Speter		ldap_unbind(lmap->ld);
264338032Speter}
264438032Speter
264538032Speter
264638032Speter#ifdef SUNET_ID
264738032Speter/*
264838032Speter** SUNET_ID_HASH -- Convert a string to it's Sunet_id canonical form
264938032Speter** This only makes sense at Stanford University.
265038032Speter*/
265138032Speter
265238032Speterchar *
265338032Spetersunet_id_hash(str)
265438032Speter	char *str;
265538032Speter{
265638032Speter	char *p, *p_last;
265738032Speter
265838032Speter	p = str;
265938032Speter	p_last = p;
266038032Speter	while (*p != '\0')
266138032Speter	{
266238032Speter		if (islower(*p) || isdigit(*p))
266338032Speter		{
266438032Speter			*p_last = *p;
266538032Speter			p_last++;
266638032Speter		}
266738032Speter		else if (isupper(*p))
266838032Speter		{
266938032Speter			*p_last = tolower(*p);
267038032Speter			p_last++;
267138032Speter		}
267238032Speter		++p;
267338032Speter	}
267438032Speter	if (*p_last != '\0')
267538032Speter		*p_last = '\0';
267638032Speter	return (str);
267738032Speter}
267838032Speter
267938032Speter
268038032Speter
268138032Speter#endif /* SUNET_ID */
268238032Speter/*
268338032Speter** LDAP_MAP_LOOKUP -- look up a datum in a LDAP map
268438032Speter*/
268538032Speter
268638032Speterchar *
268738032Speterldap_map_lookup(map, name, av, statp)
268838032Speter	MAP *map;
268938032Speter	char *name;
269038032Speter	char **av;
269138032Speter	int *statp;
269238032Speter{
269338032Speter	LDAP_MAP_STRUCT *lmap = NULL;
269438032Speter	LDAPMessage *entry;
269538032Speter	char *vp;
269638032Speter	auto int vsize;
269738032Speter	char keybuf[MAXNAME + 1];
269838032Speter	char filter[LDAP_MAP_MAX_FILTER + 1];
269938032Speter	char **attr_values = NULL;
270038032Speter	char *result;
270138032Speter	int name_len;
270238032Speter
270338032Speter	if (tTd(38, 20))
270438032Speter		printf("ldap_map_lookup(%s, %s)\n", map->map_mname, name);
270538032Speter
270638032Speter	/* actually open the map */
270738032Speter	if (!ldap_map_start(map))
270838032Speter	{
270938032Speter		result = NULL;
271038032Speter		*statp = EX_TEMPFAIL;
271138032Speter		goto quick_exit;
271238032Speter	}
271338032Speter
271438032Speter	/* Get ldap struct pointer from map */
271538032Speter	lmap = (LDAP_MAP_STRUCT *) map->map_db1;
271638032Speter
271738032Speter	name_len = strlen(name);
271838032Speter	if (name_len > MAXNAME)
271938032Speter		name_len = MAXNAME;
272038032Speter	strncpy(keybuf, name, name_len);
272138032Speter	keybuf[name_len] = '\0';
272238032Speter
272338032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
272438032Speter#ifdef SUNET_ID
272538032Speter		sunet_id_hash(keybuf);
272638032Speter#else
272738032Speter		makelower(keybuf);
272838032Speter#endif /*SUNET_ID */
272938032Speter
273038032Speter	/* sprintf keybuf into filter */
273138032Speter	snprintf(filter, sizeof filter, lmap->filter, keybuf);
273238032Speter
273338032Speter	if (ldap_search_st(lmap->ld, lmap->base,lmap->scope,filter,
273438032Speter			   lmap->attr, lmap->attrsonly, &(lmap->timeout),
273538032Speter			   &(lmap->res)) != LDAP_SUCCESS)
273638032Speter	{
273738032Speter		/* try close/opening map */
273838032Speter		ldap_map_close(map);
273938032Speter		if (!ldap_map_start(map))
274038032Speter		{
274138032Speter			result = NULL;
274238032Speter			*statp = EX_TEMPFAIL;
274338032Speter			goto quick_exit;
274438032Speter		}
274538032Speter		if (ldap_search_st(lmap->ld, lmap->base, lmap->scope, filter,
274638032Speter				   lmap->attr, lmap->attrsonly,
274738032Speter				   &(lmap->timeout), &(lmap->res))
274838032Speter			!= LDAP_SUCCESS)
274938032Speter		{
275038032Speter			if (!bitset(MF_OPTIONAL, map->map_mflags))
275138032Speter			{
275238032Speter				syserr("Error in ldap_search_st using %s in map %s",
275338032Speter					filter, map->map_mname);
275438032Speter			}
275538032Speter			result = NULL;
275638032Speter			*statp = EX_TEMPFAIL;
275738032Speter			goto quick_exit;
275838032Speter		}
275938032Speter	}
276038032Speter
276138032Speter	entry = ldap_first_entry(lmap->ld,lmap->res);
276238032Speter	if (entry == NULL)
276338032Speter	{
276438032Speter	        result = NULL;
276538032Speter		*statp = EX_NOTFOUND;
276638032Speter		goto quick_exit;
276738032Speter	}
276838032Speter
276938032Speter	/* Need to build the args for map_rewrite here */
277038032Speter	attr_values = ldap_get_values(lmap->ld,entry,lmap->attr[0]);
277138032Speter	if (attr_values == NULL)
277238032Speter	{
277338032Speter		/* bad things happened */
277438032Speter		result = NULL;
277538032Speter		*statp = EX_NOTFOUND;
277638032Speter		goto quick_exit;
277738032Speter	}
277838032Speter
277938032Speter	*statp = EX_OK;
278038032Speter
278138032Speter	/* If there is more that one use the first */
278238032Speter	vp = attr_values[0];
278338032Speter	vsize = strlen(vp);
278438032Speter
278538032Speter	if (LogLevel > 9)
278638032Speter		sm_syslog(LOG_INFO, CurEnv->e_id,
278738032Speter			"ldap %.100s => %s",
278838032Speter			name, vp);
278938032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
279038032Speter		result = map_rewrite(map, name, strlen(name), NULL);
279138032Speter	else
279238032Speter		result = map_rewrite(map, vp, vsize, av);
279338032Speter
279438032Speter  quick_exit:
279538032Speter	if (attr_values != NULL)
279638032Speter		ldap_value_free(attr_values);
279738032Speter	if (lmap != NULL)
279838032Speter		ldap_msgfree(lmap->res);
279938032Speter	ldap_map_close(map);
280038032Speter	return result ;
280138032Speter}
280238032Speter
280338032Speter
280438032Speter/*
280538032Speter** LDAP_MAP_DEQUOTE - helper routine for ldap_map_parseargs
280638032Speter*/
280738032Speter
280838032Speterchar *
280938032Speterldap_map_dequote(str)
281038032Speter	char *str;
281138032Speter{
281238032Speter	char *p;
281338032Speter	char *start;
281438032Speter	p = str;
281538032Speter
281638032Speter	if (*p == '"')
281738032Speter	{
281838032Speter		start = ++p;
281938032Speter		/* Should probably swallow initial whitespace here */
282038032Speter	}
282138032Speter	else
282238032Speter	{
282338032Speter		return(str);
282438032Speter	}
282538032Speter	while (*p != '"' && *p != '\0')
282638032Speter	{
282738032Speter		p++;
282838032Speter	}
282938032Speter	if (*p != '\0')
283038032Speter		*p = '\0';
283138032Speter	return start;
283238032Speter}
283338032Speter
283438032Speter/*
283538032Speter** LDAP_MAP_PARSEARGS -- parse ldap map definition args.
283638032Speter*/
283738032Speter
283838032Speterbool
283938032Speterldap_map_parseargs(map,args)
284038032Speter	MAP *map;
284138032Speter	char *args;
284238032Speter{
284338032Speter	register char *p = args;
284438032Speter	register int done;
284538032Speter	LDAP_MAP_STRUCT *lmap;
284638032Speter
284738032Speter	/* We need to alloc an LDAP_MAP_STRUCT struct */
284838032Speter	lmap  = (LDAP_MAP_STRUCT *) xalloc(sizeof(LDAP_MAP_STRUCT));
284938032Speter
285038032Speter	/* Set default int's here , default strings below */
285138032Speter	lmap->ldapport =  DEFAULT_LDAP_MAP_PORT;
285238032Speter	lmap->deref = DEFAULT_LDAP_MAP_DEREF;
285338032Speter	lmap->timelimit = DEFAULT_LDAP_MAP_TIMELIMIT;
285438032Speter	lmap->sizelimit = DEFAULT_LDAP_MAP_SIZELIMIT;
285538032Speter	lmap->ldap_options = DEFAULT_LDAP_MAP_LDAP_OPTIONS;
285638032Speter	lmap->method = DEFAULT_LDAP_MAP_METHOD;
285738032Speter	lmap->scope = DEFAULT_LDAP_MAP_SCOPE;
285838032Speter	lmap->attrsonly = DEFAULT_LDAP_MAP_ATTRSONLY;
285938032Speter	lmap->timeout.tv_sec = DEFAULT_LDAP_MAP_TIMELIMIT;
286038032Speter	lmap->timeout.tv_usec = 0;
286138032Speter
286238032Speter	/* Default char ptrs to NULL */
286338032Speter	lmap->binddn = NULL;
286438032Speter	lmap->passwd = NULL;
286538032Speter	lmap->base   = NULL;
286638032Speter	lmap->ldaphost = NULL;
286738032Speter
286838032Speter	/* Default general ptrs to NULL */
286938032Speter	lmap->ld = NULL;
287038032Speter	lmap->res = NULL;
287138032Speter
287238032Speter	map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
287338032Speter	for (;;)
287438032Speter	{
287538032Speter		while (isascii(*p) && isspace(*p))
287638032Speter			p++;
287738032Speter		if (*p != '-')
287838032Speter			break;
287938032Speter		switch (*++p)
288038032Speter		{
288138032Speter		  case 'N':
288238032Speter			map->map_mflags |= MF_INCLNULL;
288338032Speter			map->map_mflags &= ~MF_TRY0NULL;
288438032Speter			break;
288538032Speter
288638032Speter		  case 'O':
288738032Speter			map->map_mflags &= ~MF_TRY1NULL;
288838032Speter			break;
288938032Speter
289038032Speter		  case 'o':
289138032Speter			map->map_mflags |= MF_OPTIONAL;
289238032Speter			break;
289338032Speter
289438032Speter		  case 'f':
289538032Speter			map->map_mflags |= MF_NOFOLDCASE;
289638032Speter			break;
289738032Speter
289838032Speter		  case 'm':
289938032Speter			map->map_mflags |= MF_MATCHONLY;
290038032Speter			break;
290138032Speter
290238032Speter		  case 'A':
290338032Speter			map->map_mflags |= MF_APPEND;
290438032Speter			break;
290538032Speter
290638032Speter		  case 'q':
290738032Speter			map->map_mflags |= MF_KEEPQUOTES;
290838032Speter			break;
290938032Speter
291038032Speter		  case 't':
291138032Speter			map->map_mflags |= MF_NODEFER;
291238032Speter			break;
291338032Speter
291438032Speter		  case 'a':
291538032Speter			map->map_app = ++p;
291638032Speter			break;
291738032Speter
291838032Speter		  case 'T':
291938032Speter			map->map_tapp = ++p;
292038032Speter			break;
292138032Speter
292238032Speter			/* Start of ldap_map specific args */
292338032Speter		  case 'k':		/* search field */
292438032Speter			while (isascii(*++p) && isspace(*p))
292538032Speter				continue;
292638032Speter			lmap->filter = p;
292738032Speter			break;
292838032Speter
292938032Speter		  case 'v':		/* attr to return */
293038032Speter			while (isascii(*++p) && isspace(*p))
293138032Speter				continue;
293238032Speter			lmap->attr[0] = p;
293338032Speter			lmap->attr[1] = NULL;
293438032Speter			break;
293538032Speter
293638032Speter			/* args stolen from ldapsearch.c */
293738032Speter		  case 'R':		/* don't auto chase referrals */
293838032Speter#ifdef LDAP_REFERRALS
293938032Speter			lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
294038032Speter#else  /* LDAP_REFERRALS */
294138032Speter			syserr("compile with -DLDAP_REFERRALS for referral support\n");
294238032Speter#endif /* LDAP_REFERRALS */
294338032Speter			break;
294438032Speter
294538032Speter		  case 'n':		/* retrieve attribute names only -- no values */
294638032Speter			lmap->attrsonly += 1;
294738032Speter			break;
294838032Speter
294938032Speter		  case 's':		/* search scope */
295038032Speter			if (strncasecmp(++p, "base", 4) == 0)
295138032Speter			{
295238032Speter				lmap->scope = LDAP_SCOPE_BASE;
295338032Speter			}
295438032Speter			else if (strncasecmp(p, "one", 3) == 0)
295538032Speter			{
295638032Speter				lmap->scope = LDAP_SCOPE_ONELEVEL;
295738032Speter			}
295838032Speter			else if (strncasecmp(p, "sub", 3) == 0)
295938032Speter			{
296038032Speter				lmap->scope = LDAP_SCOPE_SUBTREE;
296138032Speter			}
296238032Speter			else
296338032Speter			{		/* bad config line */
296438032Speter				if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
296538032Speter				{
296638032Speter					char *ptr;
296738032Speter
296838032Speter					if ((ptr = strchr(p, ' ')) != NULL)
296938032Speter						*ptr = '\0';
297038032Speter					syserr("Scope must be [base|one|sub] not %s in map %s",
297138032Speter						p, map->map_mname);
297238032Speter					if (ptr != NULL)
297338032Speter						*ptr = ' ';
297438032Speter					return FALSE;
297538032Speter				}
297638032Speter			}
297738032Speter			break;
297838032Speter
297938032Speter		  case 'h':		/* ldap host */
298038032Speter			while (isascii(*++p) && isspace(*p))
298138032Speter				continue;
298238032Speter			map->map_domain = p;
298338032Speter			lmap->ldaphost = p;
298438032Speter			break;
298538032Speter
298638032Speter		  case 'b':		/* search base */
298738032Speter			while (isascii(*++p) && isspace(*p))
298838032Speter				continue;
298938032Speter			lmap->base = p;
299038032Speter			break;
299138032Speter
299238032Speter		  case 'p':		/* ldap port */
299338032Speter			while (isascii(*++p) && isspace(*p))
299438032Speter				continue;
299538032Speter			lmap->ldapport = atoi(p);
299638032Speter			break;
299738032Speter
299838032Speter		  case 'l':		/* time limit */
299938032Speter			while (isascii(*++p) && isspace(*p))
300038032Speter				continue;
300138032Speter			lmap->timelimit = atoi(p);
300238032Speter			lmap->timeout.tv_sec = lmap->timelimit;
300338032Speter			break;
300438032Speter
300538032Speter		}
300638032Speter
300738032Speter		/* need to account for quoted strings here arggg... */
300838032Speter		done =  isascii(*p) && isspace(*p);
300938032Speter		while (*p != '\0' && !done)
301038032Speter		{
301138032Speter			if (*p == '"')
301238032Speter			{
301338032Speter				while (*++p != '"' && *p != '\0')
301438032Speter				{
301538032Speter					continue;
301638032Speter				}
301738032Speter				if (*p != '\0')
301838032Speter					p++;
301938032Speter			}
302038032Speter			else
302138032Speter			{
302238032Speter				p++;
302338032Speter			}
302438032Speter			done = isascii(*p) && isspace(*p);
302538032Speter		}
302638032Speter
302738032Speter		if (*p != '\0')
302838032Speter			*p++ = '\0';
302938032Speter	}
303038032Speter
303138032Speter	if (map->map_app != NULL)
303238032Speter		map->map_app = newstr(ldap_map_dequote(map->map_app));
303338032Speter	if (map->map_tapp != NULL)
303438032Speter		map->map_tapp = newstr(ldap_map_dequote(map->map_tapp));
303538032Speter	if (map->map_domain != NULL)
303638032Speter		map->map_domain = newstr(ldap_map_dequote(map->map_domain));
303738032Speter
303838032Speter	/*
303938032Speter	** We need to swallow up all the stuff into a struct
304038032Speter	** and dump it into map->map_dbptr1
304138032Speter	*/
304238032Speter
304338032Speter	if (lmap->ldaphost != NULL)
304438032Speter		lmap->ldaphost = newstr(ldap_map_dequote(lmap->ldaphost));
304538032Speter	else
304638032Speter	{
304738032Speter		syserr("LDAP map: -h flag is required");
304838032Speter		return FALSE;
304938032Speter	}
305038032Speter
305138032Speter	if (lmap->binddn != NULL)
305238032Speter		lmap->binddn = newstr(ldap_map_dequote(lmap->binddn));
305338032Speter	else
305438032Speter		lmap->binddn = DEFAULT_LDAP_MAP_BINDDN;
305538032Speter
305638032Speter
305738032Speter	if (lmap->passwd != NULL)
305838032Speter		lmap->passwd = newstr(ldap_map_dequote(lmap->passwd));
305938032Speter	else
306038032Speter		lmap->passwd = DEFAULT_LDAP_MAP_PASSWD;
306138032Speter
306238032Speter	if (lmap->base != NULL)
306338032Speter		lmap->base = newstr(ldap_map_dequote(lmap->base));
306438032Speter	else
306538032Speter	{
306638032Speter		syserr("LDAP map: -b flag is required");
306738032Speter		return FALSE;
306838032Speter	}
306938032Speter
307038032Speter
307138032Speter	if (lmap->filter != NULL)
307238032Speter		lmap->filter = newstr(ldap_map_dequote(lmap->filter));
307338032Speter	else
307438032Speter	{
307538032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
307638032Speter		{
307738032Speter			syserr("No filter given in map %s", map->map_mname);
307838032Speter			return FALSE;
307938032Speter		}
308038032Speter	}
308138032Speter	if (lmap->attr[0] != NULL)
308238032Speter		lmap->attr[0] = newstr(ldap_map_dequote(lmap->attr[0]));
308338032Speter	else
308438032Speter	{
308538032Speter		if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
308638032Speter		{
308738032Speter			syserr("No return attribute in %s", map->map_mname);
308838032Speter			return FALSE;
308938032Speter		}
309038032Speter	}
309138032Speter
309238032Speter	map->map_db1 = (ARBPTR_T) lmap;
309338032Speter	return TRUE;
309438032Speter}
309538032Speter
309638032Speter#endif /* LDAP Modules */
309738032Speter/*
309838032Speter** syslog map
309938032Speter*/
310038032Speter
310138032Speter#if _FFR_MAP_SYSLOG
310238032Speter
310338032Speter#define map_prio	map_lockfd	/* overload field */
310438032Speter
310538032Speter/*
310638032Speter** SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
310738032Speter*/
310838032Speter
310938032Speterbool
311038032Spetersyslog_map_parseargs(map, args)
311138032Speter	MAP *map;
311238032Speter	char *args;
311338032Speter{
311438032Speter	char *p = args;
311538032Speter	char *priority = NULL;
311638032Speter
311738032Speter	for (;;)
311838032Speter	{
311938032Speter		while (isascii(*p) && isspace(*p))
312038032Speter			p++;
312138032Speter		if (*p != '-')
312238032Speter			break;
312338032Speter		if (*++p == 'L')
312438032Speter			priority = ++p;
312538032Speter		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
312638032Speter			p++;
312738032Speter		if (*p != '\0')
312838032Speter			*p++ = '\0';
312938032Speter	}
313038032Speter
313138032Speter	if (priority == NULL)
313238032Speter		map->map_prio = LOG_INFO;
313338032Speter	else
313438032Speter	{
313538032Speter		if (strncasecmp("LOG_", priority, 4) == 0)
313638032Speter			priority += 4;
313738032Speter
313838032Speter#ifdef LOG_EMERG
313938032Speter		if (strcasecmp("EMERG", priority) == 0)
314038032Speter			map->map_prio = LOG_EMERG;
314138032Speter		else
314238032Speter#endif
314338032Speter#ifdef LOG_ALERT
314438032Speter		if (strcasecmp("ALERT", priority) == 0)
314538032Speter			map->map_prio = LOG_ALERT;
314638032Speter		else
314738032Speter#endif
314838032Speter#ifdef LOG_CRIT
314938032Speter		if (strcasecmp("CRIT", priority) == 0)
315038032Speter			map->map_prio = LOG_CRIT;
315138032Speter		else
315238032Speter#endif
315338032Speter#ifdef LOG_ERR
315438032Speter		if (strcasecmp("ERR", priority) == 0)
315538032Speter			map->map_prio = LOG_ERR;
315638032Speter		else
315738032Speter#endif
315838032Speter#ifdef LOG_WARNING
315938032Speter		if (strcasecmp("WARNING", priority) == 0)
316038032Speter			map->map_prio = LOG_WARNING;
316138032Speter		else
316238032Speter#endif
316338032Speter#ifdef LOG_NOTICE
316438032Speter		if (strcasecmp("NOTICE", priority) == 0)
316538032Speter			map->map_prio = LOG_NOTICE;
316638032Speter		else
316738032Speter#endif
316838032Speter#ifdef LOG_INFO
316938032Speter		if (strcasecmp("INFO", priority) == 0)
317038032Speter			map->map_prio = LOG_INFO;
317138032Speter		else
317238032Speter#endif
317338032Speter#ifdef LOG_DEBUG
317438032Speter		if (strcasecmp("DEBUG", priority) == 0)
317538032Speter			map->map_prio = LOG_DEBUG;
317638032Speter		else
317738032Speter#endif
317838032Speter		{
317938032Speter			syserr("syslog_map_parseargs: Unknown priority %s\n",
318038032Speter			       priority);
318138032Speter			return FALSE;
318238032Speter		}
318338032Speter	}
318438032Speter	return TRUE;
318538032Speter}
318638032Speter
318738032Speter/*
318838032Speter** SYSLOG_MAP_LOOKUP -- rewrite and syslog message.  Always return empty string
318938032Speter*/
319038032Speter
319138032Speterchar *
319238032Spetersyslog_map_lookup(map, string, args, statp)
319338032Speter	MAP *map;
319438032Speter	char *string;
319538032Speter	char **args;
319638032Speter	int *statp;
319738032Speter{
319838032Speter	char *ptr = map_rewrite(map, string, strlen(string), args);
319938032Speter
320038032Speter	if (ptr != NULL)
320138032Speter	{
320238032Speter		if (tTd(38, 20))
320338032Speter			printf("syslog_map_lookup(%s (priority %d): %s\n",
320438032Speter			       map->map_mname, map->map_prio, ptr);
320538032Speter
320638032Speter		sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
320738032Speter	}
320838032Speter
320938032Speter	*statp = EX_OK;
321038032Speter	return "";
321138032Speter}
321238032Speter
321338032Speter#endif /* _FFR_MAP_SYSLOG */
321438032Speter/*
321538032Speter**  HESIOD Modules
321638032Speter*/
321738032Speter
321838032Speter#ifdef HESIOD
321938032Speter
322038032Speterbool
322138032Speterhes_map_open(map, mode)
322238032Speter	MAP *map;
322338032Speter	int mode;
322438032Speter{
322538032Speter	if (tTd(38, 2))
322638032Speter		printf("hes_map_open(%s, %s, %d)\n",
322738032Speter			map->map_mname, map->map_file, mode);
322838032Speter
322938032Speter	if (mode != O_RDONLY)
323038032Speter	{
323138032Speter		/* issue a pseudo-error message */
323238032Speter#ifdef ENOSYS
323338032Speter		errno = ENOSYS;
323438032Speter#else
323538032Speter# ifdef EFTYPE
323638032Speter		errno = EFTYPE;
323738032Speter# else
323838032Speter		errno = ENXIO;
323938032Speter# endif
324038032Speter#endif
324138032Speter		return FALSE;
324238032Speter	}
324338032Speter
324438032Speter#ifdef HESIOD_INIT
324538032Speter	if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
324638032Speter		return TRUE;
324738032Speter
324838032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
324938032Speter		syserr("421 cannot initialize Hesiod map (%s)",
325038032Speter			errstring(errno));
325138032Speter	return FALSE;
325238032Speter#else
325338032Speter	if (hes_error() == HES_ER_UNINIT)
325438032Speter		hes_init();
325538032Speter	switch (hes_error())
325638032Speter	{
325738032Speter	  case HES_ER_OK:
325838032Speter	  case HES_ER_NOTFOUND:
325938032Speter		return TRUE;
326038032Speter	}
326138032Speter
326238032Speter	if (!bitset(MF_OPTIONAL, map->map_mflags))
326338032Speter		syserr("421 cannot initialize Hesiod map (%d)", hes_error());
326438032Speter
326538032Speter	return FALSE;
326638032Speter#endif /* HESIOD_INIT */
326738032Speter}
326838032Speter
326938032Speterchar *
327038032Speterhes_map_lookup(map, name, av, statp)
327138032Speter	MAP *map;
327238032Speter	char *name;
327338032Speter	char **av;
327438032Speter	int *statp;
327538032Speter{
327638032Speter	char **hp;
327738032Speter
327838032Speter	if (tTd(38, 20))
327938032Speter		printf("hes_map_lookup(%s, %s)\n", map->map_file, name);
328038032Speter
328138032Speter	if (name[0] == '\\')
328238032Speter	{
328338032Speter		char *np;
328438032Speter		int nl;
328538032Speter		char nbuf[MAXNAME];
328638032Speter
328738032Speter		nl = strlen(name);
328838032Speter		if (nl < sizeof nbuf - 1)
328938032Speter			np = nbuf;
329038032Speter		else
329138032Speter			np = xalloc(strlen(name) + 2);
329238032Speter		np[0] = '\\';
329338032Speter		strcpy(&np[1], name);
329438032Speter#ifdef HESIOD_INIT
329538032Speter		hp = hesiod_resolve(HesiodContext, np, map->map_file);
329638032Speter#else
329738032Speter		hp = hes_resolve(np, map->map_file);
329838032Speter#endif /* HESIOD_INIT */
329938032Speter		if (np != nbuf)
330038032Speter			free(np);
330138032Speter	}
330238032Speter	else
330338032Speter	{
330438032Speter#ifdef HESIOD_INIT
330538032Speter		hp = hesiod_resolve(HesiodContext, name, map->map_file);
330638032Speter#else
330738032Speter		hp = hes_resolve(name, map->map_file);
330838032Speter#endif /* HESIOD_INIT */
330938032Speter	}
331038032Speter#ifdef HESIOD_INIT
331138032Speter	if (hp == NULL)
331238032Speter		return NULL;
331338032Speter	if (*hp == NULL)
331438032Speter	{
331538032Speter		hesiod_free_list(HesiodContext, hp);
331638032Speter		switch (errno)
331738032Speter		{
331838032Speter		  case ENOENT:
331938032Speter			  *statp = EX_NOTFOUND;
332038032Speter			  break;
332138032Speter		  case ECONNREFUSED:
332238032Speter		  case EMSGSIZE:
332338032Speter			  *statp = EX_TEMPFAIL;
332438032Speter			  break;
332538032Speter		  case ENOMEM:
332638032Speter		  default:
332738032Speter			  *statp = EX_UNAVAILABLE;
332838032Speter			  break;
332938032Speter		}
333038032Speter		return NULL;
333138032Speter	}
333238032Speter#else
333338032Speter	if (hp == NULL || hp[0] == NULL)
333438032Speter	{
333538032Speter		switch (hes_error())
333638032Speter		{
333738032Speter		  case HES_ER_OK:
333838032Speter			*statp = EX_OK;
333938032Speter			break;
334038032Speter
334138032Speter		  case HES_ER_NOTFOUND:
334238032Speter			*statp = EX_NOTFOUND;
334338032Speter			break;
334438032Speter
334538032Speter		  case HES_ER_CONFIG:
334638032Speter			*statp = EX_UNAVAILABLE;
334738032Speter			break;
334838032Speter
334938032Speter		  case HES_ER_NET:
335038032Speter			*statp = EX_TEMPFAIL;
335138032Speter			break;
335238032Speter		}
335338032Speter		return NULL;
335438032Speter	}
335538032Speter#endif /* HESIOD_INIT */
335638032Speter
335738032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
335838032Speter		return map_rewrite(map, name, strlen(name), NULL);
335938032Speter	else
336038032Speter		return map_rewrite(map, hp[0], strlen(hp[0]), av);
336138032Speter}
336238032Speter
336338032Speter#endif
336438032Speter/*
336538032Speter**  NeXT NETINFO Modules
336638032Speter*/
336738032Speter
336838032Speter#if NETINFO
336938032Speter
337038032Speter# define NETINFO_DEFAULT_DIR		"/aliases"
337138032Speter# define NETINFO_DEFAULT_PROPERTY	"members"
337238032Speter
337338032Speterextern char	*ni_propval __P((char *, char *, char *, char *, int));
337438032Speter
337538032Speter
337638032Speter/*
337738032Speter**  NI_MAP_OPEN -- open NetInfo Aliases
337838032Speter*/
337938032Speter
338038032Speterbool
338138032Speterni_map_open(map, mode)
338238032Speter	MAP *map;
338338032Speter	int mode;
338438032Speter{
338538032Speter	char *p;
338638032Speter
338738032Speter	if (tTd(38, 2))
338838032Speter		printf("ni_map_open(%s, %s, %d)\n",
338938032Speter			map->map_mname, map->map_file, mode);
339038032Speter	mode &= O_ACCMODE;
339138032Speter
339238032Speter	if (*map->map_file == '\0')
339338032Speter		map->map_file = NETINFO_DEFAULT_DIR;
339438032Speter
339538032Speter	if (map->map_valcolnm == NULL)
339638032Speter		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
339738032Speter
339838032Speter	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
339938032Speter		map->map_coldelim = ',';
340038032Speter
340138032Speter	return TRUE;
340238032Speter}
340338032Speter
340438032Speter
340538032Speter/*
340638032Speter**  NI_MAP_LOOKUP -- look up a datum in NetInfo
340738032Speter*/
340838032Speter
340938032Speterchar *
341038032Speterni_map_lookup(map, name, av, statp)
341138032Speter	MAP *map;
341238032Speter	char *name;
341338032Speter	char **av;
341438032Speter	int *statp;
341538032Speter{
341638032Speter	char *res;
341738032Speter	char *propval;
341838032Speter
341938032Speter	if (tTd(38, 20))
342038032Speter		printf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
342138032Speter
342238032Speter	propval = ni_propval(map->map_file, map->map_keycolnm, name,
342338032Speter			     map->map_valcolnm, map->map_coldelim);
342438032Speter
342538032Speter	if (propval == NULL)
342638032Speter		return NULL;
342738032Speter
342838032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
342938032Speter		res = map_rewrite(map, name, strlen(name), NULL);
343038032Speter	else
343138032Speter		res = map_rewrite(map, propval, strlen(propval), av);
343238032Speter	free(propval);
343338032Speter	return res;
343438032Speter}
343538032Speter
343638032Speter
343738032Speterbool
343838032Speterni_getcanonname(name, hbsize, statp)
343938032Speter	char *name;
344038032Speter	int hbsize;
344138032Speter	int *statp;
344238032Speter{
344338032Speter	char *vptr;
344438032Speter	char *ptr;
344538032Speter	char nbuf[MAXNAME + 1];
344638032Speter
344738032Speter	if (tTd(38, 20))
344838032Speter		printf("ni_getcanonname(%s)\n", name);
344938032Speter
345038032Speter	if (strlen(name) >= sizeof nbuf)
345138032Speter	{
345238032Speter		*statp = EX_UNAVAILABLE;
345338032Speter		return FALSE;
345438032Speter	}
345538032Speter	(void) strcpy(nbuf, name);
345638032Speter	shorten_hostname(nbuf);
345738032Speter
345838032Speter	/* we only accept single token search key */
345938032Speter	if (strchr(nbuf, '.'))
346038032Speter	{
346138032Speter		*statp = EX_NOHOST;
346238032Speter		return FALSE;
346338032Speter	}
346438032Speter
346538032Speter	/* Do the search */
346638032Speter	vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
346738032Speter
346838032Speter	if (vptr == NULL)
346938032Speter	{
347038032Speter		*statp = EX_NOHOST;
347138032Speter		return FALSE;
347238032Speter	}
347338032Speter
347438032Speter	/* Only want the first machine name */
347538032Speter	if ((ptr = strchr(vptr, '\n')) != NULL)
347638032Speter		*ptr = '\0';
347738032Speter
347838032Speter	if (hbsize >= strlen(vptr))
347938032Speter	{
348038032Speter		strcpy(name, vptr);
348138032Speter		*statp = EX_OK;
348238032Speter		return TRUE;
348338032Speter	}
348438032Speter	*statp = EX_UNAVAILABLE;
348538032Speter	free(vptr);
348638032Speter	return FALSE;
348738032Speter}
348838032Speter
348938032Speter
349038032Speter/*
349138032Speter**  NI_PROPVAL -- NetInfo property value lookup routine
349238032Speter**
349338032Speter**	Parameters:
349438032Speter**		keydir -- the NetInfo directory name in which to search
349538032Speter**			for the key.
349638032Speter**		keyprop -- the name of the property in which to find the
349738032Speter**			property we are interested.  Defaults to "name".
349838032Speter**		keyval -- the value for which we are really searching.
349938032Speter**		valprop -- the property name for the value in which we
350038032Speter**			are interested.
350138032Speter**		sepchar -- if non-nil, this can be multiple-valued, and
350238032Speter**			we should return a string separated by this
350338032Speter**			character.
350438032Speter**
350538032Speter**	Returns:
350638032Speter**		NULL -- if:
350738032Speter**			1. the directory is not found
350838032Speter**			2. the property name is not found
350938032Speter**			3. the property contains multiple values
351038032Speter**			4. some error occured
351138032Speter**		else -- the value of the lookup.
351238032Speter**
351338032Speter**	Example:
351438032Speter**		To search for an alias value, use:
351538032Speter**		  ni_propval("/aliases", "name", aliasname, "members", ',')
351638032Speter**
351738032Speter**	Notes:
351838032Speter**      	Caller should free the return value of ni_proval
351938032Speter*/
352038032Speter
352138032Speter# include <netinfo/ni.h>
352238032Speter
352338032Speter# define LOCAL_NETINFO_DOMAIN    "."
352438032Speter# define PARENT_NETINFO_DOMAIN   ".."
352538032Speter# define MAX_NI_LEVELS           256
352638032Speter
352738032Speterchar *
352838032Speterni_propval(keydir, keyprop, keyval, valprop, sepchar)
352938032Speter	char *keydir;
353038032Speter	char *keyprop;
353138032Speter	char *keyval;
353238032Speter	char *valprop;
353338032Speter	int sepchar;
353438032Speter{
353538032Speter	char *propval = NULL;
353638032Speter	int i;
353738032Speter	int j, alen;
353838032Speter	void *ni = NULL;
353938032Speter	void *lastni = NULL;
354038032Speter	ni_status nis;
354138032Speter	ni_id nid;
354238032Speter	ni_namelist ninl;
354338032Speter	register char *p;
354438032Speter	char keybuf[1024];
354538032Speter
354638032Speter	/*
354738032Speter	**  Create the full key from the two parts.
354838032Speter	**
354938032Speter	**	Note that directory can end with, e.g., "name=" to specify
355038032Speter	**	an alternate search property.
355138032Speter	*/
355238032Speter
355338032Speter	i = strlen(keydir) + strlen(keyval) + 2;
355438032Speter	if (keyprop != NULL)
355538032Speter		i += strlen(keyprop) + 1;
355638032Speter	if (i > sizeof keybuf)
355738032Speter		return NULL;
355838032Speter	strcpy(keybuf, keydir);
355938032Speter	strcat(keybuf, "/");
356038032Speter	if (keyprop != NULL)
356138032Speter	{
356238032Speter		strcat(keybuf, keyprop);
356338032Speter		strcat(keybuf, "=");
356438032Speter	}
356538032Speter	strcat(keybuf, keyval);
356638032Speter
356738032Speter	if (tTd(38, 21))
356838032Speter		printf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
356938032Speter			keydir, keyprop, keyval, valprop, sepchar, keybuf);
357038032Speter	/*
357138032Speter	**  If the passed directory and property name are found
357238032Speter	**  in one of netinfo domains we need to search (starting
357338032Speter	**  from the local domain moving all the way back to the
357438032Speter	**  root domain) set propval to the property's value
357538032Speter	**  and return it.
357638032Speter	*/
357738032Speter
357838032Speter	for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
357938032Speter	{
358038032Speter		if (i == 0)
358138032Speter		{
358238032Speter			nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
358338032Speter			if (tTd(38, 20))
358438032Speter				printf("ni_open(LOCAL) = %d\n", nis);
358538032Speter		}
358638032Speter		else
358738032Speter		{
358838032Speter			if (lastni != NULL)
358938032Speter				ni_free(lastni);
359038032Speter			lastni = ni;
359138032Speter			nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
359238032Speter			if (tTd(38, 20))
359338032Speter				printf("ni_open(PARENT) = %d\n", nis);
359438032Speter		}
359538032Speter
359638032Speter		/*
359738032Speter		**  Don't bother if we didn't get a handle on a
359838032Speter		**  proper domain.  This is not necessarily an error.
359938032Speter		**  We would get a positive ni_status if, for instance
360038032Speter		**  we never found the directory or property and tried
360138032Speter		**  to open the parent of the root domain!
360238032Speter		*/
360338032Speter
360438032Speter		if (nis != 0)
360538032Speter			break;
360638032Speter
360738032Speter		/*
360838032Speter		**  Find the path to the server information.
360938032Speter		*/
361038032Speter
361138032Speter		if (ni_pathsearch(ni, &nid, keybuf) != 0)
361238032Speter			continue;
361338032Speter
361438032Speter		/*
361538032Speter		**  Find associated value information.
361638032Speter		*/
361738032Speter
361838032Speter		if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
361938032Speter			continue;
362038032Speter
362138032Speter		if (tTd(38, 20))
362238032Speter			printf("ni_lookupprop: len=%d\n", ninl.ni_namelist_len);
362338032Speter		/*
362438032Speter		**  See if we have an acceptable number of values.
362538032Speter		*/
362638032Speter
362738032Speter		if (ninl.ni_namelist_len <= 0)
362838032Speter			continue;
362938032Speter
363038032Speter		if (sepchar == '\0' && ninl.ni_namelist_len > 1)
363138032Speter		{
363238032Speter			ni_namelist_free(&ninl);
363338032Speter			continue;
363438032Speter		}
363538032Speter
363638032Speter		/*
363738032Speter		**  Calculate number of bytes needed and build result
363838032Speter		*/
363938032Speter
364038032Speter		alen = 1;
364138032Speter		for (j = 0; j < ninl.ni_namelist_len; j++)
364238032Speter			alen += strlen(ninl.ni_namelist_val[j]) + 1;
364338032Speter		propval = p = xalloc(alen);
364438032Speter		for (j = 0; j < ninl.ni_namelist_len; j++)
364538032Speter		{
364638032Speter			strcpy(p, ninl.ni_namelist_val[j]);
364738032Speter			p += strlen(p);
364838032Speter			*p++ = sepchar;
364938032Speter		}
365038032Speter		*--p = '\0';
365138032Speter
365238032Speter		ni_namelist_free(&ninl);
365338032Speter	}
365438032Speter
365538032Speter	/*
365638032Speter	**  Clean up.
365738032Speter	*/
365838032Speter
365938032Speter	if (ni != NULL)
366038032Speter		ni_free(ni);
366138032Speter	if (lastni != NULL && ni != lastni)
366238032Speter		ni_free(lastni);
366338032Speter	if (tTd(38, 20))
366438032Speter		printf("ni_propval returns: '%s'\n", propval);
366538032Speter
366638032Speter	return propval;
366738032Speter}
366838032Speter
366938032Speter#endif
367038032Speter/*
367138032Speter**  TEXT (unindexed text file) Modules
367238032Speter**
367338032Speter**	This code donated by Sun Microsystems.
367438032Speter*/
367538032Speter
367638032Speter#define map_sff		map_lockfd	/* overload field */
367738032Speter
367838032Speter
367938032Speter/*
368038032Speter**  TEXT_MAP_OPEN -- open text table
368138032Speter*/
368238032Speter
368338032Speterbool
368438032Spetertext_map_open(map, mode)
368538032Speter	MAP *map;
368638032Speter	int mode;
368738032Speter{
368838032Speter	int sff;
368938032Speter	int i;
369038032Speter
369138032Speter	if (tTd(38, 2))
369238032Speter		printf("text_map_open(%s, %s, %d)\n",
369338032Speter			map->map_mname, map->map_file, mode);
369438032Speter
369538032Speter	mode &= O_ACCMODE;
369638032Speter	if (mode != O_RDONLY)
369738032Speter	{
369838032Speter		errno = EPERM;
369938032Speter		return FALSE;
370038032Speter	}
370138032Speter
370238032Speter	if (*map->map_file == '\0')
370338032Speter	{
370438032Speter		syserr("text map \"%s\": file name required",
370538032Speter			map->map_mname);
370638032Speter		return FALSE;
370738032Speter	}
370838032Speter
370938032Speter	if (map->map_file[0] != '/')
371038032Speter	{
371138032Speter		syserr("text map \"%s\": file name must be fully qualified",
371238032Speter			map->map_mname);
371338032Speter		return FALSE;
371438032Speter	}
371538032Speter
371638032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
371738032Speter	if (!bitset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
371838032Speter		sff |= SFF_NOWLINK;
371938032Speter	if (!bitset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
372038032Speter		sff |= SFF_SAFEDIRPATH;
372138032Speter	if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
372238032Speter			  sff, S_IRUSR, NULL)) != 0)
372338032Speter	{
372438032Speter		/* cannot open this map */
372538032Speter		if (tTd(38, 2))
372638032Speter			printf("\tunsafe map file: %d\n", i);
372738032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
372838032Speter			syserr("text map \"%s\": unsafe map file %s",
372938032Speter				map->map_mname, map->map_file);
373038032Speter		return FALSE;
373138032Speter	}
373238032Speter
373338032Speter	if (map->map_keycolnm == NULL)
373438032Speter		map->map_keycolno = 0;
373538032Speter	else
373638032Speter	{
373738032Speter		if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
373838032Speter		{
373938032Speter			syserr("text map \"%s\", file %s: -k should specify a number, not %s",
374038032Speter				map->map_mname, map->map_file,
374138032Speter				map->map_keycolnm);
374238032Speter			return FALSE;
374338032Speter		}
374438032Speter		map->map_keycolno = atoi(map->map_keycolnm);
374538032Speter	}
374638032Speter
374738032Speter	if (map->map_valcolnm == NULL)
374838032Speter		map->map_valcolno = 0;
374938032Speter	else
375038032Speter	{
375138032Speter		if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
375238032Speter		{
375338032Speter			syserr("text map \"%s\", file %s: -v should specify a number, not %s",
375438032Speter					map->map_mname, map->map_file,
375538032Speter					map->map_valcolnm);
375638032Speter			return FALSE;
375738032Speter		}
375838032Speter		map->map_valcolno = atoi(map->map_valcolnm);
375938032Speter	}
376038032Speter
376138032Speter	if (tTd(38, 2))
376238032Speter	{
376338032Speter		printf("text_map_open(%s, %s): delimiter = ",
376438032Speter			map->map_mname, map->map_file);
376538032Speter		if (map->map_coldelim == '\0')
376638032Speter			printf("(white space)\n");
376738032Speter		else
376838032Speter			printf("%c\n", map->map_coldelim);
376938032Speter	}
377038032Speter
377138032Speter	map->map_sff = sff;
377238032Speter	return TRUE;
377338032Speter}
377438032Speter
377538032Speter
377638032Speter/*
377738032Speter**  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
377838032Speter*/
377938032Speter
378038032Speterchar *
378138032Spetertext_map_lookup(map, name, av, statp)
378238032Speter	MAP *map;
378338032Speter	char *name;
378438032Speter	char **av;
378538032Speter	int *statp;
378638032Speter{
378738032Speter	char *vp;
378838032Speter	auto int vsize;
378938032Speter	int buflen;
379038032Speter	FILE *f;
379138032Speter	char delim;
379238032Speter	int key_idx;
379338032Speter	bool found_it;
379438032Speter	int sff = map->map_sff;
379538032Speter	char search_key[MAXNAME + 1];
379638032Speter	char linebuf[MAXLINE];
379738032Speter	char buf[MAXNAME + 1];
379838032Speter	extern char *get_column __P((char *, int, char, char *, int));
379938032Speter
380038032Speter	found_it = FALSE;
380138032Speter	if (tTd(38, 20))
380238032Speter		printf("text_map_lookup(%s, %s)\n", map->map_mname,  name);
380338032Speter
380438032Speter	buflen = strlen(name);
380538032Speter	if (buflen > sizeof search_key - 1)
380638032Speter		buflen = sizeof search_key - 1;
380738032Speter	bcopy(name, search_key, buflen);
380838032Speter	search_key[buflen] = '\0';
380938032Speter	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
381038032Speter		makelower(search_key);
381138032Speter
381238032Speter	f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
381338032Speter	if (f == NULL)
381438032Speter	{
381538032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
381638032Speter		*statp = EX_UNAVAILABLE;
381738032Speter		return NULL;
381838032Speter	}
381938032Speter	key_idx = map->map_keycolno;
382038032Speter	delim = map->map_coldelim;
382138032Speter	while (fgets(linebuf, MAXLINE, f) != NULL)
382238032Speter	{
382338032Speter		char *p;
382438032Speter
382538032Speter		/* skip comment line */
382638032Speter		if (linebuf[0] == '#')
382738032Speter			continue;
382838032Speter		p = strchr(linebuf, '\n');
382938032Speter		if (p != NULL)
383038032Speter			*p = '\0';
383138032Speter		p = get_column(linebuf, key_idx, delim, buf, sizeof buf);
383238032Speter		if (p != NULL && strcasecmp(search_key, p) == 0)
383338032Speter		{
383438032Speter			found_it = TRUE;
383538032Speter			break;
383638032Speter		}
383738032Speter	}
383838032Speter	fclose(f);
383938032Speter	if (!found_it)
384038032Speter	{
384138032Speter		*statp = EX_NOTFOUND;
384238032Speter		return NULL;
384338032Speter	}
384438032Speter	vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof buf);
384538032Speter	vsize = strlen(vp);
384638032Speter	*statp = EX_OK;
384738032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
384838032Speter		return map_rewrite(map, name, strlen(name), NULL);
384938032Speter	else
385038032Speter		return map_rewrite(map, vp, vsize, av);
385138032Speter}
385238032Speter
385338032Speter
385438032Speter/*
385538032Speter**  TEXT_GETCANONNAME -- look up canonical name in hosts file
385638032Speter*/
385738032Speter
385838032Speterbool
385938032Spetertext_getcanonname(name, hbsize, statp)
386038032Speter	char *name;
386138032Speter	int hbsize;
386238032Speter	int *statp;
386338032Speter{
386438032Speter	bool found;
386538032Speter	FILE *f;
386638032Speter	char linebuf[MAXLINE];
386738032Speter	char cbuf[MAXNAME + 1];
386838032Speter	char nbuf[MAXNAME + 1];
386938032Speter
387038032Speter	if (tTd(38, 20))
387138032Speter		printf("text_getcanonname(%s)\n", name);
387238032Speter
387338032Speter	if (strlen(name) >= (SIZE_T) sizeof nbuf)
387438032Speter	{
387538032Speter		*statp = EX_UNAVAILABLE;
387638032Speter		return FALSE;
387738032Speter	}
387838032Speter	(void) strcpy(nbuf, name);
387938032Speter	shorten_hostname(nbuf);
388038032Speter
388138032Speter	f = fopen(HostsFile, "r");
388238032Speter	if (f == NULL)
388338032Speter	{
388438032Speter		*statp = EX_UNAVAILABLE;
388538032Speter		return FALSE;
388638032Speter	}
388738032Speter	found = FALSE;
388838032Speter	while (!found && fgets(linebuf, MAXLINE, f) != NULL)
388938032Speter	{
389038032Speter		char *p = strpbrk(linebuf, "#\n");
389138032Speter
389238032Speter		if (p != NULL)
389338032Speter			*p = '\0';
389438032Speter		if (linebuf[0] != '\0')
389538032Speter			found = extract_canonname(nbuf, linebuf, cbuf, sizeof cbuf);
389638032Speter	}
389738032Speter	fclose(f);
389838032Speter	if (!found)
389938032Speter	{
390038032Speter		*statp = EX_NOHOST;
390138032Speter		return FALSE;
390238032Speter	}
390338032Speter
390438032Speter	if ((SIZE_T) hbsize >= strlen(cbuf))
390538032Speter	{
390638032Speter		strcpy(name, cbuf);
390738032Speter		*statp = EX_OK;
390838032Speter		return TRUE;
390938032Speter	}
391038032Speter	*statp = EX_UNAVAILABLE;
391138032Speter	return FALSE;
391238032Speter}
391338032Speter/*
391438032Speter**  STAB (Symbol Table) Modules
391538032Speter*/
391638032Speter
391738032Speter
391838032Speter/*
391938032Speter**  STAB_MAP_LOOKUP -- look up alias in symbol table
392038032Speter*/
392138032Speter
392238032Speter/* ARGSUSED2 */
392338032Speterchar *
392438032Speterstab_map_lookup(map, name, av, pstat)
392538032Speter	register MAP *map;
392638032Speter	char *name;
392738032Speter	char **av;
392838032Speter	int *pstat;
392938032Speter{
393038032Speter	register STAB *s;
393138032Speter
393238032Speter	if (tTd(38, 20))
393338032Speter		printf("stab_lookup(%s, %s)\n",
393438032Speter			map->map_mname, name);
393538032Speter
393638032Speter	s = stab(name, ST_ALIAS, ST_FIND);
393738032Speter	if (s != NULL)
393838032Speter		return (s->s_alias);
393938032Speter	return (NULL);
394038032Speter}
394138032Speter
394238032Speter
394338032Speter/*
394438032Speter**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
394538032Speter*/
394638032Speter
394738032Spetervoid
394838032Speterstab_map_store(map, lhs, rhs)
394938032Speter	register MAP *map;
395038032Speter	char *lhs;
395138032Speter	char *rhs;
395238032Speter{
395338032Speter	register STAB *s;
395438032Speter
395538032Speter	s = stab(lhs, ST_ALIAS, ST_ENTER);
395638032Speter	s->s_alias = newstr(rhs);
395738032Speter}
395838032Speter
395938032Speter
396038032Speter/*
396138032Speter**  STAB_MAP_OPEN -- initialize (reads data file)
396238032Speter**
396338032Speter**	This is a wierd case -- it is only intended as a fallback for
396438032Speter**	aliases.  For this reason, opens for write (only during a
396538032Speter**	"newaliases") always fails, and opens for read open the
396638032Speter**	actual underlying text file instead of the database.
396738032Speter*/
396838032Speter
396938032Speterbool
397038032Speterstab_map_open(map, mode)
397138032Speter	register MAP *map;
397238032Speter	int mode;
397338032Speter{
397438032Speter	FILE *af;
397538032Speter	int sff;
397638032Speter	struct stat st;
397738032Speter
397838032Speter	if (tTd(38, 2))
397938032Speter		printf("stab_map_open(%s, %s, %d)\n",
398038032Speter			map->map_mname, map->map_file, mode);
398138032Speter
398238032Speter	mode &= O_ACCMODE;
398338032Speter	if (mode != O_RDONLY)
398438032Speter	{
398538032Speter		errno = EPERM;
398638032Speter		return FALSE;
398738032Speter	}
398838032Speter
398938032Speter	sff = SFF_ROOTOK|SFF_REGONLY;
399038032Speter	if (!bitset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
399138032Speter		sff |= SFF_NOWLINK;
399238032Speter	if (!bitset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
399338032Speter		sff |= SFF_SAFEDIRPATH;
399438032Speter	af = safefopen(map->map_file, O_RDONLY, 0444, sff);
399538032Speter	if (af == NULL)
399638032Speter		return FALSE;
399738032Speter	readaliases(map, af, FALSE, FALSE);
399838032Speter
399938032Speter	if (fstat(fileno(af), &st) >= 0)
400038032Speter		map->map_mtime = st.st_mtime;
400138032Speter	fclose(af);
400238032Speter
400338032Speter	return TRUE;
400438032Speter}
400538032Speter/*
400638032Speter**  Implicit Modules
400738032Speter**
400838032Speter**	Tries several types.  For back compatibility of aliases.
400938032Speter*/
401038032Speter
401138032Speter
401238032Speter/*
401338032Speter**  IMPL_MAP_LOOKUP -- lookup in best open database
401438032Speter*/
401538032Speter
401638032Speterchar *
401738032Speterimpl_map_lookup(map, name, av, pstat)
401838032Speter	MAP *map;
401938032Speter	char *name;
402038032Speter	char **av;
402138032Speter	int *pstat;
402238032Speter{
402338032Speter	if (tTd(38, 20))
402438032Speter		printf("impl_map_lookup(%s, %s)\n",
402538032Speter			map->map_mname, name);
402638032Speter
402738032Speter#ifdef NEWDB
402838032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
402938032Speter		return db_map_lookup(map, name, av, pstat);
403038032Speter#endif
403138032Speter#ifdef NDBM
403238032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
403338032Speter		return ndbm_map_lookup(map, name, av, pstat);
403438032Speter#endif
403538032Speter	return stab_map_lookup(map, name, av, pstat);
403638032Speter}
403738032Speter
403838032Speter/*
403938032Speter**  IMPL_MAP_STORE -- store in open databases
404038032Speter*/
404138032Speter
404238032Spetervoid
404338032Speterimpl_map_store(map, lhs, rhs)
404438032Speter	MAP *map;
404538032Speter	char *lhs;
404638032Speter	char *rhs;
404738032Speter{
404838032Speter	if (tTd(38, 12))
404938032Speter		printf("impl_map_store(%s, %s, %s)\n",
405038032Speter			map->map_mname, lhs, rhs);
405138032Speter#ifdef NEWDB
405238032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
405338032Speter		db_map_store(map, lhs, rhs);
405438032Speter#endif
405538032Speter#ifdef NDBM
405638032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
405738032Speter		ndbm_map_store(map, lhs, rhs);
405838032Speter#endif
405938032Speter	stab_map_store(map, lhs, rhs);
406038032Speter}
406138032Speter
406238032Speter/*
406338032Speter**  IMPL_MAP_OPEN -- implicit database open
406438032Speter*/
406538032Speter
406638032Speterbool
406738032Speterimpl_map_open(map, mode)
406838032Speter	MAP *map;
406938032Speter	int mode;
407038032Speter{
407138032Speter	if (tTd(38, 2))
407238032Speter		printf("impl_map_open(%s, %s, %d)\n",
407338032Speter			map->map_mname, map->map_file, mode);
407438032Speter
407538032Speter	mode &= O_ACCMODE;
407638032Speter#ifdef NEWDB
407738032Speter	map->map_mflags |= MF_IMPL_HASH;
407838032Speter	if (hash_map_open(map, mode))
407938032Speter	{
408038032Speter# ifdef NDBM_YP_COMPAT
408138032Speter		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
408238032Speter# endif
408338032Speter			return TRUE;
408438032Speter	}
408538032Speter	else
408638032Speter		map->map_mflags &= ~MF_IMPL_HASH;
408738032Speter#endif
408838032Speter#ifdef NDBM
408938032Speter	map->map_mflags |= MF_IMPL_NDBM;
409038032Speter	if (ndbm_map_open(map, mode))
409138032Speter	{
409238032Speter		return TRUE;
409338032Speter	}
409438032Speter	else
409538032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
409638032Speter#endif
409738032Speter
409838032Speter#if defined(NEWDB) || defined(NDBM)
409938032Speter	if (Verbose)
410038032Speter		message("WARNING: cannot open alias database %s%s",
410138032Speter			map->map_file,
410238032Speter			mode == O_RDONLY ? "; reading text version" : "");
410338032Speter#else
410438032Speter	if (mode != O_RDONLY)
410538032Speter		usrerr("Cannot rebuild aliases: no database format defined");
410638032Speter#endif
410738032Speter
410838032Speter	if (mode == O_RDONLY)
410938032Speter		return stab_map_open(map, mode);
411038032Speter	else
411138032Speter		return FALSE;
411238032Speter}
411338032Speter
411438032Speter
411538032Speter/*
411638032Speter**  IMPL_MAP_CLOSE -- close any open database(s)
411738032Speter*/
411838032Speter
411938032Spetervoid
412038032Speterimpl_map_close(map)
412138032Speter	MAP *map;
412238032Speter{
412338032Speter	if (tTd(38, 9))
412438032Speter		printf("impl_map_close(%s, %s, %lx)\n",
412538032Speter			map->map_mname, map->map_file, map->map_mflags);
412638032Speter#ifdef NEWDB
412738032Speter	if (bitset(MF_IMPL_HASH, map->map_mflags))
412838032Speter	{
412938032Speter		db_map_close(map);
413038032Speter		map->map_mflags &= ~MF_IMPL_HASH;
413138032Speter	}
413238032Speter#endif
413338032Speter
413438032Speter#ifdef NDBM
413538032Speter	if (bitset(MF_IMPL_NDBM, map->map_mflags))
413638032Speter	{
413738032Speter		ndbm_map_close(map);
413838032Speter		map->map_mflags &= ~MF_IMPL_NDBM;
413938032Speter	}
414038032Speter#endif
414138032Speter}
414238032Speter/*
414338032Speter**  User map class.
414438032Speter**
414538032Speter**	Provides access to the system password file.
414638032Speter*/
414738032Speter
414838032Speter/*
414938032Speter**  USER_MAP_OPEN -- open user map
415038032Speter**
415138032Speter**	Really just binds field names to field numbers.
415238032Speter*/
415338032Speter
415438032Speterbool
415538032Speteruser_map_open(map, mode)
415638032Speter	MAP *map;
415738032Speter	int mode;
415838032Speter{
415938032Speter	if (tTd(38, 2))
416038032Speter		printf("user_map_open(%s, %d)\n",
416138032Speter			map->map_mname, mode);
416238032Speter
416338032Speter	mode &= O_ACCMODE;
416438032Speter	if (mode != O_RDONLY)
416538032Speter	{
416638032Speter		/* issue a pseudo-error message */
416738032Speter#ifdef ENOSYS
416838032Speter		errno = ENOSYS;
416938032Speter#else
417038032Speter# ifdef EFTYPE
417138032Speter		errno = EFTYPE;
417238032Speter# else
417338032Speter		errno = ENXIO;
417438032Speter# endif
417538032Speter#endif
417638032Speter		return FALSE;
417738032Speter	}
417838032Speter	if (map->map_valcolnm == NULL)
417938032Speter		/* nothing */ ;
418038032Speter	else if (strcasecmp(map->map_valcolnm, "name") == 0)
418138032Speter		map->map_valcolno = 1;
418238032Speter	else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
418338032Speter		map->map_valcolno = 2;
418438032Speter	else if (strcasecmp(map->map_valcolnm, "uid") == 0)
418538032Speter		map->map_valcolno = 3;
418638032Speter	else if (strcasecmp(map->map_valcolnm, "gid") == 0)
418738032Speter		map->map_valcolno = 4;
418838032Speter	else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
418938032Speter		map->map_valcolno = 5;
419038032Speter	else if (strcasecmp(map->map_valcolnm, "dir") == 0)
419138032Speter		map->map_valcolno = 6;
419238032Speter	else if (strcasecmp(map->map_valcolnm, "shell") == 0)
419338032Speter		map->map_valcolno = 7;
419438032Speter	else
419538032Speter	{
419638032Speter		syserr("User map %s: unknown column name %s",
419738032Speter			map->map_mname, map->map_valcolnm);
419838032Speter		return FALSE;
419938032Speter	}
420038032Speter	return TRUE;
420138032Speter}
420238032Speter
420338032Speter
420438032Speter/*
420538032Speter**  USER_MAP_LOOKUP -- look up a user in the passwd file.
420638032Speter*/
420738032Speter
420838032Speter/* ARGSUSED3 */
420938032Speterchar *
421038032Speteruser_map_lookup(map, key, av, statp)
421138032Speter	MAP *map;
421238032Speter	char *key;
421338032Speter	char **av;
421438032Speter	int *statp;
421538032Speter{
421638032Speter	struct passwd *pw;
421738032Speter	auto bool fuzzy;
421838032Speter
421938032Speter	if (tTd(38, 20))
422038032Speter		printf("user_map_lookup(%s, %s)\n",
422138032Speter			map->map_mname, key);
422238032Speter
422338032Speter	pw = finduser(key, &fuzzy);
422438032Speter	if (pw == NULL)
422538032Speter		return NULL;
422638032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
422738032Speter		return map_rewrite(map, key, strlen(key), NULL);
422838032Speter	else
422938032Speter	{
423038032Speter		char *rwval = NULL;
423138032Speter		char buf[30];
423238032Speter
423338032Speter		switch (map->map_valcolno)
423438032Speter		{
423538032Speter		  case 0:
423638032Speter		  case 1:
423738032Speter			rwval = pw->pw_name;
423838032Speter			break;
423938032Speter
424038032Speter		  case 2:
424138032Speter			rwval = pw->pw_passwd;
424238032Speter			break;
424338032Speter
424438032Speter		  case 3:
424538032Speter			snprintf(buf, sizeof buf, "%d", pw->pw_uid);
424638032Speter			rwval = buf;
424738032Speter			break;
424838032Speter
424938032Speter		  case 4:
425038032Speter			snprintf(buf, sizeof buf, "%d", pw->pw_gid);
425138032Speter			rwval = buf;
425238032Speter			break;
425338032Speter
425438032Speter		  case 5:
425538032Speter			rwval = pw->pw_gecos;
425638032Speter			break;
425738032Speter
425838032Speter		  case 6:
425938032Speter			rwval = pw->pw_dir;
426038032Speter			break;
426138032Speter
426238032Speter		  case 7:
426338032Speter			rwval = pw->pw_shell;
426438032Speter			break;
426538032Speter		}
426638032Speter		return map_rewrite(map, rwval, strlen(rwval), av);
426738032Speter	}
426838032Speter}
426938032Speter/*
427038032Speter**  Program map type.
427138032Speter**
427238032Speter**	This provides access to arbitrary programs.  It should be used
427338032Speter**	only very sparingly, since there is no way to bound the cost
427438032Speter**	of invoking an arbitrary program.
427538032Speter*/
427638032Speter
427738032Speterchar *
427838032Speterprog_map_lookup(map, name, av, statp)
427938032Speter	MAP *map;
428038032Speter	char *name;
428138032Speter	char **av;
428238032Speter	int *statp;
428338032Speter{
428438032Speter	int i;
428538032Speter	register char *p;
428638032Speter	int fd;
428738032Speter	auto pid_t pid;
428838032Speter	char *rval;
428938032Speter	int stat;
429038032Speter	char *argv[MAXPV + 1];
429138032Speter	char buf[MAXLINE];
429238032Speter
429338032Speter	if (tTd(38, 20))
429438032Speter		printf("prog_map_lookup(%s, %s) %s\n",
429538032Speter			map->map_mname, name, map->map_file);
429638032Speter
429738032Speter	i = 0;
429838032Speter	argv[i++] = map->map_file;
429938032Speter	if (map->map_rebuild != NULL)
430038032Speter	{
430138032Speter		snprintf(buf, sizeof buf, "%s", map->map_rebuild);
430238032Speter		for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
430338032Speter		{
430438032Speter			if (i >= MAXPV - 1)
430538032Speter				break;
430638032Speter			argv[i++] = p;
430738032Speter		}
430838032Speter	}
430938032Speter	argv[i++] = name;
431038032Speter	argv[i] = NULL;
431138032Speter	if (tTd(38, 21))
431238032Speter	{
431338032Speter		printf("prog_open:");
431438032Speter		for (i = 0; argv[i] != NULL; i++)
431538032Speter			printf(" %s", argv[i]);
431638032Speter		printf("\n");
431738032Speter	}
431838032Speter	(void) blocksignal(SIGCHLD);
431938032Speter	pid = prog_open(argv, &fd, CurEnv);
432038032Speter	if (pid < 0)
432138032Speter	{
432238032Speter		if (!bitset(MF_OPTIONAL, map->map_mflags))
432338032Speter			syserr("prog_map_lookup(%s) failed (%s) -- closing",
432438032Speter				map->map_mname, errstring(errno));
432538032Speter		else if (tTd(38, 9))
432638032Speter			printf("prog_map_lookup(%s) failed (%s) -- closing",
432738032Speter				map->map_mname, errstring(errno));
432838032Speter		map->map_mflags &= ~(MF_VALID|MF_OPEN);
432938032Speter		*statp = EX_OSFILE;
433038032Speter		return NULL;
433138032Speter	}
433238032Speter	i = read(fd, buf, sizeof buf - 1);
433338032Speter	if (i < 0)
433438032Speter	{
433538032Speter		syserr("prog_map_lookup(%s): read error %s\n",
433638032Speter			map->map_mname, errstring(errno));
433738032Speter		rval = NULL;
433838032Speter	}
433938032Speter	else if (i == 0)
434038032Speter	{
434138032Speter		if (tTd(38, 20))
434238032Speter			printf("prog_map_lookup(%s): empty answer\n",
434338032Speter				map->map_mname);
434438032Speter		rval = NULL;
434538032Speter	}
434638032Speter	else
434738032Speter	{
434838032Speter		buf[i] = '\0';
434938032Speter		p = strchr(buf, '\n');
435038032Speter		if (p != NULL)
435138032Speter			*p = '\0';
435238032Speter
435338032Speter		/* collect the return value */
435438032Speter		if (bitset(MF_MATCHONLY, map->map_mflags))
435538032Speter			rval = map_rewrite(map, name, strlen(name), NULL);
435638032Speter		else
435738032Speter			rval = map_rewrite(map, buf, strlen(buf), NULL);
435838032Speter
435938032Speter		/* now flush any additional output */
436038032Speter		while ((i = read(fd, buf, sizeof buf)) > 0)
436138032Speter			continue;
436238032Speter	}
436338032Speter
436438032Speter	/* wait for the process to terminate */
436538032Speter	close(fd);
436638032Speter	stat = waitfor(pid);
436738032Speter	(void) releasesignal(SIGCHLD);
436838032Speter
436938032Speter	if (stat == -1)
437038032Speter	{
437138032Speter		syserr("prog_map_lookup(%s): wait error %s\n",
437238032Speter			map->map_mname, errstring(errno));
437338032Speter		*statp = EX_SOFTWARE;
437438032Speter		rval = NULL;
437538032Speter	}
437638032Speter	else if (WIFEXITED(stat))
437738032Speter	{
437838032Speter		if ((*statp = WEXITSTATUS(stat)) != EX_OK)
437938032Speter			rval = NULL;
438038032Speter	}
438138032Speter	else
438238032Speter	{
438338032Speter		syserr("prog_map_lookup(%s): child died on signal %d",
438438032Speter			map->map_mname, stat);
438538032Speter		*statp = EX_UNAVAILABLE;
438638032Speter		rval = NULL;
438738032Speter	}
438838032Speter	return rval;
438938032Speter}
439038032Speter/*
439138032Speter**  Sequenced map type.
439238032Speter**
439338032Speter**	Tries each map in order until something matches, much like
439438032Speter**	implicit.  Stores go to the first map in the list that can
439538032Speter**	support storing.
439638032Speter**
439738032Speter**	This is slightly unusual in that there are two interfaces.
439838032Speter**	The "sequence" interface lets you stack maps arbitrarily.
439938032Speter**	The "switch" interface builds a sequence map by looking
440038032Speter**	at a system-dependent configuration file such as
440138032Speter**	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
440238032Speter**
440338032Speter**	We don't need an explicit open, since all maps are
440438032Speter**	opened during startup, including underlying maps.
440538032Speter*/
440638032Speter
440738032Speter/*
440838032Speter**  SEQ_MAP_PARSE -- Sequenced map parsing
440938032Speter*/
441038032Speter
441138032Speterbool
441238032Speterseq_map_parse(map, ap)
441338032Speter	MAP *map;
441438032Speter	char *ap;
441538032Speter{
441638032Speter	int maxmap;
441738032Speter
441838032Speter	if (tTd(38, 2))
441938032Speter		printf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
442038032Speter	maxmap = 0;
442138032Speter	while (*ap != '\0')
442238032Speter	{
442338032Speter		register char *p;
442438032Speter		STAB *s;
442538032Speter
442638032Speter		/* find beginning of map name */
442738032Speter		while (isascii(*ap) && isspace(*ap))
442838032Speter			ap++;
442938032Speter		for (p = ap; isascii(*p) && isalnum(*p); p++)
443038032Speter			continue;
443138032Speter		if (*p != '\0')
443238032Speter			*p++ = '\0';
443338032Speter		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
443438032Speter			p++;
443538032Speter		if (*ap == '\0')
443638032Speter		{
443738032Speter			ap = p;
443838032Speter			continue;
443938032Speter		}
444038032Speter		s = stab(ap, ST_MAP, ST_FIND);
444138032Speter		if (s == NULL)
444238032Speter		{
444338032Speter			syserr("Sequence map %s: unknown member map %s",
444438032Speter				map->map_mname, ap);
444538032Speter		}
444638032Speter		else if (maxmap == MAXMAPSTACK)
444738032Speter		{
444838032Speter			syserr("Sequence map %s: too many member maps (%d max)",
444938032Speter				map->map_mname, MAXMAPSTACK);
445038032Speter			maxmap++;
445138032Speter		}
445238032Speter		else if (maxmap < MAXMAPSTACK)
445338032Speter		{
445438032Speter			map->map_stack[maxmap++] = &s->s_map;
445538032Speter		}
445638032Speter		ap = p;
445738032Speter	}
445838032Speter	return TRUE;
445938032Speter}
446038032Speter
446138032Speter
446238032Speter/*
446338032Speter**  SWITCH_MAP_OPEN -- open a switched map
446438032Speter**
446538032Speter**	This looks at the system-dependent configuration and builds
446638032Speter**	a sequence map that does the same thing.
446738032Speter**
446838032Speter**	Every system must define a switch_map_find routine in conf.c
446938032Speter**	that will return the list of service types associated with a
447038032Speter**	given service class.
447138032Speter*/
447238032Speter
447338032Speterbool
447438032Speterswitch_map_open(map, mode)
447538032Speter	MAP *map;
447638032Speter	int mode;
447738032Speter{
447838032Speter	int mapno;
447938032Speter	int nmaps;
448038032Speter	char *maptype[MAXMAPSTACK];
448138032Speter
448238032Speter	if (tTd(38, 2))
448338032Speter		printf("switch_map_open(%s, %s, %d)\n",
448438032Speter			map->map_mname, map->map_file, mode);
448538032Speter
448638032Speter	mode &= O_ACCMODE;
448738032Speter	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
448838032Speter	if (tTd(38, 19))
448938032Speter	{
449038032Speter		printf("\tswitch_map_find => %d\n", nmaps);
449138032Speter		for (mapno = 0; mapno < nmaps; mapno++)
449238032Speter			printf("\t\t%s\n", maptype[mapno]);
449338032Speter	}
449438032Speter	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
449538032Speter		return FALSE;
449638032Speter
449738032Speter	for (mapno = 0; mapno < nmaps; mapno++)
449838032Speter	{
449938032Speter		register STAB *s;
450038032Speter		char nbuf[MAXNAME + 1];
450138032Speter
450238032Speter		if (maptype[mapno] == NULL)
450338032Speter			continue;
450438032Speter		(void) snprintf(nbuf, sizeof nbuf, "%s.%s",
450538032Speter			map->map_mname, maptype[mapno]);
450638032Speter		s = stab(nbuf, ST_MAP, ST_FIND);
450738032Speter		if (s == NULL)
450838032Speter		{
450938032Speter			syserr("Switch map %s: unknown member map %s",
451038032Speter				map->map_mname, nbuf);
451138032Speter		}
451238032Speter		else
451338032Speter		{
451438032Speter			map->map_stack[mapno] = &s->s_map;
451538032Speter			if (tTd(38, 4))
451638032Speter				printf("\tmap_stack[%d] = %s:%s\n",
451738032Speter					mapno, s->s_map.map_class->map_cname,
451838032Speter					nbuf);
451938032Speter		}
452038032Speter	}
452138032Speter	return TRUE;
452238032Speter}
452338032Speter
452438032Speter
452538032Speter/*
452638032Speter**  SEQ_MAP_CLOSE -- close all underlying maps
452738032Speter*/
452838032Speter
452938032Spetervoid
453038032Speterseq_map_close(map)
453138032Speter	MAP *map;
453238032Speter{
453338032Speter	int mapno;
453438032Speter
453538032Speter	if (tTd(38, 9))
453638032Speter		printf("seq_map_close(%s)\n", map->map_mname);
453738032Speter
453838032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
453938032Speter	{
454038032Speter		MAP *mm = map->map_stack[mapno];
454138032Speter
454238032Speter		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
454338032Speter			continue;
454438032Speter		mm->map_class->map_close(mm);
454538032Speter		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
454638032Speter	}
454738032Speter}
454838032Speter
454938032Speter
455038032Speter/*
455138032Speter**  SEQ_MAP_LOOKUP -- sequenced map lookup
455238032Speter*/
455338032Speter
455438032Speterchar *
455538032Speterseq_map_lookup(map, key, args, pstat)
455638032Speter	MAP *map;
455738032Speter	char *key;
455838032Speter	char **args;
455938032Speter	int *pstat;
456038032Speter{
456138032Speter	int mapno;
456238032Speter	int mapbit = 0x01;
456338032Speter	bool tempfail = FALSE;
456438032Speter
456538032Speter	if (tTd(38, 20))
456638032Speter		printf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
456738032Speter
456838032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
456938032Speter	{
457038032Speter		MAP *mm = map->map_stack[mapno];
457138032Speter		char *rv;
457238032Speter
457338032Speter		if (mm == NULL)
457438032Speter			continue;
457538032Speter		if (!bitset(MF_OPEN, mm->map_mflags))
457638032Speter		{
457738032Speter			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
457838032Speter			{
457938032Speter				*pstat = EX_UNAVAILABLE;
458038032Speter				return NULL;
458138032Speter			}
458238032Speter			continue;
458338032Speter		}
458438032Speter		*pstat = EX_OK;
458538032Speter		rv = mm->map_class->map_lookup(mm, key, args, pstat);
458638032Speter		if (rv != NULL)
458738032Speter			return rv;
458838032Speter		if (*pstat == EX_TEMPFAIL)
458938032Speter		{
459038032Speter			if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
459138032Speter				return NULL;
459238032Speter			tempfail = TRUE;
459338032Speter		}
459438032Speter		else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
459538032Speter			break;
459638032Speter	}
459738032Speter	if (tempfail)
459838032Speter		*pstat = EX_TEMPFAIL;
459938032Speter	else if (*pstat == EX_OK)
460038032Speter		*pstat = EX_NOTFOUND;
460138032Speter	return NULL;
460238032Speter}
460338032Speter
460438032Speter
460538032Speter/*
460638032Speter**  SEQ_MAP_STORE -- sequenced map store
460738032Speter*/
460838032Speter
460938032Spetervoid
461038032Speterseq_map_store(map, key, val)
461138032Speter	MAP *map;
461238032Speter	char *key;
461338032Speter	char *val;
461438032Speter{
461538032Speter	int mapno;
461638032Speter
461738032Speter	if (tTd(38, 12))
461838032Speter		printf("seq_map_store(%s, %s, %s)\n",
461938032Speter			map->map_mname, key, val);
462038032Speter
462138032Speter	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
462238032Speter	{
462338032Speter		MAP *mm = map->map_stack[mapno];
462438032Speter
462538032Speter		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
462638032Speter			continue;
462738032Speter
462838032Speter		mm->map_class->map_store(mm, key, val);
462938032Speter		return;
463038032Speter	}
463138032Speter	syserr("seq_map_store(%s, %s, %s): no writable map",
463238032Speter		map->map_mname, key, val);
463338032Speter}
463438032Speter/*
463538032Speter**  NULL stubs
463638032Speter*/
463738032Speter
463838032Speter/* ARGSUSED */
463938032Speterbool
464038032Speternull_map_open(map, mode)
464138032Speter	MAP *map;
464238032Speter	int mode;
464338032Speter{
464438032Speter	return TRUE;
464538032Speter}
464638032Speter
464738032Speter/* ARGSUSED */
464838032Spetervoid
464938032Speternull_map_close(map)
465038032Speter	MAP *map;
465138032Speter{
465238032Speter	return;
465338032Speter}
465438032Speter
465538032Speterchar *
465638032Speternull_map_lookup(map, key, args, pstat)
465738032Speter	MAP *map;
465838032Speter	char *key;
465938032Speter	char **args;
466038032Speter	int *pstat;
466138032Speter{
466238032Speter	*pstat = EX_NOTFOUND;
466338032Speter	return NULL;
466438032Speter}
466538032Speter
466638032Speter/* ARGSUSED */
466738032Spetervoid
466838032Speternull_map_store(map, key, val)
466938032Speter	MAP *map;
467038032Speter	char *key;
467138032Speter	char *val;
467238032Speter{
467338032Speter	return;
467438032Speter}
467538032Speter
467638032Speter
467738032Speter/*
467838032Speter**  BOGUS stubs
467938032Speter*/
468038032Speter
468138032Speterchar *
468238032Speterbogus_map_lookup(map, key, args, pstat)
468338032Speter	MAP *map;
468438032Speter	char *key;
468538032Speter	char **args;
468638032Speter	int *pstat;
468738032Speter{
468838032Speter	*pstat = EX_TEMPFAIL;
468938032Speter	return NULL;
469038032Speter}
469138032Speter
469238032SpeterMAPCLASS	BogusMapClass =
469338032Speter{
469438032Speter	"bogus-map",		NULL,		0,
469538032Speter	NULL,		bogus_map_lookup,	null_map_store,
469638032Speter	null_map_open,	null_map_close,
469738032Speter};
469838032Speter/*
469938032Speter**  REGEX modules
470038032Speter*/
470138032Speter
470238032Speter#ifdef MAP_REGEX
470338032Speter
470438032Speter# include <regex.h>
470538032Speter
470638032Speter# define DEFAULT_DELIM	CONDELSE
470738032Speter
470838032Speter# define END_OF_FIELDS	-1
470938032Speter
471038032Speter# define ERRBUF_SIZE	80
471138032Speter# define MAX_MATCH	32
471238032Speter
471338032Speter# define xnalloc(s)	memset(xalloc(s), 0, s);
471438032Speter
471538032Speterstruct regex_map
471638032Speter{
471738032Speter	regex_t	pattern_buf;		/* xalloc it */
471838032Speter	int	*regex_subfields;	/* move to type MAP */
471938032Speter	char	*delim;			/* move to type MAP */
472038032Speter};
472138032Speter
472238032Speterstatic int
472338032Speterparse_fields(s, ibuf, blen, nr_substrings)
472438032Speter	char *s;
472538032Speter	int *ibuf;		/* array */
472638032Speter	int blen;		/* number of elements in ibuf */
472738032Speter	int nr_substrings;	/* number of substrings in the pattern */
472838032Speter{
472938032Speter	register char *cp;
473038032Speter	int i = 0;
473138032Speter	bool lastone = FALSE;
473238032Speter
473338032Speter	blen--;		/* for terminating END_OF_FIELDS */
473438032Speter	cp = s;
473538032Speter	do
473638032Speter	{
473738032Speter		for (;; cp++)
473838032Speter		{
473938032Speter			if (*cp == ',')
474038032Speter			{
474138032Speter				*cp = '\0';
474238032Speter				break;
474338032Speter			}
474438032Speter			if (*cp == '\0')
474538032Speter			{
474638032Speter				lastone = TRUE;
474738032Speter				break;
474838032Speter			}
474938032Speter		}
475038032Speter		if (i < blen)
475138032Speter		{
475238032Speter			int val = atoi(s);
475338032Speter
475438032Speter			if (val < 0 || val >= nr_substrings)
475538032Speter			{
475638032Speter				syserr("field (%d) out of range, only %d substrings in pattern",
475738032Speter				       val, nr_substrings);
475838032Speter				return -1;
475938032Speter			}
476038032Speter			ibuf[i++] = val;
476138032Speter		}
476238032Speter		else
476338032Speter		{
476438032Speter			syserr("too many fields, %d max\n", blen);
476538032Speter			return -1;
476638032Speter		}
476738032Speter		s = ++cp;
476838032Speter	} while (!lastone);
476938032Speter	ibuf[i] = END_OF_FIELDS;
477038032Speter	return i;
477138032Speter}
477238032Speter
477338032Speterbool
477438032Speterregex_map_init(map, ap)
477538032Speter	MAP *map;
477638032Speter	char *ap;
477738032Speter{
477838032Speter	int regerr;
477938032Speter	struct regex_map *map_p;
478038032Speter	register char *p;
478138032Speter	char *sub_param = NULL;
478238032Speter	int pflags;
478338032Speter	static char defdstr[] = { (char)DEFAULT_DELIM, '\0' };
478438032Speter
478538032Speter	if (tTd(38, 2))
478638032Speter		printf("regex_map_init: mapname '%s', args '%s'\n",
478738032Speter				map->map_mname, ap);
478838032Speter
478938032Speter	pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
479038032Speter
479138032Speter	p = ap;
479238032Speter
479338032Speter	map_p = (struct regex_map *) xnalloc(sizeof(struct regex_map));
479438032Speter
479538032Speter	for (;;)
479638032Speter        {
479738032Speter		while (isascii(*p) && isspace(*p))
479838032Speter			p++;
479938032Speter		if (*p != '-')
480038032Speter			break;
480138032Speter		switch (*++p)
480238032Speter		{
480338032Speter		  case 'n':	/* not */
480438032Speter			map->map_mflags |= MF_REGEX_NOT;
480538032Speter			break;
480638032Speter
480738032Speter		  case 'f':	/* case sensitive */
480838032Speter			map->map_mflags |= MF_NOFOLDCASE;
480938032Speter			pflags &= ~REG_ICASE;
481038032Speter			break;
481138032Speter
481238032Speter		  case 'b':	/* basic regular expressions */
481338032Speter			pflags &= ~REG_EXTENDED;
481438032Speter			break;
481538032Speter
481638032Speter		  case 's':	/* substring match () syntax */
481738032Speter			sub_param = ++p;
481838032Speter			pflags &= ~REG_NOSUB;
481938032Speter			break;
482038032Speter
482138032Speter		  case 'd':	/* delimiter */
482238032Speter			map_p->delim = ++p;
482338032Speter			break;
482438032Speter
482538032Speter		  case 'a':	/* map append */
482638032Speter			map->map_app = ++p;
482738032Speter			break;
482838032Speter
482938032Speter		  case 'm':	/* matchonly */
483038032Speter			map->map_mflags |= MF_MATCHONLY;
483138032Speter			break;
483238032Speter
483338032Speter		}
483438032Speter                while (*p != '\0' && !(isascii(*p) && isspace(*p)))
483538032Speter                        p++;
483638032Speter                if (*p != '\0')
483738032Speter                        *p++ = '\0';
483838032Speter	}
483938032Speter	if (tTd(38, 3))
484038032Speter		printf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
484138032Speter
484238032Speter	if ((regerr = regcomp(&(map_p->pattern_buf), p, pflags)) != 0)
484338032Speter	{
484438032Speter		/* Errorhandling */
484538032Speter		char errbuf[ERRBUF_SIZE];
484638032Speter
484738032Speter		regerror(regerr, &(map_p->pattern_buf), errbuf, ERRBUF_SIZE);
484838032Speter		syserr("pattern-compile-error: %s\n", errbuf);
484938032Speter		free(map_p);
485038032Speter		return FALSE;
485138032Speter	}
485238032Speter
485338032Speter	if (map->map_app != NULL)
485438032Speter		map->map_app = newstr(map->map_app);
485538032Speter	if (map_p->delim != NULL)
485638032Speter		map_p->delim = newstr(map_p->delim);
485738032Speter	else
485838032Speter		map_p->delim = defdstr;
485938032Speter
486038032Speter	if (!bitset(REG_NOSUB, pflags))
486138032Speter	{
486238032Speter		/* substring matching */
486338032Speter		int substrings;
486438032Speter		int *fields = (int *)xalloc(sizeof(int) * (MAX_MATCH + 1));
486538032Speter
486638032Speter		substrings = map_p->pattern_buf.re_nsub + 1;
486738032Speter
486838032Speter		if (tTd(38, 3))
486938032Speter			printf("regex_map_init: nr of substrings %d\n", substrings);
487038032Speter
487138032Speter		if (substrings >= MAX_MATCH)
487238032Speter		{
487338032Speter			syserr("too many substrings, %d max\n", MAX_MATCH);
487438032Speter			free(map_p);
487538032Speter			return FALSE;
487638032Speter		}
487738032Speter		if (sub_param != NULL && sub_param[0] != '\0')
487838032Speter		{
487938032Speter			/* optional parameter -sfields */
488038032Speter			if (parse_fields(sub_param, fields,
488138032Speter					 MAX_MATCH + 1, substrings) == -1)
488238032Speter				return FALSE;
488338032Speter		}
488438032Speter		else
488538032Speter		{
488638032Speter			/* set default fields  */
488738032Speter			int i;
488838032Speter
488938032Speter			for (i = 0; i < substrings; i++)
489038032Speter				fields[i] = i;
489138032Speter			fields[i] = END_OF_FIELDS;
489238032Speter		}
489338032Speter		map_p->regex_subfields = fields;
489438032Speter		if (tTd(38, 3))
489538032Speter		{
489638032Speter			int *ip;
489738032Speter
489838032Speter			printf("regex_map_init: subfields");
489938032Speter			for (ip = fields; *ip != END_OF_FIELDS; ip++)
490038032Speter				printf(" %d", *ip);
490138032Speter			printf("\n");
490238032Speter		}
490338032Speter	}
490438032Speter	map->map_db1 = (ARBPTR_T)map_p;	/* dirty hack */
490538032Speter
490638032Speter	return TRUE;
490738032Speter}
490838032Speter
490938032Speterstatic char *
491038032Speterregex_map_rewrite(map, s, slen, av)
491138032Speter	MAP *map;
491238032Speter	const char *s;
491338032Speter	size_t slen;
491438032Speter	char **av;
491538032Speter{
491638032Speter	if (bitset(MF_MATCHONLY, map->map_mflags))
491738032Speter		return map_rewrite(map, av[0], strlen(av[0]), NULL);
491838032Speter	else
491938032Speter		return map_rewrite(map, s, slen, NULL);
492038032Speter}
492138032Speter
492238032Speterchar *
492338032Speterregex_map_lookup(map, name, av, statp)
492438032Speter	MAP *map;
492538032Speter	char *name;
492638032Speter	char **av;
492738032Speter	int *statp;
492838032Speter{
492938032Speter	int reg_res;
493038032Speter	struct regex_map *map_p;
493138032Speter	regmatch_t pmatch[MAX_MATCH];
493238032Speter
493338032Speter	if (tTd(38, 20))
493438032Speter	{
493538032Speter		char **cpp;
493638032Speter
493738032Speter		printf("regex_map_lookup: key '%s'\n", name);
493838032Speter		for (cpp = av; cpp && *cpp; cpp++)
493938032Speter			printf("regex_map_lookup: arg '%s'\n", *cpp);
494038032Speter	}
494138032Speter
494238032Speter	map_p = (struct regex_map *)(map->map_db1);
494338032Speter	reg_res = regexec(&(map_p->pattern_buf), name, MAX_MATCH, pmatch, 0);
494438032Speter
494538032Speter	if (bitset(MF_REGEX_NOT, map->map_mflags))
494638032Speter	{
494738032Speter		/* option -n */
494838032Speter		if (reg_res == REG_NOMATCH)
494938032Speter			return regex_map_rewrite(map, "", (size_t)0, av);
495038032Speter		else
495138032Speter			return NULL;
495238032Speter	}
495338032Speter	if (reg_res == REG_NOMATCH)
495438032Speter		return NULL;
495538032Speter
495638032Speter	if (map_p->regex_subfields != NULL)
495738032Speter	{
495838032Speter		/* option -s */
495938032Speter		static char retbuf[MAXNAME];
496038032Speter		int fields[MAX_MATCH + 1];
496138032Speter		bool first = TRUE;
496238032Speter		int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
496338032Speter		bool quotemode = FALSE, bslashmode = FALSE;
496438032Speter		register char *dp, *sp;
496538032Speter		char *endp, *ldp;
496638032Speter		int *ip;
496738032Speter
496838032Speter		dp = retbuf;
496938032Speter		ldp = retbuf + sizeof(retbuf) - 1;
497038032Speter
497138032Speter		if (av[1] != NULL)
497238032Speter		{
497338032Speter			if (parse_fields(av[1], fields, MAX_MATCH + 1,
497438032Speter				 (int) map_p->pattern_buf.re_nsub + 1) == -1)
497538032Speter			{
497638032Speter				*statp = EX_CONFIG;
497738032Speter				return NULL;
497838032Speter			}
497938032Speter			ip = fields;
498038032Speter		}
498138032Speter		else
498238032Speter			ip = map_p->regex_subfields;
498338032Speter
498438032Speter		for ( ; *ip != END_OF_FIELDS; ip++)
498538032Speter		{
498638032Speter			if (!first)
498738032Speter			{
498838032Speter				for (sp = map_p->delim; *sp; sp++)
498938032Speter				{
499038032Speter					if (dp < ldp)
499138032Speter						*dp++ = *sp;
499238032Speter				}
499338032Speter			}
499438032Speter			else
499538032Speter				first = FALSE;
499638032Speter
499738032Speter
499838032Speter			if (pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
499938032Speter				continue;
500038032Speter
500138032Speter			sp = name + pmatch[*ip].rm_so;
500238032Speter			endp = name + pmatch[*ip].rm_eo;
500338032Speter			for (; endp > sp; sp++)
500438032Speter			{
500538032Speter				if (dp < ldp)
500638032Speter				{
500738032Speter					if(bslashmode)
500838032Speter					{
500938032Speter						*dp++ = *sp;
501038032Speter						bslashmode = FALSE;
501138032Speter					}
501238032Speter					else if(quotemode && *sp != '"' &&
501338032Speter						*sp != '\\')
501438032Speter					{
501538032Speter						*dp++ = *sp;
501638032Speter					}
501738032Speter					else switch(*dp++ = *sp)
501838032Speter					{
501938032Speter						case '\\':
502038032Speter						bslashmode = TRUE;
502138032Speter						break;
502238032Speter
502338032Speter						case '(':
502438032Speter						cmntcnt++;
502538032Speter						break;
502638032Speter
502738032Speter						case ')':
502838032Speter						cmntcnt--;
502938032Speter						break;
503038032Speter
503138032Speter						case '<':
503238032Speter						anglecnt++;
503338032Speter						break;
503438032Speter
503538032Speter						case '>':
503638032Speter						anglecnt--;
503738032Speter						break;
503838032Speter
503938032Speter						case ' ':
504038032Speter						spacecnt++;
504138032Speter						break;
504238032Speter
504338032Speter						case '"':
504438032Speter						quotemode = !quotemode;
504538032Speter						break;
504638032Speter					}
504738032Speter				}
504838032Speter			}
504938032Speter		}
505038032Speter		if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
505138032Speter		    bslashmode || spacecnt != 0)
505238032Speter		{
505338032Speter			sm_syslog(LOG_WARNING, NOQID,
505438032Speter				 "Warning: regex may cause prescan() failure map=%s lookup=%s",
505538032Speter				 map->map_mname, name);
505638032Speter			return NULL;
505738032Speter		}
505838032Speter
505938032Speter		*dp = '\0';
506038032Speter
506138032Speter		return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
506238032Speter	}
506338032Speter	return regex_map_rewrite(map, "", (size_t)0, av);
506438032Speter}
506538032Speter#endif /* MAP_REGEX */
5066