xref: /csrg-svn/usr.sbin/sendmail/src/map.c (revision 68879)
156822Seric /*
268839Seric  * Copyright (c) 1992, 1995 Eric P. Allman.
362526Sbostic  * Copyright (c) 1992, 1993
462526Sbostic  *	The Regents of the University of California.  All rights reserved.
556822Seric  *
656822Seric  * %sccs.include.redist.c%
756822Seric  */
856822Seric 
956822Seric #ifndef lint
10*68879Seric static char sccsid[] = "@(#)map.c	8.57 (Berkeley) 04/24/95";
1156822Seric #endif /* not lint */
1256822Seric 
1356822Seric #include "sendmail.h"
1456822Seric 
1560089Seric #ifdef NDBM
1668509Seric # include <ndbm.h>
1756822Seric #endif
1860089Seric #ifdef NEWDB
1968509Seric # include <db.h>
2056822Seric #endif
2160089Seric #ifdef NIS
2268524Seric   struct dom_binding { int dummy; };	/* needed on IRIX */
2368509Seric # include <rpcsvc/ypclnt.h>
2457208Seric #endif
2556822Seric 
2656822Seric /*
2760089Seric **  MAP.C -- implementations for various map classes.
2856822Seric **
2960089Seric **	Each map class implements a series of functions:
3060089Seric **
3160089Seric **	bool map_parse(MAP *map, char *args)
3260089Seric **		Parse the arguments from the config file.  Return TRUE
3360089Seric **		if they were ok, FALSE otherwise.  Fill in map with the
3460089Seric **		values.
3560089Seric **
3660222Seric **	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
3760222Seric **		Look up the key in the given map.  If found, do any
3860222Seric **		rewriting the map wants (including "args" if desired)
3960089Seric **		and return the value.  Set *pstat to the appropriate status
4060222Seric **		on error and return NULL.  Args will be NULL if called
4160222Seric **		from the alias routines, although this should probably
4260222Seric **		not be relied upon.  It is suggested you call map_rewrite
4360222Seric **		to return the results -- it takes care of null termination
4460222Seric **		and uses a dynamically expanded buffer as needed.
4560089Seric **
4660089Seric **	void map_store(MAP *map, char *key, char *value)
4760089Seric **		Store the key:value pair in the map.
4860089Seric **
4960089Seric **	bool map_open(MAP *map, int mode)
5060222Seric **		Open the map for the indicated mode.  Mode should
5160222Seric **		be either O_RDONLY or O_RDWR.  Return TRUE if it
5260222Seric **		was opened successfully, FALSE otherwise.  If the open
5360222Seric **		failed an the MF_OPTIONAL flag is not set, it should
5460222Seric **		also print an error.  If the MF_ALIAS bit is set
5560222Seric **		and this map class understands the @:@ convention, it
5660222Seric **		should call aliaswait() before returning.
5760089Seric **
5860089Seric **	void map_close(MAP *map)
5960089Seric **		Close the map.
6060089Seric */
6160089Seric 
6260089Seric #define DBMMODE		0644
6364718Seric 
6464718Seric extern bool	aliaswait __P((MAP *, char *, int));
6560089Seric /*
6660089Seric **  MAP_PARSEARGS -- parse config line arguments for database lookup
6760089Seric **
6860089Seric **	This is a generic version of the map_parse method.
6960089Seric **
7056822Seric **	Parameters:
7160089Seric **		map -- the map being initialized.
7260089Seric **		ap -- a pointer to the args on the config line.
7356822Seric **
7456822Seric **	Returns:
7560089Seric **		TRUE -- if everything parsed OK.
7656822Seric **		FALSE -- otherwise.
7756822Seric **
7856822Seric **	Side Effects:
7960089Seric **		null terminates the filename; stores it in map
8056822Seric */
8156822Seric 
8256822Seric bool
8360089Seric map_parseargs(map, ap)
8456822Seric 	MAP *map;
8560089Seric 	char *ap;
8656822Seric {
8760089Seric 	register char *p = ap;
8856822Seric 
8963753Seric 	map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
9060089Seric 	for (;;)
9160089Seric 	{
9260089Seric 		while (isascii(*p) && isspace(*p))
9360089Seric 			p++;
9460089Seric 		if (*p != '-')
9560089Seric 			break;
9660089Seric 		switch (*++p)
9760089Seric 		{
9860089Seric 		  case 'N':
9960207Seric 			map->map_mflags |= MF_INCLNULL;
10063753Seric 			map->map_mflags &= ~MF_TRY0NULL;
10160089Seric 			break;
10260089Seric 
10363753Seric 		  case 'O':
10463753Seric 			map->map_mflags &= ~MF_TRY1NULL;
10563753Seric 			break;
10663753Seric 
10760089Seric 		  case 'o':
10860207Seric 			map->map_mflags |= MF_OPTIONAL;
10960089Seric 			break;
11060089Seric 
11160089Seric 		  case 'f':
11260207Seric 			map->map_mflags |= MF_NOFOLDCASE;
11360089Seric 			break;
11460089Seric 
11560089Seric 		  case 'm':
11660207Seric 			map->map_mflags |= MF_MATCHONLY;
11760089Seric 			break;
11860089Seric 
11968497Seric 		  case 'A':
12068497Seric 			map->map_mflags |= MF_APPEND;
12168497Seric 			break;
12268497Seric 
12360089Seric 		  case 'a':
12460089Seric 			map->map_app = ++p;
12560089Seric 			break;
12668350Seric 
12768350Seric 		  case 'k':
12868350Seric 			while (isascii(*++p) && isspace(*p))
12968350Seric 				continue;
13068350Seric 			map->map_keycolnm = p;
13168350Seric 			break;
13268350Seric 
13368350Seric 		  case 'v':
13468350Seric 			while (isascii(*++p) && isspace(*p))
13568350Seric 				continue;
13668350Seric 			map->map_valcolnm = p;
13768350Seric 			break;
13868350Seric 
13968350Seric 		  case 'z':
14068350Seric 			if (*++p != '\\')
14168350Seric 				map->map_coldelim = *p;
14268350Seric 			else
14368350Seric 			{
14468350Seric 				switch (*++p)
14568350Seric 				{
14668350Seric 				  case 'n':
14768350Seric 					map->map_coldelim = '\n';
14868350Seric 					break;
14968350Seric 
15068350Seric 				  case 't':
15168350Seric 					map->map_coldelim = '\t';
15268350Seric 					break;
15368350Seric 
15468350Seric 				  default:
15568350Seric 					map->map_coldelim = '\\';
15668350Seric 				}
15768350Seric 			}
15868350Seric 			break;
15968497Seric #ifdef RESERVED_FOR_SUN
16068497Seric 		  case 'd':
16168497Seric 			map->map_mflags |= MF_DOMAIN_WIDE;
16268497Seric 			break;
16368497Seric 
16468497Seric 		  case 's':
16568497Seric 			/* info type */
16668497Seric 			break;
16768497Seric #endif
16860089Seric 		}
16960089Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
17060089Seric 			p++;
17160089Seric 		if (*p != '\0')
17260089Seric 			*p++ = '\0';
17360089Seric 	}
17460089Seric 	if (map->map_app != NULL)
17560089Seric 		map->map_app = newstr(map->map_app);
17668350Seric 	if (map->map_keycolnm != NULL)
17768350Seric 		map->map_keycolnm = newstr(map->map_keycolnm);
17868350Seric 	if (map->map_valcolnm != NULL)
17968350Seric 		map->map_valcolnm = newstr(map->map_valcolnm);
18060089Seric 
18160089Seric 	if (*p != '\0')
18260089Seric 	{
18360089Seric 		map->map_file = p;
18460089Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
18560089Seric 			p++;
18660089Seric 		if (*p != '\0')
18760089Seric 			*p++ = '\0';
18860089Seric 		map->map_file = newstr(map->map_file);
18960089Seric 	}
19060089Seric 
19160089Seric 	while (*p != '\0' && isascii(*p) && isspace(*p))
19260089Seric 		p++;
19360089Seric 	if (*p != '\0')
19460089Seric 		map->map_rebuild = newstr(p);
19560089Seric 
19668350Seric 	if (map->map_file == NULL &&
19768350Seric 	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
19857208Seric 	{
19960089Seric 		syserr("No file name for %s map %s",
20060089Seric 			map->map_class->map_cname, map->map_mname);
20156822Seric 		return FALSE;
20257208Seric 	}
20360089Seric 	return TRUE;
20460089Seric }
20560089Seric /*
20660089Seric **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
20760089Seric **
20860089Seric **	It also adds the map_app string.  It can be used as a utility
20960089Seric **	in the map_lookup method.
21060089Seric **
21160089Seric **	Parameters:
21260089Seric **		map -- the map that causes this.
21360089Seric **		s -- the string to rewrite, NOT necessarily null terminated.
21460089Seric **		slen -- the length of s.
21560089Seric **		av -- arguments to interpolate into buf.
21660089Seric **
21760089Seric **	Returns:
21867895Seric **		Pointer to rewritten result.  This is static data that
21967895Seric **		should be copied if it is to be saved!
22060089Seric **
22160089Seric **	Side Effects:
22260089Seric **		none.
22360089Seric */
22460089Seric 
22560089Seric char *
22660089Seric map_rewrite(map, s, slen, av)
22760089Seric 	register MAP *map;
22860089Seric 	register char *s;
22960089Seric 	int slen;
23060089Seric 	char **av;
23160089Seric {
23260089Seric 	register char *bp;
23360089Seric 	register char c;
23460089Seric 	char **avp;
23560089Seric 	register char *ap;
23660089Seric 	int i;
23760089Seric 	int len;
23867895Seric 	static int buflen = -1;
23967895Seric 	static char *buf = NULL;
24060089Seric 
24160537Seric 	if (tTd(39, 1))
24260089Seric 	{
24360256Seric 		printf("map_rewrite(%.*s), av =", slen, s);
24460256Seric 		if (av == NULL)
24560256Seric 			printf(" (nullv)");
24660256Seric 		else
24760256Seric 		{
24860256Seric 			for (avp = av; *avp != NULL; avp++)
24960256Seric 				printf("\n\t%s", *avp);
25060256Seric 		}
25160256Seric 		printf("\n");
25260089Seric 	}
25360089Seric 
25460089Seric 	/* count expected size of output (can safely overestimate) */
25560089Seric 	i = len = slen;
25660089Seric 	if (av != NULL)
25760089Seric 	{
25860089Seric 		bp = s;
25960089Seric 		for (i = slen; --i >= 0 && (c = *bp++) != 0; )
26060089Seric 		{
26160089Seric 			if (c != '%')
26260089Seric 				continue;
26360089Seric 			if (--i < 0)
26460089Seric 				break;
26560089Seric 			c = *bp++;
26660089Seric 			if (!(isascii(c) && isdigit(c)))
26760089Seric 				continue;
26863937Seric 			for (avp = av; --c >= '0' && *avp != NULL; avp++)
26960089Seric 				continue;
27060089Seric 			if (*avp == NULL)
27160089Seric 				continue;
27260089Seric 			len += strlen(*avp);
27360089Seric 		}
27460089Seric 	}
27560089Seric 	if (map->map_app != NULL)
27660089Seric 		len += strlen(map->map_app);
27767895Seric 	if (buflen < ++len)
27860089Seric 	{
27960089Seric 		/* need to malloc additional space */
28067895Seric 		buflen = len;
28167895Seric 		if (buf != NULL)
28267895Seric 			free(buf);
28367895Seric 		buf = xalloc(buflen);
28460089Seric 	}
28560089Seric 
28667895Seric 	bp = buf;
28760089Seric 	if (av == NULL)
28860089Seric 	{
28960089Seric 		bcopy(s, bp, slen);
29060089Seric 		bp += slen;
29160089Seric 	}
29260089Seric 	else
29360089Seric 	{
29460089Seric 		while (--slen >= 0 && (c = *s++) != '\0')
29560089Seric 		{
29660089Seric 			if (c != '%')
29760089Seric 			{
29860089Seric   pushc:
29960089Seric 				*bp++ = c;
30060089Seric 				continue;
30160089Seric 			}
30260089Seric 			if (--slen < 0 || (c = *s++) == '\0')
30360089Seric 				c = '%';
30460089Seric 			if (c == '%')
30560089Seric 				goto pushc;
30660089Seric 			if (!(isascii(c) && isdigit(c)))
30760089Seric 			{
30860089Seric 				*bp++ = '%';
30960089Seric 				goto pushc;
31060089Seric 			}
31163937Seric 			for (avp = av; --c >= '0' && *avp != NULL; avp++)
31260089Seric 				continue;
31360089Seric 			if (*avp == NULL)
31460089Seric 				continue;
31560089Seric 
31660089Seric 			/* transliterate argument into output string */
31760089Seric 			for (ap = *avp; (c = *ap++) != '\0'; )
31860089Seric 				*bp++ = c;
31960089Seric 		}
32060089Seric 	}
32160089Seric 	if (map->map_app != NULL)
32260089Seric 		strcpy(bp, map->map_app);
32360089Seric 	else
32460089Seric 		*bp = '\0';
32560537Seric 	if (tTd(39, 1))
32667895Seric 		printf("map_rewrite => %s\n", buf);
32767895Seric 	return buf;
32860089Seric }
32960089Seric /*
33060537Seric **  INITMAPS -- initialize for aliasing
33160537Seric **
33260537Seric **	Parameters:
33360537Seric **		rebuild -- if TRUE, this rebuilds the cached versions.
33460537Seric **		e -- current envelope.
33560537Seric **
33660537Seric **	Returns:
33760537Seric **		none.
33860537Seric **
33960537Seric **	Side Effects:
34060537Seric **		initializes aliases:
34160537Seric **		if NDBM:  opens the database.
34260537Seric **		if ~NDBM: reads the aliases into the symbol table.
34360537Seric */
34460537Seric 
34560537Seric initmaps(rebuild, e)
34660537Seric 	bool rebuild;
34760537Seric 	register ENVELOPE *e;
34860537Seric {
34960537Seric 	extern void map_init();
35060537Seric 
35164671Seric #ifdef XDEBUG
35264671Seric 	checkfd012("entering initmaps");
35364671Seric #endif
35460537Seric 	CurEnv = e;
35565085Seric 	if (rebuild)
35665085Seric 	{
35765085Seric 		stabapply(map_init, 1);
35865085Seric 		stabapply(map_init, 2);
35965085Seric 	}
36065085Seric 	else
36165085Seric 	{
36265085Seric 		stabapply(map_init, 0);
36365085Seric 	}
36464671Seric #ifdef XDEBUG
36564671Seric 	checkfd012("exiting initmaps");
36664671Seric #endif
36760537Seric }
36860537Seric 
36960537Seric void
37060537Seric map_init(s, rebuild)
37160537Seric 	register STAB *s;
37260537Seric 	int rebuild;
37360537Seric {
37460537Seric 	register MAP *map;
37560537Seric 
37660537Seric 	/* has to be a map */
37760537Seric 	if (s->s_type != ST_MAP)
37860537Seric 		return;
37960537Seric 
38060537Seric 	map = &s->s_map;
38160537Seric 	if (!bitset(MF_VALID, map->map_mflags))
38260537Seric 		return;
38360537Seric 
38460537Seric 	if (tTd(38, 2))
38568350Seric 		printf("map_init(%s:%s, %s, %d)\n",
38664690Seric 			map->map_class->map_cname == NULL ? "NULL" :
38764690Seric 				map->map_class->map_cname,
38868350Seric 			map->map_mname == NULL ? "NULL" : map->map_mname,
38965085Seric 			map->map_file == NULL ? "NULL" : map->map_file,
39065085Seric 			rebuild);
39160537Seric 
39265085Seric 	if (rebuild == (bitset(MF_ALIAS, map->map_mflags) &&
39365085Seric 		    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2))
39465085Seric 	{
39565085Seric 		if (tTd(38, 3))
39665085Seric 			printf("\twrong pass\n");
39765085Seric 		return;
39865085Seric 	}
39965085Seric 
40060537Seric 	/* if already open, close it (for nested open) */
40160537Seric 	if (bitset(MF_OPEN, map->map_mflags))
40260537Seric 	{
40360537Seric 		map->map_class->map_close(map);
40460537Seric 		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
40560537Seric 	}
40660537Seric 
40765085Seric 	if (rebuild == 2)
40860537Seric 	{
40965085Seric 		rebuildaliases(map, FALSE);
41060537Seric 	}
41160537Seric 	else
41260537Seric 	{
41360537Seric 		if (map->map_class->map_open(map, O_RDONLY))
41460537Seric 		{
41560537Seric 			if (tTd(38, 4))
41668350Seric 				printf("\t%s:%s %s: valid\n",
41764690Seric 					map->map_class->map_cname == NULL ? "NULL" :
41864690Seric 						map->map_class->map_cname,
41968350Seric 					map->map_mname == NULL ? "NULL" :
42068350Seric 						map->map_mname,
42164690Seric 					map->map_file == NULL ? "NULL" :
42264690Seric 						map->map_file);
42360537Seric 			map->map_mflags |= MF_OPEN;
42460537Seric 		}
42568350Seric 		else
42668350Seric 		{
42768350Seric 			if (tTd(38, 4))
42868350Seric 				printf("\t%s:%s %s: invalid: %s\n",
42968350Seric 					map->map_class->map_cname == NULL ? "NULL" :
43068350Seric 						map->map_class->map_cname,
43168350Seric 					map->map_mname == NULL ? "NULL" :
43268350Seric 						map->map_mname,
43368350Seric 					map->map_file == NULL ? "NULL" :
43468350Seric 						map->map_file,
43568350Seric 					errstring(errno));
43668350Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
43768350Seric 			{
43868350Seric 				extern MAPCLASS BogusMapClass;
43968350Seric 
44068350Seric 				map->map_class = &BogusMapClass;
44168350Seric 				map->map_mflags |= MF_OPEN;
44268350Seric 			}
44368350Seric 		}
44460537Seric 	}
44560537Seric }
44660537Seric /*
44760089Seric **  NDBM modules
44860089Seric */
44960089Seric 
45060089Seric #ifdef NDBM
45160089Seric 
45260089Seric /*
45360089Seric **  DBM_MAP_OPEN -- DBM-style map open
45460089Seric */
45560089Seric 
45660089Seric bool
45760089Seric ndbm_map_open(map, mode)
45860089Seric 	MAP *map;
45960089Seric 	int mode;
46060089Seric {
46164284Seric 	register DBM *dbm;
46264284Seric 	struct stat st;
46360089Seric 
46460537Seric 	if (tTd(38, 2))
46568350Seric 		printf("ndbm_map_open(%s, %s, %d)\n",
46668350Seric 			map->map_mname, map->map_file, mode);
46760089Seric 
46860207Seric 	if (mode == O_RDWR)
46960207Seric 		mode |= O_CREAT|O_TRUNC;
47060207Seric 
47160089Seric 	/* open the database */
47260089Seric 	dbm = dbm_open(map->map_file, mode, DBMMODE);
47356822Seric 	if (dbm == NULL)
47456822Seric 	{
47564718Seric 		if (aliaswait(map, ".pag", FALSE))
47664718Seric 			return TRUE;
47760207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
47856836Seric 			syserr("Cannot open DBM database %s", map->map_file);
47956822Seric 		return FALSE;
48056822Seric 	}
48160089Seric 	map->map_db1 = (void *) dbm;
48264964Seric 	if (mode == O_RDONLY)
48364964Seric 	{
48464964Seric 		if (bitset(MF_ALIAS, map->map_mflags) &&
48564964Seric 		    !aliaswait(map, ".pag", TRUE))
48664718Seric 			return FALSE;
48764964Seric 	}
48864964Seric 	else
48964964Seric 	{
49064964Seric 		int fd;
49164964Seric 
49264964Seric 		/* exclusive lock for duration of rebuild */
49364964Seric 		fd = dbm_dirfno((DBM *) map->map_db1);
49464964Seric 		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) &&
49564964Seric 		    lockfile(fd, map->map_file, ".dir", LOCK_EX))
49664964Seric 			map->map_mflags |= MF_LOCKED;
49764964Seric 	}
49864718Seric 	if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0)
49964284Seric 		map->map_mtime = st.st_mtime;
50056822Seric 	return TRUE;
50156822Seric }
50260089Seric 
50360089Seric 
50460089Seric /*
50556822Seric **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
50656822Seric */
50756822Seric 
50856822Seric char *
50960089Seric ndbm_map_lookup(map, name, av, statp)
51056822Seric 	MAP *map;
51160089Seric 	char *name;
51256822Seric 	char **av;
51359084Seric 	int *statp;
51456822Seric {
51556822Seric 	datum key, val;
51664373Seric 	int fd;
51760089Seric 	char keybuf[MAXNAME + 1];
51856822Seric 
51960537Seric 	if (tTd(38, 20))
52068350Seric 		printf("ndbm_map_lookup(%s, %s)\n",
52168350Seric 			map->map_mname, name);
52260089Seric 
52360089Seric 	key.dptr = name;
52460089Seric 	key.dsize = strlen(name);
52560207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
52657014Seric 	{
52760089Seric 		if (key.dsize > sizeof keybuf - 1)
52860089Seric 			key.dsize = sizeof keybuf - 1;
52960089Seric 		bcopy(key.dptr, keybuf, key.dsize + 1);
53060089Seric 		makelower(keybuf);
53160089Seric 		key.dptr = keybuf;
53257014Seric 	}
53364373Seric 	fd = dbm_dirfno((DBM *) map->map_db1);
53464388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
53564373Seric 		(void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
53663753Seric 	val.dptr = NULL;
53763753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
53863753Seric 	{
53963753Seric 		val = dbm_fetch((DBM *) map->map_db1, key);
54063753Seric 		if (val.dptr != NULL)
54163753Seric 			map->map_mflags &= ~MF_TRY1NULL;
54263753Seric 	}
54363753Seric 	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
54463753Seric 	{
54556822Seric 		key.dsize++;
54663753Seric 		val = dbm_fetch((DBM *) map->map_db1, key);
54763753Seric 		if (val.dptr != NULL)
54863753Seric 			map->map_mflags &= ~MF_TRY0NULL;
54963753Seric 	}
55064388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
55164373Seric 		(void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
55256822Seric 	if (val.dptr == NULL)
55356822Seric 		return NULL;
55460207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
55563753Seric 		return map_rewrite(map, name, strlen(name), NULL);
55663753Seric 	else
55763753Seric 		return map_rewrite(map, val.dptr, val.dsize, av);
55856822Seric }
55956822Seric 
56056822Seric 
56156822Seric /*
56260089Seric **  DBM_MAP_STORE -- store a datum in the database
56356822Seric */
56456822Seric 
56560089Seric void
56660089Seric ndbm_map_store(map, lhs, rhs)
56760089Seric 	register MAP *map;
56860089Seric 	char *lhs;
56960089Seric 	char *rhs;
57060089Seric {
57160089Seric 	datum key;
57260089Seric 	datum data;
57360089Seric 	int stat;
57460089Seric 
57560537Seric 	if (tTd(38, 12))
57668350Seric 		printf("ndbm_map_store(%s, %s, %s)\n",
57768350Seric 			map->map_mname, lhs, rhs);
57860089Seric 
57960089Seric 	key.dsize = strlen(lhs);
58060089Seric 	key.dptr = lhs;
58160089Seric 
58260089Seric 	data.dsize = strlen(rhs);
58360089Seric 	data.dptr = rhs;
58460089Seric 
58560207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
58660089Seric 	{
58760089Seric 		key.dsize++;
58860089Seric 		data.dsize++;
58960089Seric 	}
59060089Seric 
59160089Seric 	stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
59260089Seric 	if (stat > 0)
59360089Seric 	{
59468497Seric 		if (!bitset(MF_APPEND, map->map_mflags))
59568497Seric 			usrerr("050 Warning: duplicate alias name %s", lhs);
59668497Seric 		else
59768497Seric 		{
59868497Seric 			static char *buf = NULL;
59968497Seric 			static int bufsiz = 0;
600*68879Seric 			auto int xstat;
60168497Seric 			datum old;
60268497Seric 
603*68879Seric 			old.dptr = ndbm_map_lookup(map, key.dptr, NULL, &xstat);
60468497Seric 			if (old.dptr != NULL && *old.dptr != '\0')
60568497Seric 			{
60668497Seric 				old.dsize = strlen(old.dptr);
60768497Seric 				if (data.dsize + old.dsize + 2 > bufsiz)
60868497Seric 				{
60968497Seric 					if (buf != NULL)
61068497Seric 						(void) free(buf);
61168497Seric 					bufsiz = data.dsize + old.dsize + 2;
61268497Seric 					buf = xalloc(bufsiz);
61368497Seric 				}
61468497Seric 				sprintf(buf, "%s,%s", data.dptr, old.dptr);
61568497Seric 				data.dsize = data.dsize + old.dsize + 1;
61668497Seric 				data.dptr = buf;
61768497Seric 				if (tTd(38, 9))
61868497Seric 					printf("ndbm_map_store append=%s\n", data.dptr);
61968497Seric 			}
62068497Seric 		}
62160089Seric 		stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
62260089Seric 	}
62360089Seric 	if (stat != 0)
62460089Seric 		syserr("readaliases: dbm put (%s)", lhs);
62560089Seric }
62660089Seric 
62760089Seric 
62860089Seric /*
62960207Seric **  NDBM_MAP_CLOSE -- close the database
63060089Seric */
63160089Seric 
63260089Seric void
63360089Seric ndbm_map_close(map)
63460089Seric 	register MAP  *map;
63560089Seric {
63666773Seric 	if (tTd(38, 9))
63768350Seric 		printf("ndbm_map_close(%s, %s, %x)\n",
63868350Seric 			map->map_mname, map->map_file, map->map_mflags);
63966773Seric 
64060207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
64160089Seric 	{
64264250Seric #ifdef NIS
64364075Seric 		bool inclnull;
64460089Seric 		char buf[200];
64560089Seric 
64664075Seric 		inclnull = bitset(MF_INCLNULL, map->map_mflags);
64764075Seric 		map->map_mflags &= ~MF_INCLNULL;
64864075Seric 
64960089Seric 		(void) sprintf(buf, "%010ld", curtime());
65060089Seric 		ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
65160089Seric 
65264941Seric 		(void) gethostname(buf, sizeof buf);
65360089Seric 		ndbm_map_store(map, "YP_MASTER_NAME", buf);
65464075Seric 
65564075Seric 		if (inclnull)
65664075Seric 			map->map_mflags |= MF_INCLNULL;
65760089Seric #endif
65860089Seric 
65960089Seric 		/* write out the distinguished alias */
66060089Seric 		ndbm_map_store(map, "@", "@");
66160089Seric 	}
66260089Seric 	dbm_close((DBM *) map->map_db1);
66360089Seric }
66460089Seric 
66560089Seric #endif
66660089Seric /*
66760582Seric **  NEWDB (Hash and BTree) Modules
66860089Seric */
66960089Seric 
67060089Seric #ifdef NEWDB
67160089Seric 
67260089Seric /*
67360582Seric **  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
67460582Seric **
67560582Seric **	These do rather bizarre locking.  If you can lock on open,
67660582Seric **	do that to avoid the condition of opening a database that
67760582Seric **	is being rebuilt.  If you don't, we'll try to fake it, but
67860582Seric **	there will be a race condition.  If opening for read-only,
67960582Seric **	we immediately release the lock to avoid freezing things up.
68060582Seric **	We really ought to hold the lock, but guarantee that we won't
68160582Seric **	be pokey about it.  That's hard to do.
68260089Seric */
68360089Seric 
68456822Seric bool
68560089Seric bt_map_open(map, mode)
68656822Seric 	MAP *map;
68760089Seric 	int mode;
68856822Seric {
68956822Seric 	DB *db;
69060228Seric 	int i;
69160582Seric 	int omode;
69264373Seric 	int fd;
69364284Seric 	struct stat st;
69468528Seric 	char buf[MAXNAME + 1];
69556822Seric 
69660537Seric 	if (tTd(38, 2))
69768350Seric 		printf("bt_map_open(%s, %s, %d)\n",
69868350Seric 			map->map_mname, map->map_file, mode);
69960089Seric 
70060582Seric 	omode = mode;
70160582Seric 	if (omode == O_RDWR)
70260582Seric 	{
70360582Seric 		omode |= O_CREAT|O_TRUNC;
70465830Seric #if defined(O_EXLOCK) && HASFLOCK
70560582Seric 		omode |= O_EXLOCK;
70666843Seric # if !OLD_NEWDB
70760582Seric 	}
70860582Seric 	else
70960582Seric 	{
71060582Seric 		omode |= O_SHLOCK;
71160582Seric # endif
71260582Seric #endif
71360582Seric 	}
71460207Seric 
71560228Seric 	(void) strcpy(buf, map->map_file);
71660228Seric 	i = strlen(buf);
71760228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
71860228Seric 		(void) strcat(buf, ".db");
71960582Seric 	db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
72056822Seric 	if (db == NULL)
72156822Seric 	{
72264718Seric #ifdef MAYBENEXTRELEASE
72364718Seric 		if (aliaswait(map, ".db", FALSE))
72464718Seric 			return TRUE;
72564718Seric #endif
72660207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
72756836Seric 			syserr("Cannot open BTREE database %s", map->map_file);
72856822Seric 		return FALSE;
72956822Seric 	}
73068350Seric #if !OLD_NEWDB
73164373Seric 	fd = db->fd(db);
73268778Seric # if defined(O_EXLOCK) && HASFLOCK
73368778Seric 	if (fd >= 0)
73468778Seric 	{
73568778Seric 		if (mode == O_RDONLY)
73668778Seric 			(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
73768778Seric 		else
73868778Seric 			map->map_mflags |= MF_LOCKED;
73968778Seric 	}
74068778Seric # else
74164373Seric 	if (mode == O_RDWR && fd >= 0)
74264388Seric 	{
74364388Seric 		if (lockfile(fd, map->map_file, ".db", LOCK_EX))
74464388Seric 			map->map_mflags |= MF_LOCKED;
74564388Seric 	}
74660582Seric # endif
74760582Seric #endif
74860585Seric 
74960585Seric 	/* try to make sure that at least the database header is on disk */
75060585Seric 	if (mode == O_RDWR)
75166843Seric #if OLD_NEWDB
75264373Seric 		(void) db->sync(db);
75364373Seric #else
75460585Seric 		(void) db->sync(db, 0);
75560585Seric 
75664373Seric 	if (fd >= 0 && fstat(fd, &st) >= 0)
75764284Seric 		map->map_mtime = st.st_mtime;
75864284Seric #endif
75964284Seric 
76060089Seric 	map->map_db2 = (void *) db;
76160207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
76264718Seric 		if (!aliaswait(map, ".db", TRUE))
76364718Seric 			return FALSE;
76456822Seric 	return TRUE;
76556822Seric }
76656822Seric 
76756822Seric 
76856822Seric /*
76956822Seric **  HASH_MAP_INIT -- HASH-style map initialization
77056822Seric */
77156822Seric 
77256822Seric bool
77360089Seric hash_map_open(map, mode)
77456822Seric 	MAP *map;
77560089Seric 	int mode;
77656822Seric {
77756822Seric 	DB *db;
77860228Seric 	int i;
77960582Seric 	int omode;
78064373Seric 	int fd;
78164284Seric 	struct stat st;
78268528Seric 	char buf[MAXNAME + 1];
78356822Seric 
78460537Seric 	if (tTd(38, 2))
78568350Seric 		printf("hash_map_open(%s, %s, %d)\n",
78668350Seric 			map->map_mname, map->map_file, mode);
78760089Seric 
78860582Seric 	omode = mode;
78960582Seric 	if (omode == O_RDWR)
79060582Seric 	{
79160582Seric 		omode |= O_CREAT|O_TRUNC;
79265830Seric #if defined(O_EXLOCK) && HASFLOCK
79360582Seric 		omode |= O_EXLOCK;
79466843Seric # if !OLD_NEWDB
79560582Seric 	}
79660582Seric 	else
79760582Seric 	{
79860582Seric 		omode |= O_SHLOCK;
79960582Seric # endif
80060582Seric #endif
80160582Seric 	}
80260207Seric 
80360228Seric 	(void) strcpy(buf, map->map_file);
80460228Seric 	i = strlen(buf);
80560228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
80660228Seric 		(void) strcat(buf, ".db");
80760582Seric 	db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
80856822Seric 	if (db == NULL)
80956822Seric 	{
81064718Seric #ifdef MAYBENEXTRELEASE
81164718Seric 		if (aliaswait(map, ".db", FALSE))
81264718Seric 			return TRUE;
81364718Seric #endif
81460207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
81556836Seric 			syserr("Cannot open HASH database %s", map->map_file);
81656822Seric 		return FALSE;
81756822Seric 	}
81868350Seric #if !OLD_NEWDB
81964373Seric 	fd = db->fd(db);
82068778Seric # if defined(O_EXLOCK) && HASFLOCK
82168778Seric 	if (fd >= 0)
82268778Seric 	{
82368778Seric 		if (mode == O_RDONLY)
82468778Seric 			(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
82568778Seric 		else
82668778Seric 			map->map_mflags |= MF_LOCKED;
82768778Seric 	}
82868778Seric # else
82964373Seric 	if (mode == O_RDWR && fd >= 0)
83064388Seric 	{
83164388Seric 		if (lockfile(fd, map->map_file, ".db", LOCK_EX))
83264388Seric 			map->map_mflags |= MF_LOCKED;
83364388Seric 	}
83460582Seric # endif
83560582Seric #endif
83660585Seric 
83760585Seric 	/* try to make sure that at least the database header is on disk */
83860585Seric 	if (mode == O_RDWR)
83966843Seric #if OLD_NEWDB
84064373Seric 		(void) db->sync(db);
84164373Seric #else
84260585Seric 		(void) db->sync(db, 0);
84360585Seric 
84464373Seric 	if (fd >= 0 && fstat(fd, &st) >= 0)
84564284Seric 		map->map_mtime = st.st_mtime;
84664284Seric #endif
84764284Seric 
84860089Seric 	map->map_db2 = (void *) db;
84960207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
85064718Seric 		if (!aliaswait(map, ".db", TRUE))
85164718Seric 			return FALSE;
85256822Seric 	return TRUE;
85356822Seric }
85456822Seric 
85556822Seric 
85656822Seric /*
85756822Seric **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
85856822Seric */
85956822Seric 
86056822Seric char *
86160089Seric db_map_lookup(map, name, av, statp)
86256822Seric 	MAP *map;
86360089Seric 	char *name;
86456822Seric 	char **av;
86559084Seric 	int *statp;
86656822Seric {
86756822Seric 	DBT key, val;
86860422Seric 	register DB *db = (DB *) map->map_db2;
86960422Seric 	int st;
87060422Seric 	int saveerrno;
87164373Seric 	int fd;
87260089Seric 	char keybuf[MAXNAME + 1];
87356822Seric 
87460537Seric 	if (tTd(38, 20))
87568350Seric 		printf("db_map_lookup(%s, %s)\n",
87668350Seric 			map->map_mname, name);
87760089Seric 
87860089Seric 	key.size = strlen(name);
87960089Seric 	if (key.size > sizeof keybuf - 1)
88060089Seric 		key.size = sizeof keybuf - 1;
88160089Seric 	key.data = keybuf;
88260089Seric 	bcopy(name, keybuf, key.size + 1);
88360207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
88460089Seric 		makelower(keybuf);
88566843Seric #if !OLD_NEWDB
88664388Seric 	fd = db->fd(db);
88764388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
88864388Seric 		(void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH);
88960422Seric #endif
89063753Seric 	st = 1;
89163753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
89263753Seric 	{
89363753Seric 		st = db->get(db, &key, &val, 0);
89463753Seric 		if (st == 0)
89563753Seric 			map->map_mflags &= ~MF_TRY1NULL;
89663753Seric 	}
89763753Seric 	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
89863753Seric 	{
89963753Seric 		key.size++;
90063753Seric 		st = db->get(db, &key, &val, 0);
90163753Seric 		if (st == 0)
90263753Seric 			map->map_mflags &= ~MF_TRY0NULL;
90363753Seric 	}
90460422Seric 	saveerrno = errno;
90566843Seric #if !OLD_NEWDB
90664388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
90764373Seric 		(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
90860422Seric #endif
90960422Seric 	if (st != 0)
91060422Seric 	{
91160422Seric 		errno = saveerrno;
91260422Seric 		if (st < 0)
91360422Seric 			syserr("db_map_lookup: get (%s)", name);
91456822Seric 		return NULL;
91560422Seric 	}
91660207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
91763753Seric 		return map_rewrite(map, name, strlen(name), NULL);
91863753Seric 	else
91963753Seric 		return map_rewrite(map, val.data, val.size, av);
92056822Seric }
92156822Seric 
92260089Seric 
92360089Seric /*
92460089Seric **  DB_MAP_STORE -- store a datum in the NEWDB database
92556822Seric */
92656822Seric 
92760089Seric void
92860089Seric db_map_store(map, lhs, rhs)
92960089Seric 	register MAP *map;
93060089Seric 	char *lhs;
93160089Seric 	char *rhs;
93256822Seric {
93360089Seric 	int stat;
93460089Seric 	DBT key;
93560089Seric 	DBT data;
93660089Seric 	register DB *db = map->map_db2;
93756822Seric 
93860537Seric 	if (tTd(38, 20))
93968350Seric 		printf("db_map_store(%s, %s, %s)\n",
94068350Seric 			map->map_mname, lhs, rhs);
94160089Seric 
94260089Seric 	key.size = strlen(lhs);
94360089Seric 	key.data = lhs;
94460089Seric 
94560089Seric 	data.size = strlen(rhs);
94660089Seric 	data.data = rhs;
94760089Seric 
94860207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
94956822Seric 	{
95060089Seric 		key.size++;
95160089Seric 		data.size++;
95260089Seric 	}
95356836Seric 
95460089Seric 	stat = db->put(db, &key, &data, R_NOOVERWRITE);
95560089Seric 	if (stat > 0)
95660089Seric 	{
95768497Seric 		if (!bitset(MF_APPEND, map->map_mflags))
95868497Seric 			usrerr("050 Warning: duplicate alias name %s", lhs);
95968497Seric 		else
96068497Seric 		{
96168497Seric 			static char *buf = NULL;
96268497Seric 			static int bufsiz = 0;
96368497Seric 			DBT old;
96468497Seric 
96568497Seric 			old.data = db_map_lookup(map, key.data, NULL, &stat);
96668497Seric 			if (old.data != NULL)
96768497Seric 			{
96868497Seric 				old.size = strlen(old.data);
96968497Seric 				if (data.size + old.size + 2 > bufsiz)
97068497Seric 				{
97168497Seric 					if (buf != NULL)
97268497Seric 						(void) free(buf);
97368497Seric 					bufsiz = data.size + old.size + 2;
97468497Seric 					buf = xalloc(bufsiz);
97568497Seric 				}
97668497Seric 				sprintf(buf, "%s,%s", data.data, old.data);
97768497Seric 				data.size = data.size + old.size + 1;
97868497Seric 				data.data = buf;
97968497Seric 				if (tTd(38, 9))
98068497Seric 					printf("db_map_store append=%s\n", data.data);
98168497Seric 			}
98268497Seric 		}
98360089Seric 		stat = db->put(db, &key, &data, 0);
98460089Seric 	}
98560089Seric 	if (stat != 0)
98660089Seric 		syserr("readaliases: db put (%s)", lhs);
98760089Seric }
98856836Seric 
98956847Seric 
99060089Seric /*
99160089Seric **  DB_MAP_CLOSE -- add distinguished entries and close the database
99260089Seric */
99360089Seric 
99460089Seric void
99560089Seric db_map_close(map)
99660089Seric 	MAP *map;
99760089Seric {
99860089Seric 	register DB *db = map->map_db2;
99960089Seric 
100060537Seric 	if (tTd(38, 9))
100168350Seric 		printf("db_map_close(%s, %s, %x)\n",
100268350Seric 			map->map_mname, map->map_file, map->map_mflags);
100360089Seric 
100460207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
100558804Seric 	{
100660089Seric 		/* write out the distinguished alias */
100760089Seric 		db_map_store(map, "@", "@");
100858804Seric 	}
100958963Seric 
101060089Seric 	if (db->close(db) != 0)
101160089Seric 		syserr("readaliases: db close failure");
101256822Seric }
101357208Seric 
101460089Seric #endif
101560089Seric /*
101660089Seric **  NIS Modules
101760089Seric */
101860089Seric 
101960089Seric # ifdef NIS
102060089Seric 
102164369Seric # ifndef YPERR_BUSY
102264369Seric #  define YPERR_BUSY	16
102364369Seric # endif
102464369Seric 
102557208Seric /*
102660089Seric **  NIS_MAP_OPEN -- open DBM map
102757208Seric */
102857208Seric 
102957208Seric bool
103060089Seric nis_map_open(map, mode)
103157208Seric 	MAP *map;
103260089Seric 	int mode;
103357208Seric {
103457216Seric 	int yperr;
103560215Seric 	register char *p;
103660215Seric 	auto char *vp;
103760215Seric 	auto int vsize;
103857216Seric 	char *master;
103957216Seric 
104060537Seric 	if (tTd(38, 2))
104168350Seric 		printf("nis_map_open(%s, %s)\n",
104268350Seric 			map->map_mname, map->map_file);
104360089Seric 
104460207Seric 	if (mode != O_RDONLY)
104560207Seric 	{
104664650Seric 		/* issue a pseudo-error message */
104764650Seric #ifdef ENOSYS
104864650Seric 		errno = ENOSYS;
104964650Seric #else
105064650Seric # ifdef EFTYPE
105164650Seric 		errno = EFTYPE;
105264650Seric # else
105364650Seric 		errno = ENXIO;
105464650Seric # endif
105564650Seric #endif
105660207Seric 		return FALSE;
105760207Seric 	}
105860207Seric 
105960089Seric 	p = strchr(map->map_file, '@');
106060089Seric 	if (p != NULL)
106160089Seric 	{
106260089Seric 		*p++ = '\0';
106360089Seric 		if (*p != '\0')
106460089Seric 			map->map_domain = p;
106560089Seric 	}
106660215Seric 
106760089Seric 	if (*map->map_file == '\0')
106860089Seric 		map->map_file = "mail.aliases";
106960089Seric 
107066157Seric 	if (map->map_domain == NULL)
107166157Seric 	{
107266157Seric 		yperr = yp_get_default_domain(&map->map_domain);
107366157Seric 		if (yperr != 0)
107466157Seric 		{
107566744Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
107668350Seric 				syserr("421 NIS map %s specified, but NIS not running\n",
107766744Seric 					map->map_file);
107866157Seric 			return FALSE;
107966157Seric 		}
108066157Seric 	}
108166157Seric 
108260215Seric 	/* check to see if this map actually exists */
108360089Seric 	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
108460089Seric 			&vp, &vsize);
108560537Seric 	if (tTd(38, 10))
108660089Seric 		printf("nis_map_open: yp_match(%s, %s) => %s\n",
108760089Seric 			map->map_domain, map->map_file, yperr_string(yperr));
108860089Seric 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
108968350Seric 	{
109068350Seric 		if (!bitset(MF_ALIAS, map->map_mflags) ||
109168350Seric 		    aliaswait(map, NULL, TRUE))
109268350Seric 			return TRUE;
109368350Seric 	}
109460215Seric 
109560215Seric 	if (!bitset(MF_OPTIONAL, map->map_mflags))
109668735Seric 	{
109768735Seric 		syserr("421 Cannot bind to map %s in domain %s: %s",
109868735Seric 			map->map_file, map->map_domain, yperr_string(yperr));
109968735Seric 	}
110060215Seric 
110160089Seric 	return FALSE;
110260089Seric }
110360089Seric 
110460089Seric 
110560089Seric /*
110657208Seric **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
110757208Seric */
110857208Seric 
110957208Seric char *
111060089Seric nis_map_lookup(map, name, av, statp)
111157208Seric 	MAP *map;
111260089Seric 	char *name;
111357208Seric 	char **av;
111459084Seric 	int *statp;
111557208Seric {
111657208Seric 	char *vp;
111757642Seric 	auto int vsize;
111859274Seric 	int buflen;
111960215Seric 	int yperr;
112060089Seric 	char keybuf[MAXNAME + 1];
112157208Seric 
112260537Seric 	if (tTd(38, 20))
112368350Seric 		printf("nis_map_lookup(%s, %s)\n",
112468350Seric 			map->map_mname, name);
112560089Seric 
112660089Seric 	buflen = strlen(name);
112760089Seric 	if (buflen > sizeof keybuf - 1)
112860089Seric 		buflen = sizeof keybuf - 1;
112960089Seric 	bcopy(name, keybuf, buflen + 1);
113060207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
113160089Seric 		makelower(keybuf);
113263753Seric 	yperr = YPERR_KEY;
113363753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
113463753Seric 	{
113563753Seric 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
113663753Seric 			     &vp, &vsize);
113763753Seric 		if (yperr == 0)
113863753Seric 			map->map_mflags &= ~MF_TRY1NULL;
113963753Seric 	}
114063753Seric 	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
114163753Seric 	{
114259274Seric 		buflen++;
114363753Seric 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
114463753Seric 			     &vp, &vsize);
114563753Seric 		if (yperr == 0)
114663753Seric 			map->map_mflags &= ~MF_TRY0NULL;
114763753Seric 	}
114860089Seric 	if (yperr != 0)
114960089Seric 	{
115060089Seric 		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
115160215Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
115257208Seric 		return NULL;
115360089Seric 	}
115460207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
115563753Seric 		return map_rewrite(map, name, strlen(name), NULL);
115663753Seric 	else
115763753Seric 		return map_rewrite(map, vp, vsize, av);
115857208Seric }
115957208Seric 
116068350Seric #endif
116168350Seric /*
116268350Seric **  NISPLUS Modules
116368350Seric **
116468350Seric **	This code donated by Sun Microsystems.
116568350Seric */
116667848Seric 
116768350Seric #ifdef NISPLUS
116868350Seric 
116968350Seric #undef NIS /* symbol conflict in nis.h */
117068350Seric #include <rpcsvc/nis.h>
117168350Seric #include <rpcsvc/nislib.h>
117268350Seric 
117368350Seric #define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
117468350Seric #define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
117568350Seric #define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
117668350Seric #define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
117768350Seric 
117867848Seric /*
117968350Seric **  NISPLUS_MAP_OPEN -- open nisplus table
118067848Seric */
118167848Seric 
118268350Seric bool
118368350Seric nisplus_map_open(map, mode)
118467848Seric 	MAP *map;
118568350Seric 	int mode;
118667848Seric {
118768350Seric 	register char *p;
118868350Seric 	char qbuf[MAXLINE + NIS_MAXNAMELEN];
118968350Seric 	nis_result *res = NULL;
119068350Seric 	u_int objs_len;
119168350Seric 	nis_object *obj_ptr;
119268350Seric 	int retry_cnt, max_col, i;
119368350Seric 
119468350Seric 	if (tTd(38, 2))
119568350Seric 		printf("nisplus_map_open(%s, %s, %d)\n",
119668350Seric 			map->map_mname, map->map_file, mode);
119768350Seric 
119868350Seric 	if (mode != O_RDONLY)
119968350Seric 	{
120068350Seric 		errno = ENODEV;
120168350Seric 		return FALSE;
120268350Seric 	}
120368350Seric 
120468350Seric 	if (*map->map_file == '\0')
120568350Seric 		map->map_file = "mail_aliases.org_dir";
120668350Seric 
120768350Seric 	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
120868350Seric 	{
120968350Seric 		/* set default NISPLUS Domain to $m */
121068350Seric 		extern char *nisplus_default_domain();
121168350Seric 
121268350Seric 		map->map_domain = newstr(nisplus_default_domain());
121368350Seric 		if (tTd(38, 2))
121468350Seric 			printf("nisplus_map_open(%s): using domain %s\n",
121568350Seric 				 map->map_file, map->map_domain);
121668350Seric 	}
121768350Seric 	if (!PARTIAL_NAME(map->map_file))
121868350Seric 		map->map_domain = newstr("");
121968350Seric 
122068350Seric 	/* check to see if this map actually exists */
122168350Seric 	if (PARTIAL_NAME(map->map_file))
122268350Seric 		sprintf(qbuf, "%s.%s", map->map_file, map->map_domain);
122368350Seric 	else
122468350Seric 		strcpy(qbuf, map->map_file);
122568350Seric 
122668350Seric 	retry_cnt = 0;
122768350Seric 	while (res == NULL || res->status != NIS_SUCCESS)
122868350Seric 	{
122968350Seric 		res = nis_lookup(qbuf, FOLLOW_LINKS);
123068350Seric 		switch (res->status)
123168350Seric 		{
123268350Seric 		  case NIS_SUCCESS:
123368350Seric 		  case NIS_TRYAGAIN:
123468350Seric 		  case NIS_RPCERROR:
123568350Seric 		  case NIS_NAMEUNREACHABLE:
123668350Seric 			break;
123768350Seric 
123868350Seric 		  default:		/* all other nisplus errors */
123968350Seric #if 0
124068350Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
124168350Seric 				syserr("421 Cannot find table %s.%s: %s",
124268350Seric 					map->map_file, map->map_domain,
124368350Seric 					nis_sperrno(res->status));
124468350Seric #endif
124568350Seric 			errno = EBADR;
124668350Seric 			return FALSE;
124768350Seric 		}
124868350Seric 		sleep(2);		/* try not to overwhelm hosed server */
124968350Seric 		if (retry_cnt++ > 4)
125068350Seric 		{
125168350Seric 			errno = EBADR;
125268350Seric 			return FALSE;
125368350Seric 		}
125468350Seric 	}
125568350Seric 
125668350Seric 	if (NIS_RES_NUMOBJ(res) != 1 ||
125768350Seric 	    (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
125868350Seric 	{
125968350Seric 		if (tTd(38, 10))
126068350Seric 			printf("nisplus_map_open: %s is not a table\n", qbuf);
126168350Seric #if 0
126268350Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
126368350Seric 			syserr("421 %s.%s: %s is not a table",
126468350Seric 				map->map_file, map->map_domain,
126568350Seric 				nis_sperrno(res->status));
126668350Seric #endif
126768350Seric 		errno = EBADR;
126868350Seric 		return FALSE;
126968350Seric 	}
127068350Seric 	/* default key column is column 0 */
127168350Seric 	if (map->map_keycolnm == NULL)
127268350Seric 		map->map_keycolnm = newstr(COL_NAME(res,0));
127368350Seric 
127468350Seric 	max_col = COL_MAX(res);
127568350Seric 
127668350Seric 	/* verify the key column exist */
127768350Seric 	for (i=0; i< max_col; i++)
127868350Seric 	{
127968350Seric 		if (!strcmp(map->map_keycolnm, COL_NAME(res,i)))
128068350Seric 			break;
128168350Seric 	}
128268350Seric 	if (i == max_col)
128368350Seric 	{
128468350Seric 		if (tTd(38, 2))
128568350Seric 			printf("nisplus_map_open(%s): can not find key column %s\n",
128668350Seric 				map->map_file, map->map_keycolnm);
128768350Seric 		errno = EBADR;
128868350Seric 		return FALSE;
128968350Seric 	}
129068350Seric 
129168350Seric 	/* default value column is the last column */
129268350Seric 	if (map->map_valcolnm == NULL)
129368350Seric 	{
129468350Seric 		map->map_valcolno = max_col - 1;
129568350Seric 		return TRUE;
129668350Seric 	}
129768350Seric 
129868350Seric 	for (i=0; i< max_col; i++)
129968350Seric 	{
130068350Seric 		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
130168350Seric 		{
130268350Seric 			map->map_valcolno = i;
130368350Seric 			return TRUE;
130468350Seric 		}
130568350Seric 	}
130668350Seric 
130768350Seric 	if (tTd(38, 2))
130868350Seric 		printf("nisplus_map_open(%s): can not find column %s\n",
130968350Seric 			 map->map_file, map->map_keycolnm);
131068350Seric 	errno = EBADR;
131168350Seric 	return FALSE;
131267848Seric }
131367848Seric 
131467848Seric 
131567848Seric /*
131668350Seric **  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
131767848Seric */
131867848Seric 
131968350Seric char *
132068350Seric nisplus_map_lookup(map, name, av, statp)
132167848Seric 	MAP *map;
132268350Seric 	char *name;
132368350Seric 	char **av;
132468350Seric 	int *statp;
132567848Seric {
132668350Seric 	char *vp;
132768350Seric 	auto int vsize;
132868350Seric 	int buflen;
132968350Seric 	char search_key[MAXNAME + 1];
133068350Seric 	char qbuf[MAXLINE + NIS_MAXNAMELEN];
133168350Seric 	nis_result *result;
133268350Seric 
133368350Seric 	if (tTd(38, 20))
133468350Seric 		printf("nisplus_map_lookup(%s, %s)\n",
133568350Seric 			map->map_mname, name);
133668350Seric 
133768350Seric 	if (!bitset(MF_OPEN, map->map_mflags))
133868350Seric 	{
133968350Seric 		if (nisplus_map_open(map, O_RDONLY))
134068350Seric 			map->map_mflags |= MF_OPEN;
134168350Seric 		else
134268350Seric 		{
134368350Seric 			*statp = EX_UNAVAILABLE;
134468350Seric 			return NULL;
134568350Seric 		}
134668350Seric 	}
134768350Seric 
134868350Seric 	buflen = strlen(name);
134968350Seric 	if (buflen > sizeof search_key - 1)
135068350Seric 		buflen = sizeof search_key - 1;
135168350Seric 	bcopy(name, search_key, buflen + 1);
135268350Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
135368350Seric 		makelower(search_key);
135468350Seric 
135568350Seric 	/* construct the query */
135668350Seric 	if (PARTIAL_NAME(map->map_file))
135768350Seric 		sprintf(qbuf, "[%s=%s],%s.%s", map->map_keycolnm,
135868350Seric 			search_key, map->map_file, map->map_domain);
135968350Seric 	else
136068350Seric 		sprintf(qbuf, "[%s=%s],%s", map->map_keycolnm,
136168350Seric 			search_key, map->map_file);
136268350Seric 
136368350Seric 	if (tTd(38, 20))
136468350Seric 		printf("qbuf=%s\n", qbuf);
136568350Seric 	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
136668350Seric 	if (result->status == NIS_SUCCESS)
136768350Seric 	{
136868350Seric 		int count;
136968350Seric 		char *str;
137068350Seric 
137168350Seric 		if ((count = NIS_RES_NUMOBJ(result)) != 1)
137268350Seric 		{
137368350Seric 			if (LogLevel > 10)
137468350Seric 				syslog(LOG_WARNING,
137568350Seric 				  "%s:Lookup error, expected 1 entry, got (%d)",
137668350Seric 				    map->map_file, count);
137768350Seric 
137868350Seric 			/* ignore second entry */
137968350Seric 			if (tTd(38, 20))
138068350Seric 				printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
138168350Seric 					name, count);
138268350Seric 		}
138368350Seric 
138468350Seric 		vp = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
138568350Seric 		/* set the length of the result */
138668350Seric 		if (vp == NULL)
138768350Seric 			vp = "";
138868350Seric 		vsize = strlen(vp);
138968350Seric 		if (tTd(38, 20))
139068350Seric 			printf("nisplus_map_lookup(%s), found %s\n",
139168350Seric 				name, vp);
139268350Seric 		if (bitset(MF_MATCHONLY, map->map_mflags))
139368350Seric 			str = map_rewrite(map, name, strlen(name), NULL);
139468350Seric 		else
139568350Seric 			str = map_rewrite(map, vp, vsize, av);
139668350Seric 		nis_freeresult(result);
139768350Seric #ifdef MAP_EXIT_STAT
139868350Seric 		*statp = EX_OK;
139968350Seric #endif
140068350Seric 		return str;
140168350Seric 	}
140268350Seric 	else
140368350Seric 	{
140468350Seric #ifdef MAP_EXIT_STAT
140568350Seric 		if (result->status == NIS_NOTFOUND)
140668350Seric 			*statp = EX_NOTFOUND;
140768350Seric 		else if (result->status == NIS_TRYAGAIN)
140868350Seric 			*statp = EX_TEMPFAIL;
140968350Seric 		else
141068350Seric 		{
141168350Seric 			*statp = EX_UNAVAILABLE;
141268350Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
141368350Seric 		}
141468350Seric #else
141568350Seric 		if ((result->status != NIS_NOTFOUND) &&
141668350Seric 		    (result->status != NIS_TRYAGAIN))
141768350Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
141868350Seric #endif
141968350Seric 	}
142068350Seric 	if (tTd(38, 20))
142168350Seric 		printf("nisplus_map_lookup(%s), failed\n", name);
142268350Seric 	nis_freeresult(result);
142368350Seric 	return NULL;
142467848Seric }
142567848Seric 
142668350Seric 
142768350Seric char *
142868350Seric nisplus_default_domain()
142968350Seric {
143068528Seric 	static char default_domain[MAXNAME + 1] = "";
143168350Seric 	char *p;
143268350Seric 
143368350Seric 	if (default_domain[0] != '\0')
143468350Seric 		return(default_domain);
143568350Seric 
143668458Seric 	p = nis_local_directory();
143768350Seric 	strcpy(default_domain, p);
143868458Seric 	return default_domain;
143968350Seric }
144068350Seric 
144168350Seric #endif /* NISPLUS */
144267848Seric /*
144368350Seric **  HESIOD Modules
144468350Seric */
144568350Seric 
144668350Seric #ifdef HESIOD
144768350Seric 
144868350Seric #include <hesiod.h>
144968350Seric 
145068350Seric char *
145168350Seric hes_map_lookup(map, name, av, statp)
145268350Seric         MAP *map;
145368350Seric         char *name;
145468350Seric         char **av;
145568350Seric         int *statp;
145668350Seric {
145768350Seric 	char **hp;
145868350Seric 	char *retdata = NULL;
145968350Seric 	int i;
146068350Seric 
146168350Seric 	if (tTd(38, 20))
146268350Seric 		printf("hes_map_lookup(%s, %s)\n", map->map_file, name);
146368350Seric 
146468350Seric 	hp = hes_resolve(name, map->map_file);
146568350Seric 	if (hp == NULL)
146668350Seric 		return NULL;
146768350Seric 
146868350Seric 	if (hp[0] != NULL)
146968350Seric 	{
147068350Seric 		if (bitset(MF_MATCHONLY, map->map_mflags))
147168350Seric 			retdata = map_rewrite(map, name, strlen(name), NULL);
147268350Seric 		else
147368350Seric 			retdata = map_rewrite(map, hp[0], strlen(hp[0]), av);
147468350Seric 	}
147568350Seric 
147668350Seric 	for (i = 0; hp[i] != NULL; i++)
147768350Seric 		free(hp[i]);
147868350Seric 	free(hp);
147968350Seric 	return retdata;
148068350Seric }
148168350Seric 
148268350Seric #endif
148368350Seric /*
148468350Seric **  NeXT NETINFO Modules
148568350Seric */
148668350Seric 
148768350Seric #ifdef NETINFO
148868350Seric 
148968350Seric #define NETINFO_DEFAULT_DIR		"/aliases"
149068350Seric #define NETINFO_DEFAULT_PROPERTY	"members"
149168350Seric 
149268350Seric 
149368350Seric /*
149468350Seric **  NI_MAP_OPEN -- open NetInfo Aliases
149568350Seric */
149668350Seric 
149768350Seric bool
149868350Seric ni_map_open(map, mode)
149968350Seric 	MAP *map;
150068350Seric 	int mode;
150168350Seric {
150268350Seric 	char *p;
150368350Seric 
150468350Seric 	if (tTd(38, 20))
150568350Seric 		printf("ni_map_open: %s\n", map->map_file);
150668350Seric 
150768350Seric 	if (*map->map_file == '\0')
150868350Seric 		map->map_file = NETINFO_DEFAULT_DIR;
150968350Seric 
151068350Seric 	if (map->map_valcolnm == NULL)
151168350Seric 		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
151268350Seric 
151368350Seric 	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
151468350Seric 		map->map_coldelim = ',';
151568350Seric 
151668350Seric 	return TRUE;
151768350Seric }
151868350Seric 
151968350Seric 
152068350Seric /*
152168350Seric **  NI_MAP_LOOKUP -- look up a datum in NetInfo
152268350Seric */
152368350Seric 
152468350Seric char *
152568350Seric ni_map_lookup(map, name, av, statp)
152668350Seric 	MAP *map;
152768350Seric 	char *name;
152868350Seric 	char **av;
152968350Seric 	int *statp;
153068350Seric {
153168350Seric 	char *res;
153268350Seric 	char *propval;
153368350Seric 	extern char *ni_propval();
153468350Seric 
153568350Seric 	if (tTd(38, 20))
153668350Seric 		printf("ni_map_lookup(%s, %s)\n",
153768350Seric 			map->map_mname, name);
153868350Seric 
153968350Seric 	propval = ni_propval(map->map_file, map->map_keycolnm, name,
154068350Seric 			     map->map_valcolnm, map->map_coldelim);
154168350Seric 
154268350Seric 	if (propval == NULL)
154368350Seric 		return NULL;
154468350Seric 
154568350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
154668350Seric 		res = map_rewrite(map, name, strlen(name), NULL);
154768350Seric 	else
154868350Seric 		res = map_rewrite(map, propval, strlen(propval), av);
154968350Seric 	free(propval);
155068350Seric 	return res;
155168350Seric }
155268350Seric 
155368350Seric #endif
155468350Seric /*
155568350Seric **  TEXT (unindexed text file) Modules
155668350Seric **
155768350Seric **	This code donated by Sun Microsystems.
155868350Seric */
155968350Seric 
156068350Seric 
156168350Seric /*
156268350Seric **  TEXT_MAP_OPEN -- open text table
156368350Seric */
156468350Seric 
156568350Seric bool
156668350Seric text_map_open(map, mode)
156768350Seric 	MAP *map;
156868350Seric 	int mode;
156968350Seric {
157068350Seric 	struct stat sbuf;
157168350Seric 
157268350Seric 	if (tTd(38, 2))
157368350Seric 		printf("text_map_open(%s, %s, %d)\n",
157468350Seric 			map->map_mname, map->map_file, mode);
157568350Seric 
157668350Seric 	if (mode != O_RDONLY)
157768350Seric 	{
157868350Seric 		errno = ENODEV;
157968350Seric 		return FALSE;
158068350Seric 	}
158168350Seric 
158268350Seric 	if (*map->map_file == '\0')
158368350Seric 	{
158468350Seric 		if (tTd(38, 2))
158568350Seric 			printf("text_map_open: file name required\n");
158668350Seric 		return FALSE;
158768350Seric 	}
158868350Seric 
158968350Seric 	if (map->map_file[0] != '/')
159068350Seric 	{
159168350Seric 		if (tTd(38, 2))
159268350Seric 			printf("text_map_open(%s): file name must be fully qualified\n",
159368350Seric 				map->map_file);
159468350Seric 		return FALSE;
159568350Seric 	}
159668350Seric 	/* check to see if this map actually accessable */
159768350Seric 	if (access(map->map_file, R_OK) <0)
159868350Seric 		return FALSE;
159968350Seric 
160068350Seric 	/* check to see if this map actually exist */
160168350Seric 	if (stat(map->map_file, &sbuf) <0)
160268350Seric 	{
160368350Seric 		if (tTd(38, 2))
160468350Seric 			printf("text_map_open(%s): can not stat %s\n",
160568350Seric 				map->map_file, map->map_file);
160668350Seric 		return FALSE;
160768350Seric 	}
160868350Seric 
160968350Seric 	if (!S_ISREG(sbuf.st_mode))
161068350Seric 	{
161168350Seric 		if (tTd(38, 2))
161268350Seric 			printf("text_map_open(%s): %s is not a file\n",
161368350Seric 				map->map_file, map->map_file);
161468350Seric 		return FALSE;
161568350Seric 	}
161668350Seric 
161768350Seric 	if (map->map_keycolnm == NULL)
161868350Seric 		map->map_keycolno = 0;
161968350Seric 	else
162068350Seric 	{
162168350Seric 		if (!isdigit(*map->map_keycolnm))
162268350Seric 		{
162368350Seric 			if (tTd(38, 2))
162468350Seric 				printf("text_map_open(%s): -k should specify a number, not %s\n",
162568350Seric 					map->map_file, map->map_keycolnm);
162668350Seric 			return FALSE;
162768350Seric 		}
162868350Seric 		map->map_keycolno = atoi(map->map_keycolnm);
162968350Seric 	}
163068350Seric 
163168350Seric 	if (map->map_valcolnm == NULL)
163268350Seric 		map->map_valcolno = 0;
163368350Seric 	else
163468350Seric 	{
163568350Seric 		if (!isdigit(*map->map_valcolnm))
163668350Seric 		{
163768350Seric 			if (tTd(38, 2))
163868350Seric 				printf("text_map_open(%s): -v should specify a number, not %s\n",
163968350Seric 					map->map_file, map->map_valcolnm);
164068350Seric 			return FALSE;
164168350Seric 		}
164268350Seric 		map->map_valcolno = atoi(map->map_valcolnm);
164368350Seric 	}
164468350Seric 
164568350Seric 	if (tTd(38, 2))
164668350Seric 	{
164768520Seric 		printf("text_map_open(%s): delimiter = ",
164868520Seric 			map->map_file);
164968520Seric 		if (map->map_coldelim == '\0')
165068520Seric 			printf("(white space)\n");
165168520Seric 		else
165268520Seric 			printf("%c\n", map->map_coldelim);
165368350Seric 	}
165468350Seric 
165568350Seric 	return TRUE;
165668350Seric }
165768350Seric 
165868350Seric 
165968350Seric /*
166068350Seric **  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
166168350Seric */
166268350Seric 
166368350Seric char *
166468350Seric text_map_lookup(map, name, av, statp)
166568350Seric 	MAP *map;
166668350Seric 	char *name;
166768350Seric 	char **av;
166868350Seric 	int *statp;
166968350Seric {
167068350Seric 	char *vp;
167168350Seric 	auto int vsize;
167268350Seric 	int buflen;
167368350Seric 	char search_key[MAXNAME + 1];
167468350Seric 	char linebuf[MAXLINE];
167568350Seric 	FILE *f;
167668528Seric 	char buf[MAXNAME + 1];
167768350Seric 	char delim;
167868350Seric 	int key_idx;
167968350Seric 	bool found_it;
168068350Seric 	extern char *get_column();
168168350Seric 
168268350Seric 
168368350Seric 	found_it = FALSE;
168468350Seric 	if (tTd(38, 20))
168568350Seric 		printf("text_map_lookup(%s)\n", name);
168668350Seric 
168768350Seric 	buflen = strlen(name);
168868350Seric 	if (buflen > sizeof search_key - 1)
168968350Seric 		buflen = sizeof search_key - 1;
169068350Seric 	bcopy(name, search_key, buflen + 1);
169168350Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
169268350Seric 		makelower(search_key);
169368350Seric 
169468350Seric 	f = fopen(map->map_file, "r");
169568350Seric 	if (f == NULL)
169668350Seric 	{
169768350Seric 		map->map_mflags &= ~(MF_VALID|MF_OPEN);
169868350Seric 		*statp = EX_UNAVAILABLE;
169968350Seric 		return NULL;
170068350Seric 	}
170168350Seric 	key_idx = map->map_keycolno;
170268350Seric 	delim = map->map_coldelim;
170368350Seric 	while (fgets(linebuf, MAXLINE, f))
170468350Seric 	{
170568350Seric 		char *lf;
170668350Seric 		if (linebuf[0] == '#')
170768350Seric 			continue; /* skip comment line */
170868350Seric 		if (lf = strchr(linebuf, '\n'))
170968350Seric 			*lf = '\0';
171068350Seric 		if (!strcasecmp(search_key,
171168350Seric 				get_column(linebuf, key_idx, delim, buf)))
171268350Seric 		{
171368350Seric 			found_it = TRUE;
171468350Seric 			break;
171568350Seric 		}
171668350Seric 	}
171768350Seric 	fclose(f);
171868350Seric 	if (!found_it)
171968350Seric 	{
172068350Seric #ifdef MAP_EXIT_STAT
172168350Seric 		*statp = EX_NOTFOUND;
172268350Seric #endif
172368350Seric 		return(NULL);
172468350Seric 	}
172568350Seric 	vp = get_column(linebuf, map->map_valcolno, delim, buf);
172668350Seric 	vsize = strlen(vp);
172768350Seric #ifdef MAP_EXIT_STAT
172868350Seric 	*statp = EX_OK;
172968350Seric #endif
173068350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
173168350Seric 		return map_rewrite(map, name, strlen(name), NULL);
173268350Seric 	else
173368350Seric 		return map_rewrite(map, vp, vsize, av);
173468350Seric }
173568350Seric /*
173660089Seric **  STAB (Symbol Table) Modules
173760089Seric */
173860089Seric 
173960089Seric 
174060089Seric /*
174160207Seric **  STAB_MAP_LOOKUP -- look up alias in symbol table
174260089Seric */
174360089Seric 
174460089Seric char *
174561707Seric stab_map_lookup(map, name, av, pstat)
174660089Seric 	register MAP *map;
174760089Seric 	char *name;
174861707Seric 	char **av;
174961707Seric 	int *pstat;
175060089Seric {
175160089Seric 	register STAB *s;
175260089Seric 
175360537Seric 	if (tTd(38, 20))
175468350Seric 		printf("stab_lookup(%s, %s)\n",
175568350Seric 			map->map_mname, name);
175660089Seric 
175760089Seric 	s = stab(name, ST_ALIAS, ST_FIND);
175860089Seric 	if (s != NULL)
175960089Seric 		return (s->s_alias);
176060089Seric 	return (NULL);
176160089Seric }
176260089Seric 
176360089Seric 
176460089Seric /*
176560207Seric **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
176660089Seric */
176760089Seric 
176860089Seric void
176960089Seric stab_map_store(map, lhs, rhs)
177060089Seric 	register MAP *map;
177160089Seric 	char *lhs;
177260089Seric 	char *rhs;
177360089Seric {
177460089Seric 	register STAB *s;
177560089Seric 
177660089Seric 	s = stab(lhs, ST_ALIAS, ST_ENTER);
177760089Seric 	s->s_alias = newstr(rhs);
177860089Seric }
177960089Seric 
178060089Seric 
178160089Seric /*
178260207Seric **  STAB_MAP_OPEN -- initialize (reads data file)
178360207Seric **
178460207Seric **	This is a wierd case -- it is only intended as a fallback for
178560207Seric **	aliases.  For this reason, opens for write (only during a
178660207Seric **	"newaliases") always fails, and opens for read open the
178760207Seric **	actual underlying text file instead of the database.
178860089Seric */
178960089Seric 
179060089Seric bool
179160089Seric stab_map_open(map, mode)
179260089Seric 	register MAP *map;
179360089Seric 	int mode;
179460089Seric {
179563835Seric 	FILE *af;
179664284Seric 	struct stat st;
179763835Seric 
179860537Seric 	if (tTd(38, 2))
179968350Seric 		printf("stab_map_open(%s, %s)\n",
180068350Seric 			map->map_mname, map->map_file);
180160089Seric 
180260089Seric 	if (mode != O_RDONLY)
180360207Seric 	{
180460207Seric 		errno = ENODEV;
180560089Seric 		return FALSE;
180660207Seric 	}
180760089Seric 
180863835Seric 	af = fopen(map->map_file, "r");
180963835Seric 	if (af == NULL)
181063835Seric 		return FALSE;
181168350Seric 	readaliases(map, af, FALSE, FALSE);
181264284Seric 
181364284Seric 	if (fstat(fileno(af), &st) >= 0)
181464284Seric 		map->map_mtime = st.st_mtime;
181563835Seric 	fclose(af);
181663835Seric 
181760089Seric 	return TRUE;
181860089Seric }
181960089Seric /*
182060089Seric **  Implicit Modules
182156822Seric **
182260089Seric **	Tries several types.  For back compatibility of aliases.
182356822Seric */
182456822Seric 
182560089Seric 
182660089Seric /*
182760207Seric **  IMPL_MAP_LOOKUP -- lookup in best open database
182860089Seric */
182960089Seric 
183060089Seric char *
183160089Seric impl_map_lookup(map, name, av, pstat)
183260089Seric 	MAP *map;
183360089Seric 	char *name;
183456822Seric 	char **av;
183560089Seric 	int *pstat;
183656822Seric {
183760537Seric 	if (tTd(38, 20))
183868350Seric 		printf("impl_map_lookup(%s, %s)\n",
183968350Seric 			map->map_mname, name);
184056822Seric 
184160089Seric #ifdef NEWDB
184260207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
184360089Seric 		return db_map_lookup(map, name, av, pstat);
184460089Seric #endif
184560089Seric #ifdef NDBM
184660207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
184760089Seric 		return ndbm_map_lookup(map, name, av, pstat);
184860089Seric #endif
184960089Seric 	return stab_map_lookup(map, name, av, pstat);
185060089Seric }
185160089Seric 
185260089Seric /*
185360207Seric **  IMPL_MAP_STORE -- store in open databases
185460089Seric */
185560089Seric 
185660089Seric void
185760089Seric impl_map_store(map, lhs, rhs)
185860089Seric 	MAP *map;
185960089Seric 	char *lhs;
186060089Seric 	char *rhs;
186160089Seric {
186260089Seric #ifdef NEWDB
186360207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
186460089Seric 		db_map_store(map, lhs, rhs);
186560089Seric #endif
186660089Seric #ifdef NDBM
186760207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
186860089Seric 		ndbm_map_store(map, lhs, rhs);
186960089Seric #endif
187060089Seric 	stab_map_store(map, lhs, rhs);
187160089Seric }
187260089Seric 
187360089Seric /*
187460089Seric **  IMPL_MAP_OPEN -- implicit database open
187560089Seric */
187660089Seric 
187760089Seric bool
187860089Seric impl_map_open(map, mode)
187960089Seric 	MAP *map;
188060089Seric 	int mode;
188160089Seric {
188260089Seric 	struct stat stb;
188360089Seric 
188460537Seric 	if (tTd(38, 2))
188568350Seric 		printf("impl_map_open(%s, %s, %d)\n",
188668350Seric 			map->map_mname, map->map_file, mode);
188760089Seric 
188860089Seric 	if (stat(map->map_file, &stb) < 0)
188956822Seric 	{
189060089Seric 		/* no alias file at all */
189164718Seric 		if (tTd(38, 3))
189264718Seric 			printf("no map file\n");
189360089Seric 		return FALSE;
189456822Seric 	}
189556822Seric 
189660089Seric #ifdef NEWDB
189760207Seric 	map->map_mflags |= MF_IMPL_HASH;
189860089Seric 	if (hash_map_open(map, mode))
189956822Seric 	{
190064250Seric #if defined(NDBM) && defined(NIS)
190160561Seric 		if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0)
190260207Seric #endif
190360207Seric 			return TRUE;
190460089Seric 	}
190560207Seric 	else
190660207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
190760089Seric #endif
190860089Seric #ifdef NDBM
190960207Seric 	map->map_mflags |= MF_IMPL_NDBM;
191060089Seric 	if (ndbm_map_open(map, mode))
191160089Seric 	{
191260089Seric 		return TRUE;
191360089Seric 	}
191460207Seric 	else
191560207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
191660089Seric #endif
191756822Seric 
191864650Seric #if defined(NEWDB) || defined(NDBM)
191960089Seric 	if (Verbose)
192060089Seric 		message("WARNING: cannot open alias database %s", map->map_file);
192164964Seric #else
192264964Seric 	if (mode != O_RDONLY)
192364964Seric 		usrerr("Cannot rebuild aliases: no database format defined");
192460207Seric #endif
192560089Seric 
192660207Seric 	return stab_map_open(map, mode);
192756822Seric }
192860089Seric 
192960207Seric 
193060089Seric /*
193160207Seric **  IMPL_MAP_CLOSE -- close any open database(s)
193260089Seric */
193360089Seric 
193460089Seric void
193560207Seric impl_map_close(map)
193660089Seric 	MAP *map;
193760089Seric {
193868350Seric 	if (tTd(38, 20))
193968350Seric 		printf("impl_map_close(%s, %s, %x)\n",
194068350Seric 			map->map_mname, map->map_file, map->map_mflags);
194160089Seric #ifdef NEWDB
194260207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
194360089Seric 	{
194460207Seric 		db_map_close(map);
194560207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
194660089Seric 	}
194760089Seric #endif
194860089Seric 
194960089Seric #ifdef NDBM
195060207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
195160089Seric 	{
195260207Seric 		ndbm_map_close(map);
195360207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
195460089Seric 	}
195560089Seric #endif
195660089Seric }
195760207Seric /*
195868350Seric **  User map class.
195968350Seric **
196068350Seric **	Provides access to the system password file.
196168350Seric */
196268350Seric 
196368350Seric /*
196468350Seric **  USER_MAP_OPEN -- open user map
196568350Seric **
196668350Seric **	Really just binds field names to field numbers.
196768350Seric */
196868350Seric 
196968350Seric bool
197068350Seric user_map_open(map, mode)
197168350Seric 	MAP *map;
197268350Seric 	int mode;
197368350Seric {
197468350Seric 	if (tTd(38, 2))
197568350Seric 		printf("user_map_open(%s)\n", map->map_mname);
197668350Seric 
197768350Seric 	if (mode != O_RDONLY)
197868350Seric 	{
197968350Seric 		/* issue a pseudo-error message */
198068350Seric #ifdef ENOSYS
198168350Seric 		errno = ENOSYS;
198268350Seric #else
198368350Seric # ifdef EFTYPE
198468350Seric 		errno = EFTYPE;
198568350Seric # else
198668350Seric 		errno = ENXIO;
198768350Seric # endif
198868350Seric #endif
198968350Seric 		return FALSE;
199068350Seric 	}
199168350Seric 	if (map->map_valcolnm == NULL)
199268350Seric 		/* nothing */ ;
199368350Seric 	else if (strcasecmp(map->map_valcolnm, "name") == 0)
199468350Seric 		map->map_valcolno = 1;
199568350Seric 	else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
199668350Seric 		map->map_valcolno = 2;
199768350Seric 	else if (strcasecmp(map->map_valcolnm, "uid") == 0)
199868350Seric 		map->map_valcolno = 3;
199968350Seric 	else if (strcasecmp(map->map_valcolnm, "gid") == 0)
200068350Seric 		map->map_valcolno = 4;
200168350Seric 	else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
200268350Seric 		map->map_valcolno = 5;
200368350Seric 	else if (strcasecmp(map->map_valcolnm, "dir") == 0)
200468350Seric 		map->map_valcolno = 6;
200568350Seric 	else if (strcasecmp(map->map_valcolnm, "shell") == 0)
200668350Seric 		map->map_valcolno = 7;
200768350Seric 	else
200868350Seric 	{
200968350Seric 		syserr("User map %s: unknown column name %s",
201068350Seric 			map->map_mname, map->map_valcolnm);
201168350Seric 		return FALSE;
201268350Seric 	}
201368350Seric 	return TRUE;
201468350Seric }
201568350Seric 
201668350Seric 
201768350Seric /*
201868350Seric **  USER_MAP_LOOKUP -- look up a user in the passwd file.
201968350Seric */
202068350Seric 
202168350Seric char *
202268350Seric user_map_lookup(map, key, av, statp)
202368350Seric 	MAP *map;
202468350Seric 	char *key;
202568350Seric 	char **av;
202668350Seric 	int *statp;
202768350Seric {
202868350Seric 	struct passwd *pw;
202968350Seric 
203068350Seric 	if (tTd(38, 20))
203168350Seric 		printf("user_map_lookup(%s, %s)\n",
203268350Seric 			map->map_mname, key);
203368350Seric 
203468693Seric 	pw = sm_getpwnam(key);
203568350Seric 	if (pw == NULL)
203668350Seric 		return NULL;
203768350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
203868350Seric 		return map_rewrite(map, key, strlen(key), NULL);
203968350Seric 	else
204068350Seric 	{
204168433Seric 		char *rwval = NULL;
204268350Seric 		char buf[30];
204368350Seric 
204468350Seric 		switch (map->map_valcolno)
204568350Seric 		{
204668350Seric 		  case 0:
204768350Seric 		  case 1:
204868350Seric 			rwval = pw->pw_name;
204968350Seric 			break;
205068350Seric 
205168350Seric 		  case 2:
205268350Seric 			rwval = pw->pw_passwd;
205368350Seric 			break;
205468350Seric 
205568350Seric 		  case 3:
205668350Seric 			sprintf(buf, "%d", pw->pw_uid);
205768350Seric 			rwval = buf;
205868350Seric 			break;
205968350Seric 
206068350Seric 		  case 4:
206168350Seric 			sprintf(buf, "%d", pw->pw_gid);
206268350Seric 			rwval = buf;
206368350Seric 			break;
206468350Seric 
206568350Seric 		  case 5:
206668350Seric 			rwval = pw->pw_gecos;
206768350Seric 			break;
206868350Seric 
206968350Seric 		  case 6:
207068350Seric 			rwval = pw->pw_dir;
207168350Seric 			break;
207268350Seric 
207368350Seric 		  case 7:
207468350Seric 			rwval = pw->pw_shell;
207568350Seric 			break;
207668350Seric 		}
207768350Seric 		return map_rewrite(map, rwval, strlen(rwval), av);
207868350Seric 	}
207968350Seric }
208068350Seric /*
208168350Seric **  BESTMX -- find the best MX for a name
208268350Seric **
208368350Seric **	This is really a hack, but I don't see any obvious way
208468350Seric **	to generalize it at the moment.
208568350Seric */
208668350Seric 
208768350Seric #if NAMED_BIND
208868350Seric 
208968350Seric char *
209068350Seric bestmx_map_lookup(map, name, av, statp)
209168350Seric 	MAP *map;
209268350Seric 	char *name;
209368350Seric 	char **av;
209468350Seric 	int *statp;
209568350Seric {
209668350Seric         int nmx;
209768350Seric         auto int rcode;
209868350Seric         char *mxhosts[MAXMXHOSTS + 1];
209968350Seric 
210068350Seric 	nmx = getmxrr(name, mxhosts, FALSE, &rcode);
210168350Seric 	if (nmx <= 0)
210268350Seric 		return NULL;
210368350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
210468350Seric 		return map_rewrite(map, name, strlen(name), NULL);
210568350Seric 	else
210668350Seric 		return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
210768350Seric }
210868350Seric 
210968350Seric #endif
211068350Seric /*
211168350Seric **  Sequenced map type.
211268350Seric **
211368350Seric **	Tries each map in order until something matches, much like
211468350Seric **	implicit.  Stores go to the first map in the list that can
211568350Seric **	support storing.
211668350Seric **
211768350Seric **	This is slightly unusual in that there are two interfaces.
211868350Seric **	The "sequence" interface lets you stack maps arbitrarily.
211968350Seric **	The "switch" interface builds a sequence map by looking
212068350Seric **	at a system-dependent configuration file such as
212168350Seric **	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
212268350Seric **
212368350Seric **	We don't need an explicit open, since all maps are
212468350Seric **	opened during startup, including underlying maps.
212568350Seric */
212668350Seric 
212768350Seric /*
212868350Seric **  SEQ_MAP_PARSE -- Sequenced map parsing
212968350Seric */
213068350Seric 
213168350Seric bool
213268350Seric seq_map_parse(map, ap)
213368350Seric 	MAP *map;
213468350Seric 	char *ap;
213568350Seric {
213668350Seric 	int maxmap;
213768350Seric 
213868350Seric 	if (tTd(38, 2))
213968350Seric 		printf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
214068350Seric 	maxmap = 0;
214168350Seric 	while (*ap != '\0')
214268350Seric 	{
214368350Seric 		register char *p;
214468350Seric 		STAB *s;
214568350Seric 
214668350Seric 		/* find beginning of map name */
214768350Seric 		while (isascii(*ap) && isspace(*ap))
214868350Seric 			ap++;
214968350Seric 		for (p = ap; isascii(*p) && isalnum(*p); p++)
215068350Seric 			continue;
215168350Seric 		if (*p != '\0')
215268350Seric 			*p++ = '\0';
215368350Seric 		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
215468350Seric 			p++;
215568350Seric 		if (*ap == '\0')
215668350Seric 		{
215768350Seric 			ap = p;
215868350Seric 			continue;
215968350Seric 		}
216068350Seric 		s = stab(ap, ST_MAP, ST_FIND);
216168350Seric 		if (s == NULL)
216268350Seric 		{
216368350Seric 			syserr("Sequence map %s: unknown member map %s",
216468350Seric 				map->map_mname, ap);
216568350Seric 		}
216668350Seric 		else if (maxmap == MAXMAPSTACK)
216768350Seric 		{
216868350Seric 			syserr("Sequence map %s: too many member maps (%d max)",
216968350Seric 				map->map_mname, MAXMAPSTACK);
217068350Seric 			maxmap++;
217168350Seric 		}
217268350Seric 		else if (maxmap < MAXMAPSTACK)
217368350Seric 		{
217468350Seric 			map->map_stack[maxmap++] = &s->s_map;
217568350Seric 		}
217668350Seric 		ap = p;
217768350Seric 	}
217868350Seric 	return TRUE;
217968350Seric }
218068350Seric 
218168350Seric 
218268350Seric /*
218368350Seric **  SWITCH_MAP_OPEN -- open a switched map
218468350Seric **
218568350Seric **	This looks at the system-dependent configuration and builds
218668350Seric **	a sequence map that does the same thing.
218768350Seric **
218868350Seric **	Every system must define a switch_map_find routine in conf.c
218968350Seric **	that will return the list of service types associated with a
219068350Seric **	given service class.
219168350Seric */
219268350Seric 
219368350Seric bool
219468350Seric switch_map_open(map, mode)
219568350Seric 	MAP *map;
219668350Seric 	int mode;
219768350Seric {
219868350Seric 	int mapno;
219968350Seric 	int nmaps;
220068350Seric 	char *maptype[MAXMAPSTACK];
220168350Seric 
220268350Seric 	if (tTd(38, 2))
220368350Seric 		printf("switch_map_open(%s, %s, %d)\n",
220468350Seric 			map->map_mname, map->map_file, mode);
220568350Seric 
220668350Seric 	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
220768350Seric 	if (tTd(38, 19))
220868350Seric 	{
220968350Seric 		printf("\tswitch_map_find => %d\n", nmaps);
221068350Seric 		for (mapno = 0; mapno < nmaps; mapno++)
221168350Seric 			printf("\t\t%s\n", maptype[mapno]);
221268350Seric 	}
221368350Seric 	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
221468350Seric 		return FALSE;
221568350Seric 
221668350Seric 	for (mapno = 0; mapno < nmaps; mapno++)
221768350Seric 	{
221868350Seric 		register STAB *s;
221968350Seric 		char nbuf[MAXNAME + 1];
222068350Seric 
222168350Seric 		if (maptype[mapno] == NULL)
222268350Seric 			continue;
222368350Seric 		(void) sprintf(nbuf, "%s.%s", map->map_file, maptype[mapno]);
222468350Seric 		s = stab(nbuf, ST_MAP, ST_FIND);
222568350Seric 		if (s == NULL)
222668350Seric 		{
222768350Seric 			syserr("Switch map %s: unknown member map %s",
222868350Seric 				map->map_mname, nbuf);
222968350Seric 		}
223068350Seric 		else
223168350Seric 		{
223268350Seric 			map->map_stack[mapno] = &s->s_map;
223368350Seric 			if (tTd(38, 4))
223468350Seric 				printf("\tmap_stack[%d] = %s:%s\n",
223568350Seric 					mapno, s->s_map.map_class->map_cname,
223668350Seric 					nbuf);
223768350Seric 		}
223868350Seric 	}
223968350Seric 	return TRUE;
224068350Seric }
224168350Seric 
224268350Seric 
224368350Seric /*
224468350Seric **  SEQ_MAP_CLOSE -- close all underlying maps
224568350Seric */
224668350Seric 
224768350Seric seq_map_close(map)
224868350Seric 	MAP *map;
224968350Seric {
225068350Seric 	int mapno;
225168350Seric 
225268350Seric 	if (tTd(38, 20))
225368350Seric 		printf("seq_map_close(%s)\n", map->map_mname);
225468350Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
225568350Seric 	{
225668350Seric 		MAP *mm = map->map_stack[mapno];
225768350Seric 
225868350Seric 		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
225968350Seric 			continue;
226068350Seric 		mm->map_class->map_close(mm);
226168798Seric 		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
226268350Seric 	}
226368350Seric }
226468350Seric 
226568350Seric 
226668350Seric /*
226768350Seric **  SEQ_MAP_LOOKUP -- sequenced map lookup
226868350Seric */
226968350Seric 
227068350Seric char *
227168350Seric seq_map_lookup(map, key, args, pstat)
227268350Seric 	MAP *map;
227368350Seric 	char *key;
227468350Seric 	char **args;
227568350Seric 	int *pstat;
227668350Seric {
227768350Seric 	int mapno;
227868350Seric 	int mapbit = 0x01;
227968350Seric 
228068350Seric 	if (tTd(38, 20))
228168350Seric 		printf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
228268350Seric 
228368350Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
228468350Seric 	{
228568350Seric 		MAP *mm = map->map_stack[mapno];
228668350Seric 		int stat = 0;
228768350Seric 		char *rv;
228868350Seric 
228968350Seric 		if (mm == NULL)
229068350Seric 			continue;
229168350Seric 		if (!bitset(MF_OPEN, mm->map_mflags))
229268350Seric 		{
229368350Seric 			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
229468350Seric 			{
229568350Seric 				*pstat = EX_UNAVAILABLE;
229668350Seric 				return NULL;
229768350Seric 			}
229868350Seric 			continue;
229968350Seric 		}
230068350Seric 		rv = mm->map_class->map_lookup(mm, key, args, &stat);
230168350Seric 		if (rv != NULL)
230268350Seric 			return rv;
230368350Seric 		if (stat == 0 && bitset(mapbit, map->map_return[MA_NOTFOUND]))
230468350Seric 			return NULL;
230568350Seric 		if (stat != 0 && bitset(mapbit, map->map_return[MA_TRYAGAIN]))
230668350Seric 		{
230768350Seric 			*pstat = stat;
230868350Seric 			return NULL;
230968350Seric 		}
231068350Seric 	}
231168350Seric 	return NULL;
231268350Seric }
231368350Seric 
231468350Seric 
231568350Seric /*
231668350Seric **  SEQ_MAP_STORE -- sequenced map store
231768350Seric */
231868350Seric 
231968350Seric void
232068350Seric seq_map_store(map, key, val)
232168350Seric 	MAP *map;
232268350Seric 	char *key;
232368350Seric 	char *val;
232468350Seric {
232568350Seric 	int mapno;
232668350Seric 
232768350Seric 	if (tTd(38, 12))
232868350Seric 		printf("seq_map_store(%s, %s, %s)\n",
232968350Seric 			map->map_mname, key, val);
233068350Seric 
233168350Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
233268350Seric 	{
233368350Seric 		MAP *mm = map->map_stack[mapno];
233468350Seric 
233568350Seric 		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
233668350Seric 			continue;
233768350Seric 
233868350Seric 		mm->map_class->map_store(mm, key, val);
233968350Seric 		return;
234068350Seric 	}
234168350Seric 	syserr("seq_map_store(%s, %s, %s): no writable map",
234268350Seric 		map->map_mname, key, val);
234368350Seric }
234468350Seric /*
234560207Seric **  NULL stubs
234660089Seric */
234760089Seric 
234860207Seric bool
234960207Seric null_map_open(map, mode)
235060089Seric 	MAP *map;
235160207Seric 	int mode;
235260089Seric {
235360207Seric 	return TRUE;
235460089Seric }
235560089Seric 
235660207Seric void
235760207Seric null_map_close(map)
235860207Seric 	MAP *map;
235960089Seric {
236060207Seric 	return;
236160207Seric }
236260089Seric 
236360207Seric void
236460207Seric null_map_store(map, key, val)
236560207Seric 	MAP *map;
236660207Seric 	char *key;
236760207Seric 	char *val;
236860089Seric {
236960207Seric 	return;
237060089Seric }
237168350Seric 
237268350Seric 
237368350Seric /*
237468350Seric **  BOGUS stubs
237568350Seric */
237668350Seric 
237768350Seric char *
237868350Seric bogus_map_lookup(map, key, args, pstat)
237968350Seric 	MAP *map;
238068350Seric 	char *key;
238168350Seric 	char **args;
238268350Seric 	int *pstat;
238368350Seric {
238468350Seric 	*pstat = EX_TEMPFAIL;
238568350Seric 	return NULL;
238668350Seric }
238768350Seric 
238868350Seric MAPCLASS	BogusMapClass =
238968350Seric {
239068350Seric 	"bogus-map",		NULL,		0,
239168350Seric 	NULL,		bogus_map_lookup,	null_map_store,
239268350Seric 	null_map_open,	null_map_close,
239368350Seric };
2394