xref: /csrg-svn/usr.sbin/sendmail/src/map.c (revision 67848)
156822Seric /*
256822Seric  * Copyright (c) 1992 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*67848Seric static char sccsid[] = "@(#)map.c	8.32 (Berkeley) 10/24/94";
1156822Seric #endif /* not lint */
1256822Seric 
1356822Seric #include "sendmail.h"
1456822Seric 
1560089Seric #ifdef NDBM
1656822Seric #include <ndbm.h>
1756822Seric #endif
1860089Seric #ifdef NEWDB
1956822Seric #include <db.h>
2056822Seric #endif
2160089Seric #ifdef NIS
2257208Seric #include <rpcsvc/ypclnt.h>
2357208Seric #endif
2456822Seric 
2556822Seric /*
2660089Seric **  MAP.C -- implementations for various map classes.
2756822Seric **
2860089Seric **	Each map class implements a series of functions:
2960089Seric **
3060089Seric **	bool map_parse(MAP *map, char *args)
3160089Seric **		Parse the arguments from the config file.  Return TRUE
3260089Seric **		if they were ok, FALSE otherwise.  Fill in map with the
3360089Seric **		values.
3460089Seric **
3560222Seric **	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
3660222Seric **		Look up the key in the given map.  If found, do any
3760222Seric **		rewriting the map wants (including "args" if desired)
3860089Seric **		and return the value.  Set *pstat to the appropriate status
3960222Seric **		on error and return NULL.  Args will be NULL if called
4060222Seric **		from the alias routines, although this should probably
4160222Seric **		not be relied upon.  It is suggested you call map_rewrite
4260222Seric **		to return the results -- it takes care of null termination
4360222Seric **		and uses a dynamically expanded buffer as needed.
4460089Seric **
4560089Seric **	void map_store(MAP *map, char *key, char *value)
4660089Seric **		Store the key:value pair in the map.
4760089Seric **
4860089Seric **	bool map_open(MAP *map, int mode)
4960222Seric **		Open the map for the indicated mode.  Mode should
5060222Seric **		be either O_RDONLY or O_RDWR.  Return TRUE if it
5160222Seric **		was opened successfully, FALSE otherwise.  If the open
5260222Seric **		failed an the MF_OPTIONAL flag is not set, it should
5360222Seric **		also print an error.  If the MF_ALIAS bit is set
5460222Seric **		and this map class understands the @:@ convention, it
5560222Seric **		should call aliaswait() before returning.
5660089Seric **
5760089Seric **	void map_close(MAP *map)
5860089Seric **		Close the map.
5960089Seric */
6060089Seric 
6160089Seric #define DBMMODE		0644
6264718Seric 
6364718Seric extern bool	aliaswait __P((MAP *, char *, int));
6460089Seric /*
6560089Seric **  MAP_PARSEARGS -- parse config line arguments for database lookup
6660089Seric **
6760089Seric **	This is a generic version of the map_parse method.
6860089Seric **
6956822Seric **	Parameters:
7060089Seric **		map -- the map being initialized.
7160089Seric **		ap -- a pointer to the args on the config line.
7256822Seric **
7356822Seric **	Returns:
7460089Seric **		TRUE -- if everything parsed OK.
7556822Seric **		FALSE -- otherwise.
7656822Seric **
7756822Seric **	Side Effects:
7860089Seric **		null terminates the filename; stores it in map
7956822Seric */
8056822Seric 
8156822Seric bool
8260089Seric map_parseargs(map, ap)
8356822Seric 	MAP *map;
8460089Seric 	char *ap;
8556822Seric {
8660089Seric 	register char *p = ap;
8756822Seric 
8863753Seric 	map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
8960089Seric 	for (;;)
9060089Seric 	{
9160089Seric 		while (isascii(*p) && isspace(*p))
9260089Seric 			p++;
9360089Seric 		if (*p != '-')
9460089Seric 			break;
9560089Seric 		switch (*++p)
9660089Seric 		{
9760089Seric 		  case 'N':
9860207Seric 			map->map_mflags |= MF_INCLNULL;
9963753Seric 			map->map_mflags &= ~MF_TRY0NULL;
10060089Seric 			break;
10160089Seric 
10263753Seric 		  case 'O':
10363753Seric 			map->map_mflags &= ~MF_TRY1NULL;
10463753Seric 			break;
10563753Seric 
10660089Seric 		  case 'o':
10760207Seric 			map->map_mflags |= MF_OPTIONAL;
10860089Seric 			break;
10960089Seric 
11060089Seric 		  case 'f':
11160207Seric 			map->map_mflags |= MF_NOFOLDCASE;
11260089Seric 			break;
11360089Seric 
11460089Seric 		  case 'm':
11560207Seric 			map->map_mflags |= MF_MATCHONLY;
11660089Seric 			break;
11760089Seric 
11860089Seric 		  case 'a':
11960089Seric 			map->map_app = ++p;
12060089Seric 			break;
12167726Seric 
12267726Seric 		  case 'k':
12367726Seric 			while (isascii(*++p) && isspace(*p))
12467726Seric 				continue;
12567726Seric 			map->map_keycolnm = p;
12667726Seric 			break;
12767726Seric 
12867726Seric 		  case 'v':
12967726Seric 			while (isascii(*++p) && isspace(*p))
13067726Seric 				continue;
13167726Seric 			map->map_valcolnm = p;
13267726Seric 			break;
13367726Seric 
13467726Seric 		  case 'z':
13567726Seric 			if (*++p != '\\')
13667726Seric 				map->map_coldelim = *p;
13767726Seric 			else
13867726Seric 			{
13967726Seric 				switch (*++p)
14067726Seric 				{
14167726Seric 				  case 'n':
14267726Seric 					map->map_coldelim = '\n';
14367726Seric 					break;
14467726Seric 
14567726Seric 				  case 't':
14667726Seric 					map->map_coldelim = '\t';
14767726Seric 					break;
14867726Seric 
14967726Seric 				  default:
15067726Seric 					map->map_coldelim = '\\';
15167726Seric 				}
15267726Seric 			}
15367726Seric 			break;
15460089Seric 		}
15560089Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
15660089Seric 			p++;
15760089Seric 		if (*p != '\0')
15860089Seric 			*p++ = '\0';
15960089Seric 	}
16060089Seric 	if (map->map_app != NULL)
16160089Seric 		map->map_app = newstr(map->map_app);
16267726Seric 	if (map->map_keycolnm != NULL)
16367726Seric 		map->map_keycolnm = newstr(map->map_keycolnm);
16467726Seric 	if (map->map_valcolnm != NULL)
16567726Seric 		map->map_valcolnm = newstr(map->map_valcolnm);
16660089Seric 
16760089Seric 	if (*p != '\0')
16860089Seric 	{
16960089Seric 		map->map_file = p;
17060089Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
17160089Seric 			p++;
17260089Seric 		if (*p != '\0')
17360089Seric 			*p++ = '\0';
17460089Seric 		map->map_file = newstr(map->map_file);
17560089Seric 	}
17660089Seric 
17760089Seric 	while (*p != '\0' && isascii(*p) && isspace(*p))
17860089Seric 		p++;
17960089Seric 	if (*p != '\0')
18060089Seric 		map->map_rebuild = newstr(p);
18160089Seric 
18256822Seric 	if (map->map_file == NULL)
18357208Seric 	{
18460089Seric 		syserr("No file name for %s map %s",
18560089Seric 			map->map_class->map_cname, map->map_mname);
18656822Seric 		return FALSE;
18757208Seric 	}
18860089Seric 	return TRUE;
18960089Seric }
19060089Seric /*
19160089Seric **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
19260089Seric **
19360089Seric **	It also adds the map_app string.  It can be used as a utility
19460089Seric **	in the map_lookup method.
19560089Seric **
19660089Seric **	Parameters:
19760089Seric **		map -- the map that causes this.
19860089Seric **		s -- the string to rewrite, NOT necessarily null terminated.
19960089Seric **		slen -- the length of s.
20060089Seric **		av -- arguments to interpolate into buf.
20160089Seric **
20260089Seric **	Returns:
20360089Seric **		Pointer to rewritten result.
20460089Seric **
20560089Seric **	Side Effects:
20660089Seric **		none.
20760089Seric */
20860089Seric 
20960492Seric struct rwbuf
21060492Seric {
21160492Seric 	int	rwb_len;	/* size of buffer */
21260492Seric 	char	*rwb_buf;	/* ptr to buffer */
21360492Seric };
21460492Seric 
21560492Seric struct rwbuf	RwBufs[2];	/* buffers for rewriting output */
21660492Seric 
21760089Seric char *
21860089Seric map_rewrite(map, s, slen, av)
21960089Seric 	register MAP *map;
22060089Seric 	register char *s;
22160089Seric 	int slen;
22260089Seric 	char **av;
22360089Seric {
22460089Seric 	register char *bp;
22560089Seric 	register char c;
22660089Seric 	char **avp;
22760089Seric 	register char *ap;
22860492Seric 	register struct rwbuf *rwb;
22960089Seric 	int i;
23060089Seric 	int len;
23160089Seric 
23260537Seric 	if (tTd(39, 1))
23360089Seric 	{
23460256Seric 		printf("map_rewrite(%.*s), av =", slen, s);
23560256Seric 		if (av == NULL)
23660256Seric 			printf(" (nullv)");
23760256Seric 		else
23860256Seric 		{
23960256Seric 			for (avp = av; *avp != NULL; avp++)
24060256Seric 				printf("\n\t%s", *avp);
24160256Seric 		}
24260256Seric 		printf("\n");
24360089Seric 	}
24460089Seric 
24560492Seric 	rwb = RwBufs;
24660492Seric 	if (av == NULL)
24760492Seric 		rwb++;
24860492Seric 
24960089Seric 	/* count expected size of output (can safely overestimate) */
25060089Seric 	i = len = slen;
25160089Seric 	if (av != NULL)
25260089Seric 	{
25360089Seric 		bp = s;
25460089Seric 		for (i = slen; --i >= 0 && (c = *bp++) != 0; )
25560089Seric 		{
25660089Seric 			if (c != '%')
25760089Seric 				continue;
25860089Seric 			if (--i < 0)
25960089Seric 				break;
26060089Seric 			c = *bp++;
26160089Seric 			if (!(isascii(c) && isdigit(c)))
26260089Seric 				continue;
26363937Seric 			for (avp = av; --c >= '0' && *avp != NULL; avp++)
26460089Seric 				continue;
26560089Seric 			if (*avp == NULL)
26660089Seric 				continue;
26760089Seric 			len += strlen(*avp);
26860089Seric 		}
26960089Seric 	}
27060089Seric 	if (map->map_app != NULL)
27160089Seric 		len += strlen(map->map_app);
27260492Seric 	if (rwb->rwb_len < ++len)
27360089Seric 	{
27460089Seric 		/* need to malloc additional space */
27560492Seric 		rwb->rwb_len = len;
27660492Seric 		if (rwb->rwb_buf != NULL)
27760492Seric 			free(rwb->rwb_buf);
27860492Seric 		rwb->rwb_buf = xalloc(rwb->rwb_len);
27960089Seric 	}
28060089Seric 
28160492Seric 	bp = rwb->rwb_buf;
28260089Seric 	if (av == NULL)
28360089Seric 	{
28460089Seric 		bcopy(s, bp, slen);
28560089Seric 		bp += slen;
28660089Seric 	}
28760089Seric 	else
28860089Seric 	{
28960089Seric 		while (--slen >= 0 && (c = *s++) != '\0')
29060089Seric 		{
29160089Seric 			if (c != '%')
29260089Seric 			{
29360089Seric   pushc:
29460089Seric 				*bp++ = c;
29560089Seric 				continue;
29660089Seric 			}
29760089Seric 			if (--slen < 0 || (c = *s++) == '\0')
29860089Seric 				c = '%';
29960089Seric 			if (c == '%')
30060089Seric 				goto pushc;
30160089Seric 			if (!(isascii(c) && isdigit(c)))
30260089Seric 			{
30360089Seric 				*bp++ = '%';
30460089Seric 				goto pushc;
30560089Seric 			}
30663937Seric 			for (avp = av; --c >= '0' && *avp != NULL; avp++)
30760089Seric 				continue;
30860089Seric 			if (*avp == NULL)
30960089Seric 				continue;
31060089Seric 
31160089Seric 			/* transliterate argument into output string */
31260089Seric 			for (ap = *avp; (c = *ap++) != '\0'; )
31360089Seric 				*bp++ = c;
31460089Seric 		}
31560089Seric 	}
31660089Seric 	if (map->map_app != NULL)
31760089Seric 		strcpy(bp, map->map_app);
31860089Seric 	else
31960089Seric 		*bp = '\0';
32060537Seric 	if (tTd(39, 1))
32160492Seric 		printf("map_rewrite => %s\n", rwb->rwb_buf);
32260492Seric 	return rwb->rwb_buf;
32360089Seric }
32460089Seric /*
32560537Seric **  INITMAPS -- initialize for aliasing
32660537Seric **
32760537Seric **	Parameters:
32860537Seric **		rebuild -- if TRUE, this rebuilds the cached versions.
32960537Seric **		e -- current envelope.
33060537Seric **
33160537Seric **	Returns:
33260537Seric **		none.
33360537Seric **
33460537Seric **	Side Effects:
33560537Seric **		initializes aliases:
33660537Seric **		if NDBM:  opens the database.
33760537Seric **		if ~NDBM: reads the aliases into the symbol table.
33860537Seric */
33960537Seric 
34060537Seric initmaps(rebuild, e)
34160537Seric 	bool rebuild;
34260537Seric 	register ENVELOPE *e;
34360537Seric {
34460537Seric 	extern void map_init();
34560537Seric 
34664671Seric #ifdef XDEBUG
34764671Seric 	checkfd012("entering initmaps");
34864671Seric #endif
34960537Seric 	CurEnv = e;
35065085Seric 	if (rebuild)
35165085Seric 	{
35265085Seric 		stabapply(map_init, 1);
35365085Seric 		stabapply(map_init, 2);
35465085Seric 	}
35565085Seric 	else
35665085Seric 	{
35765085Seric 		stabapply(map_init, 0);
35865085Seric 	}
35964671Seric #ifdef XDEBUG
36064671Seric 	checkfd012("exiting initmaps");
36164671Seric #endif
36260537Seric }
36360537Seric 
36460537Seric void
36560537Seric map_init(s, rebuild)
36660537Seric 	register STAB *s;
36760537Seric 	int rebuild;
36860537Seric {
36960537Seric 	register MAP *map;
37060537Seric 
37160537Seric 	/* has to be a map */
37260537Seric 	if (s->s_type != ST_MAP)
37360537Seric 		return;
37460537Seric 
37560537Seric 	map = &s->s_map;
37660537Seric 	if (!bitset(MF_VALID, map->map_mflags))
37760537Seric 		return;
37860537Seric 
37960537Seric 	if (tTd(38, 2))
38067726Seric 		printf("map_init(%s:%s, %s, %d)\n",
38164690Seric 			map->map_class->map_cname == NULL ? "NULL" :
38264690Seric 				map->map_class->map_cname,
38367726Seric 			map->map_mname == NULL ? "NULL" : map->map_mname,
38465085Seric 			map->map_file == NULL ? "NULL" : map->map_file,
38565085Seric 			rebuild);
38660537Seric 
38765085Seric 	if (rebuild == (bitset(MF_ALIAS, map->map_mflags) &&
38865085Seric 		    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2))
38965085Seric 	{
39065085Seric 		if (tTd(38, 3))
39165085Seric 			printf("\twrong pass\n");
39265085Seric 		return;
39365085Seric 	}
39465085Seric 
39560537Seric 	/* if already open, close it (for nested open) */
39660537Seric 	if (bitset(MF_OPEN, map->map_mflags))
39760537Seric 	{
39860537Seric 		map->map_class->map_close(map);
39960537Seric 		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
40060537Seric 	}
40160537Seric 
40265085Seric 	if (rebuild == 2)
40360537Seric 	{
40465085Seric 		rebuildaliases(map, FALSE);
40560537Seric 	}
40660537Seric 	else
40760537Seric 	{
40860537Seric 		if (map->map_class->map_open(map, O_RDONLY))
40960537Seric 		{
41060537Seric 			if (tTd(38, 4))
41167726Seric 				printf("\t%s:%s %s: valid\n",
41264690Seric 					map->map_class->map_cname == NULL ? "NULL" :
41364690Seric 						map->map_class->map_cname,
41467726Seric 					map->map_mname == NULL ? "NULL" :
41567726Seric 						map->map_mname,
41664690Seric 					map->map_file == NULL ? "NULL" :
41764690Seric 						map->map_file);
41860537Seric 			map->map_mflags |= MF_OPEN;
41960537Seric 		}
42060537Seric 		else if (tTd(38, 4))
42167726Seric 			printf("\t%s:%s %s: invalid: %s\n",
42264690Seric 				map->map_class->map_cname == NULL ? "NULL" :
42364690Seric 					map->map_class->map_cname,
42467726Seric 				map->map_mname == NULL ? "NULL" :
42567726Seric 					map->map_mname,
42664690Seric 				map->map_file == NULL ? "NULL" :
42764690Seric 					map->map_file,
42860537Seric 				errstring(errno));
42960537Seric 	}
43060537Seric }
43160537Seric /*
43260089Seric **  NDBM modules
43360089Seric */
43460089Seric 
43560089Seric #ifdef NDBM
43660089Seric 
43760089Seric /*
43860089Seric **  DBM_MAP_OPEN -- DBM-style map open
43960089Seric */
44060089Seric 
44160089Seric bool
44260089Seric ndbm_map_open(map, mode)
44360089Seric 	MAP *map;
44460089Seric 	int mode;
44560089Seric {
44664284Seric 	register DBM *dbm;
44764284Seric 	struct stat st;
44860089Seric 
44960537Seric 	if (tTd(38, 2))
45067726Seric 		printf("ndbm_map_open(%s, %s, %d)\n",
45167726Seric 			map->map_mname, map->map_file, mode);
45260089Seric 
45360207Seric 	if (mode == O_RDWR)
45460207Seric 		mode |= O_CREAT|O_TRUNC;
45560207Seric 
45660089Seric 	/* open the database */
45760089Seric 	dbm = dbm_open(map->map_file, mode, DBMMODE);
45856822Seric 	if (dbm == NULL)
45956822Seric 	{
46064718Seric #ifdef MAYBENEXTRELEASE
46164718Seric 		if (aliaswait(map, ".pag", FALSE))
46264718Seric 			return TRUE;
46364718Seric #endif
46460207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
46556836Seric 			syserr("Cannot open DBM database %s", map->map_file);
46656822Seric 		return FALSE;
46756822Seric 	}
46860089Seric 	map->map_db1 = (void *) dbm;
46964964Seric 	if (mode == O_RDONLY)
47064964Seric 	{
47164964Seric 		if (bitset(MF_ALIAS, map->map_mflags) &&
47264964Seric 		    !aliaswait(map, ".pag", TRUE))
47364718Seric 			return FALSE;
47464964Seric 	}
47564964Seric 	else
47664964Seric 	{
47764964Seric 		int fd;
47864964Seric 
47964964Seric 		/* exclusive lock for duration of rebuild */
48064964Seric 		fd = dbm_dirfno((DBM *) map->map_db1);
48164964Seric 		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) &&
48264964Seric 		    lockfile(fd, map->map_file, ".dir", LOCK_EX))
48364964Seric 			map->map_mflags |= MF_LOCKED;
48464964Seric 	}
48564718Seric 	if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0)
48664284Seric 		map->map_mtime = st.st_mtime;
48756822Seric 	return TRUE;
48856822Seric }
48960089Seric 
49060089Seric 
49160089Seric /*
49256822Seric **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
49356822Seric */
49456822Seric 
49556822Seric char *
49660089Seric ndbm_map_lookup(map, name, av, statp)
49756822Seric 	MAP *map;
49860089Seric 	char *name;
49956822Seric 	char **av;
50059084Seric 	int *statp;
50156822Seric {
50256822Seric 	datum key, val;
50364373Seric 	int fd;
50460089Seric 	char keybuf[MAXNAME + 1];
50556822Seric 
50660537Seric 	if (tTd(38, 20))
50767726Seric 		printf("ndbm_map_lookup(%s, %s)\n",
50867726Seric 			map->map_mname, name);
50960089Seric 
51060089Seric 	key.dptr = name;
51160089Seric 	key.dsize = strlen(name);
51260207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
51357014Seric 	{
51460089Seric 		if (key.dsize > sizeof keybuf - 1)
51560089Seric 			key.dsize = sizeof keybuf - 1;
51660089Seric 		bcopy(key.dptr, keybuf, key.dsize + 1);
51760089Seric 		makelower(keybuf);
51860089Seric 		key.dptr = keybuf;
51957014Seric 	}
52064373Seric 	fd = dbm_dirfno((DBM *) map->map_db1);
52164388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
52264373Seric 		(void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
52363753Seric 	val.dptr = NULL;
52463753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
52563753Seric 	{
52663753Seric 		val = dbm_fetch((DBM *) map->map_db1, key);
52763753Seric 		if (val.dptr != NULL)
52863753Seric 			map->map_mflags &= ~MF_TRY1NULL;
52963753Seric 	}
53063753Seric 	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
53163753Seric 	{
53256822Seric 		key.dsize++;
53363753Seric 		val = dbm_fetch((DBM *) map->map_db1, key);
53463753Seric 		if (val.dptr != NULL)
53563753Seric 			map->map_mflags &= ~MF_TRY0NULL;
53663753Seric 	}
53764388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
53864373Seric 		(void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
53956822Seric 	if (val.dptr == NULL)
54056822Seric 		return NULL;
54160207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
54263753Seric 		return map_rewrite(map, name, strlen(name), NULL);
54363753Seric 	else
54463753Seric 		return map_rewrite(map, val.dptr, val.dsize, av);
54556822Seric }
54656822Seric 
54756822Seric 
54856822Seric /*
54960089Seric **  DBM_MAP_STORE -- store a datum in the database
55056822Seric */
55156822Seric 
55260089Seric void
55360089Seric ndbm_map_store(map, lhs, rhs)
55460089Seric 	register MAP *map;
55560089Seric 	char *lhs;
55660089Seric 	char *rhs;
55760089Seric {
55860089Seric 	datum key;
55960089Seric 	datum data;
56060089Seric 	int stat;
56160089Seric 
56260537Seric 	if (tTd(38, 12))
56367726Seric 		printf("ndbm_map_store(%s, %s, %s)\n",
56467726Seric 			map->map_mname, lhs, rhs);
56560089Seric 
56660089Seric 	key.dsize = strlen(lhs);
56760089Seric 	key.dptr = lhs;
56860089Seric 
56960089Seric 	data.dsize = strlen(rhs);
57060089Seric 	data.dptr = rhs;
57160089Seric 
57260207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
57360089Seric 	{
57460089Seric 		key.dsize++;
57560089Seric 		data.dsize++;
57660089Seric 	}
57760089Seric 
57860089Seric 	stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
57960089Seric 	if (stat > 0)
58060089Seric 	{
58160089Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
58260089Seric 		stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
58360089Seric 	}
58460089Seric 	if (stat != 0)
58560089Seric 		syserr("readaliases: dbm put (%s)", lhs);
58660089Seric }
58760089Seric 
58860089Seric 
58960089Seric /*
59060207Seric **  NDBM_MAP_CLOSE -- close the database
59160089Seric */
59260089Seric 
59360089Seric void
59460089Seric ndbm_map_close(map)
59560089Seric 	register MAP  *map;
59660089Seric {
59766773Seric 	if (tTd(38, 9))
59867726Seric 		printf("ndbm_map_close(%s, %s, %x)\n",
59967726Seric 			map->map_mname, map->map_file, map->map_mflags);
60066773Seric 
60160207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
60260089Seric 	{
60364250Seric #ifdef NIS
60464075Seric 		bool inclnull;
60560089Seric 		char buf[200];
60660089Seric 
60764075Seric 		inclnull = bitset(MF_INCLNULL, map->map_mflags);
60864075Seric 		map->map_mflags &= ~MF_INCLNULL;
60964075Seric 
61060089Seric 		(void) sprintf(buf, "%010ld", curtime());
61160089Seric 		ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
61260089Seric 
61364941Seric 		(void) gethostname(buf, sizeof buf);
61460089Seric 		ndbm_map_store(map, "YP_MASTER_NAME", buf);
61564075Seric 
61664075Seric 		if (inclnull)
61764075Seric 			map->map_mflags |= MF_INCLNULL;
61860089Seric #endif
61960089Seric 
62060089Seric 		/* write out the distinguished alias */
62160089Seric 		ndbm_map_store(map, "@", "@");
62260089Seric 	}
62360089Seric 	dbm_close((DBM *) map->map_db1);
62460089Seric }
62560089Seric 
62660089Seric #endif
62760089Seric /*
62860582Seric **  NEWDB (Hash and BTree) Modules
62960089Seric */
63060089Seric 
63160089Seric #ifdef NEWDB
63260089Seric 
63360089Seric /*
63460582Seric **  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
63560582Seric **
63660582Seric **	These do rather bizarre locking.  If you can lock on open,
63760582Seric **	do that to avoid the condition of opening a database that
63860582Seric **	is being rebuilt.  If you don't, we'll try to fake it, but
63960582Seric **	there will be a race condition.  If opening for read-only,
64060582Seric **	we immediately release the lock to avoid freezing things up.
64160582Seric **	We really ought to hold the lock, but guarantee that we won't
64260582Seric **	be pokey about it.  That's hard to do.
64360089Seric */
64460089Seric 
64556822Seric bool
64660089Seric bt_map_open(map, mode)
64756822Seric 	MAP *map;
64860089Seric 	int mode;
64956822Seric {
65056822Seric 	DB *db;
65160228Seric 	int i;
65260582Seric 	int omode;
65364373Seric 	int fd;
65464284Seric 	struct stat st;
65560089Seric 	char buf[MAXNAME];
65656822Seric 
65760537Seric 	if (tTd(38, 2))
65867726Seric 		printf("bt_map_open(%s, %s, %d)\n",
65967726Seric 			map->map_mname, map->map_file, mode);
66060089Seric 
66160582Seric 	omode = mode;
66260582Seric 	if (omode == O_RDWR)
66360582Seric 	{
66460582Seric 		omode |= O_CREAT|O_TRUNC;
66565830Seric #if defined(O_EXLOCK) && HASFLOCK
66660582Seric 		omode |= O_EXLOCK;
66766843Seric # if !OLD_NEWDB
66860582Seric 	}
66960582Seric 	else
67060582Seric 	{
67160582Seric 		omode |= O_SHLOCK;
67260582Seric # endif
67360582Seric #endif
67460582Seric 	}
67560207Seric 
67660228Seric 	(void) strcpy(buf, map->map_file);
67760228Seric 	i = strlen(buf);
67860228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
67960228Seric 		(void) strcat(buf, ".db");
68060582Seric 	db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
68156822Seric 	if (db == NULL)
68256822Seric 	{
68364718Seric #ifdef MAYBENEXTRELEASE
68464718Seric 		if (aliaswait(map, ".db", FALSE))
68564718Seric 			return TRUE;
68664718Seric #endif
68760207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
68856836Seric 			syserr("Cannot open BTREE database %s", map->map_file);
68956822Seric 		return FALSE;
69056822Seric 	}
69167173Seric #if !OLD_NEWDB
69264373Seric 	fd = db->fd(db);
69367187Seric # if HASFLOCK
69467187Seric #  if !defined(O_EXLOCK)
69564373Seric 	if (mode == O_RDWR && fd >= 0)
69664388Seric 	{
69764388Seric 		if (lockfile(fd, map->map_file, ".db", LOCK_EX))
69864388Seric 			map->map_mflags |= MF_LOCKED;
69964388Seric 	}
70067187Seric #  else
70164373Seric 	if (mode == O_RDONLY && fd >= 0)
70264373Seric 		(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
70364388Seric 	else
70464388Seric 		map->map_mflags |= MF_LOCKED;
70567187Seric #  endif
70660582Seric # endif
70760582Seric #endif
70860585Seric 
70960585Seric 	/* try to make sure that at least the database header is on disk */
71060585Seric 	if (mode == O_RDWR)
71166843Seric #if OLD_NEWDB
71264373Seric 		(void) db->sync(db);
71364373Seric #else
71460585Seric 		(void) db->sync(db, 0);
71560585Seric 
71664373Seric 	if (fd >= 0 && fstat(fd, &st) >= 0)
71764284Seric 		map->map_mtime = st.st_mtime;
71864284Seric #endif
71964284Seric 
72060089Seric 	map->map_db2 = (void *) db;
72160207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
72264718Seric 		if (!aliaswait(map, ".db", TRUE))
72364718Seric 			return FALSE;
72456822Seric 	return TRUE;
72556822Seric }
72656822Seric 
72756822Seric 
72856822Seric /*
72956822Seric **  HASH_MAP_INIT -- HASH-style map initialization
73056822Seric */
73156822Seric 
73256822Seric bool
73360089Seric hash_map_open(map, mode)
73456822Seric 	MAP *map;
73560089Seric 	int mode;
73656822Seric {
73756822Seric 	DB *db;
73860228Seric 	int i;
73960582Seric 	int omode;
74064373Seric 	int fd;
74164284Seric 	struct stat st;
74260089Seric 	char buf[MAXNAME];
74356822Seric 
74460537Seric 	if (tTd(38, 2))
74567726Seric 		printf("hash_map_open(%s, %s, %d)\n",
74667726Seric 			map->map_mname, map->map_file, mode);
74760089Seric 
74860582Seric 	omode = mode;
74960582Seric 	if (omode == O_RDWR)
75060582Seric 	{
75160582Seric 		omode |= O_CREAT|O_TRUNC;
75265830Seric #if defined(O_EXLOCK) && HASFLOCK
75360582Seric 		omode |= O_EXLOCK;
75466843Seric # if !OLD_NEWDB
75560582Seric 	}
75660582Seric 	else
75760582Seric 	{
75860582Seric 		omode |= O_SHLOCK;
75960582Seric # endif
76060582Seric #endif
76160582Seric 	}
76260207Seric 
76360228Seric 	(void) strcpy(buf, map->map_file);
76460228Seric 	i = strlen(buf);
76560228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
76660228Seric 		(void) strcat(buf, ".db");
76760582Seric 	db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
76856822Seric 	if (db == NULL)
76956822Seric 	{
77064718Seric #ifdef MAYBENEXTRELEASE
77164718Seric 		if (aliaswait(map, ".db", FALSE))
77264718Seric 			return TRUE;
77364718Seric #endif
77460207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
77556836Seric 			syserr("Cannot open HASH database %s", map->map_file);
77656822Seric 		return FALSE;
77756822Seric 	}
77867173Seric #if !OLD_NEWDB
77964373Seric 	fd = db->fd(db);
78067187Seric # if HASFLOCK
78167187Seric #  if !defined(O_EXLOCK)
78264373Seric 	if (mode == O_RDWR && fd >= 0)
78364388Seric 	{
78464388Seric 		if (lockfile(fd, map->map_file, ".db", LOCK_EX))
78564388Seric 			map->map_mflags |= MF_LOCKED;
78664388Seric 	}
78767187Seric #  else
78864373Seric 	if (mode == O_RDONLY && fd >= 0)
78964373Seric 		(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
79064388Seric 	else
79164388Seric 		map->map_mflags |= MF_LOCKED;
79267187Seric #  endif
79360582Seric # endif
79460582Seric #endif
79560585Seric 
79660585Seric 	/* try to make sure that at least the database header is on disk */
79760585Seric 	if (mode == O_RDWR)
79866843Seric #if OLD_NEWDB
79964373Seric 		(void) db->sync(db);
80064373Seric #else
80160585Seric 		(void) db->sync(db, 0);
80260585Seric 
80364373Seric 	if (fd >= 0 && fstat(fd, &st) >= 0)
80464284Seric 		map->map_mtime = st.st_mtime;
80564284Seric #endif
80664284Seric 
80760089Seric 	map->map_db2 = (void *) db;
80860207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
80964718Seric 		if (!aliaswait(map, ".db", TRUE))
81064718Seric 			return FALSE;
81156822Seric 	return TRUE;
81256822Seric }
81356822Seric 
81456822Seric 
81556822Seric /*
81656822Seric **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
81756822Seric */
81856822Seric 
81956822Seric char *
82060089Seric db_map_lookup(map, name, av, statp)
82156822Seric 	MAP *map;
82260089Seric 	char *name;
82356822Seric 	char **av;
82459084Seric 	int *statp;
82556822Seric {
82656822Seric 	DBT key, val;
82760422Seric 	register DB *db = (DB *) map->map_db2;
82860422Seric 	int st;
82960422Seric 	int saveerrno;
83064373Seric 	int fd;
83160089Seric 	char keybuf[MAXNAME + 1];
83256822Seric 
83360537Seric 	if (tTd(38, 20))
83467726Seric 		printf("db_map_lookup(%s, %s)\n",
83567726Seric 			map->map_mname, name);
83660089Seric 
83760089Seric 	key.size = strlen(name);
83860089Seric 	if (key.size > sizeof keybuf - 1)
83960089Seric 		key.size = sizeof keybuf - 1;
84060089Seric 	key.data = keybuf;
84160089Seric 	bcopy(name, keybuf, key.size + 1);
84260207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
84360089Seric 		makelower(keybuf);
84466843Seric #if !OLD_NEWDB
84564388Seric 	fd = db->fd(db);
84664388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
84764388Seric 		(void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH);
84860422Seric #endif
84963753Seric 	st = 1;
85063753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
85163753Seric 	{
85263753Seric 		st = db->get(db, &key, &val, 0);
85363753Seric 		if (st == 0)
85463753Seric 			map->map_mflags &= ~MF_TRY1NULL;
85563753Seric 	}
85663753Seric 	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
85763753Seric 	{
85863753Seric 		key.size++;
85963753Seric 		st = db->get(db, &key, &val, 0);
86063753Seric 		if (st == 0)
86163753Seric 			map->map_mflags &= ~MF_TRY0NULL;
86263753Seric 	}
86360422Seric 	saveerrno = errno;
86466843Seric #if !OLD_NEWDB
86564388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
86664373Seric 		(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
86760422Seric #endif
86860422Seric 	if (st != 0)
86960422Seric 	{
87060422Seric 		errno = saveerrno;
87160422Seric 		if (st < 0)
87260422Seric 			syserr("db_map_lookup: get (%s)", name);
87356822Seric 		return NULL;
87460422Seric 	}
87560207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
87663753Seric 		return map_rewrite(map, name, strlen(name), NULL);
87763753Seric 	else
87863753Seric 		return map_rewrite(map, val.data, val.size, av);
87956822Seric }
88056822Seric 
88160089Seric 
88260089Seric /*
88360089Seric **  DB_MAP_STORE -- store a datum in the NEWDB database
88456822Seric */
88556822Seric 
88660089Seric void
88760089Seric db_map_store(map, lhs, rhs)
88860089Seric 	register MAP *map;
88960089Seric 	char *lhs;
89060089Seric 	char *rhs;
89156822Seric {
89260089Seric 	int stat;
89360089Seric 	DBT key;
89460089Seric 	DBT data;
89560089Seric 	register DB *db = map->map_db2;
89656822Seric 
89760537Seric 	if (tTd(38, 20))
89867726Seric 		printf("db_map_store(%s, %s, %s)\n",
89967726Seric 			map->map_mname, lhs, rhs);
90060089Seric 
90160089Seric 	key.size = strlen(lhs);
90260089Seric 	key.data = lhs;
90360089Seric 
90460089Seric 	data.size = strlen(rhs);
90560089Seric 	data.data = rhs;
90660089Seric 
90760207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
90856822Seric 	{
90960089Seric 		key.size++;
91060089Seric 		data.size++;
91160089Seric 	}
91256836Seric 
91360089Seric 	stat = db->put(db, &key, &data, R_NOOVERWRITE);
91460089Seric 	if (stat > 0)
91560089Seric 	{
91660089Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
91760089Seric 		stat = db->put(db, &key, &data, 0);
91860089Seric 	}
91960089Seric 	if (stat != 0)
92060089Seric 		syserr("readaliases: db put (%s)", lhs);
92160089Seric }
92256836Seric 
92356847Seric 
92460089Seric /*
92560089Seric **  DB_MAP_CLOSE -- add distinguished entries and close the database
92660089Seric */
92760089Seric 
92860089Seric void
92960089Seric db_map_close(map)
93060089Seric 	MAP *map;
93160089Seric {
93260089Seric 	register DB *db = map->map_db2;
93360089Seric 
93460537Seric 	if (tTd(38, 9))
93567726Seric 		printf("db_map_close(%s, %s, %x)\n",
93667726Seric 			map->map_mname, map->map_file, map->map_mflags);
93760089Seric 
93860207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
93958804Seric 	{
94060089Seric 		/* write out the distinguished alias */
94160089Seric 		db_map_store(map, "@", "@");
94258804Seric 	}
94358963Seric 
94460089Seric 	if (db->close(db) != 0)
94560089Seric 		syserr("readaliases: db close failure");
94656822Seric }
94757208Seric 
94860089Seric #endif
94960089Seric /*
95060089Seric **  NIS Modules
95160089Seric */
95260089Seric 
95360089Seric # ifdef NIS
95460089Seric 
95564369Seric # ifndef YPERR_BUSY
95664369Seric #  define YPERR_BUSY	16
95764369Seric # endif
95864369Seric 
95957208Seric /*
96060089Seric **  NIS_MAP_OPEN -- open DBM map
96157208Seric */
96257208Seric 
96357208Seric bool
96460089Seric nis_map_open(map, mode)
96557208Seric 	MAP *map;
96660089Seric 	int mode;
96757208Seric {
96857216Seric 	int yperr;
96960215Seric 	register char *p;
97060215Seric 	auto char *vp;
97160215Seric 	auto int vsize;
97257216Seric 	char *master;
97357216Seric 
97460537Seric 	if (tTd(38, 2))
97567726Seric 		printf("nis_map_open(%s, %s)\n",
97667726Seric 			map->map_mname, map->map_file);
97760089Seric 
97860207Seric 	if (mode != O_RDONLY)
97960207Seric 	{
98064650Seric 		/* issue a pseudo-error message */
98164650Seric #ifdef ENOSYS
98264650Seric 		errno = ENOSYS;
98364650Seric #else
98464650Seric # ifdef EFTYPE
98564650Seric 		errno = EFTYPE;
98664650Seric # else
98764650Seric 		errno = ENXIO;
98864650Seric # endif
98964650Seric #endif
99060207Seric 		return FALSE;
99160207Seric 	}
99260207Seric 
99360089Seric 	p = strchr(map->map_file, '@');
99460089Seric 	if (p != NULL)
99560089Seric 	{
99660089Seric 		*p++ = '\0';
99760089Seric 		if (*p != '\0')
99860089Seric 			map->map_domain = p;
99960089Seric 	}
100060215Seric 
100160089Seric 	if (*map->map_file == '\0')
100260089Seric 		map->map_file = "mail.aliases";
100360089Seric 
100466157Seric 	if (map->map_domain == NULL)
100566157Seric 	{
100666157Seric 		yperr = yp_get_default_domain(&map->map_domain);
100766157Seric 		if (yperr != 0)
100866157Seric 		{
100966744Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
101066744Seric 				syserr("NIS map %s specified, but NIS not running\n",
101166744Seric 					map->map_file);
101266157Seric 			return FALSE;
101366157Seric 		}
101466157Seric 	}
101566157Seric 
101660215Seric 	/* check to see if this map actually exists */
101760089Seric 	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
101860089Seric 			&vp, &vsize);
101960537Seric 	if (tTd(38, 10))
102060089Seric 		printf("nis_map_open: yp_match(%s, %s) => %s\n",
102160089Seric 			map->map_domain, map->map_file, yperr_string(yperr));
102260089Seric 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
102360089Seric 		return TRUE;
102460215Seric 
102560215Seric 	if (!bitset(MF_OPTIONAL, map->map_mflags))
102660215Seric 		syserr("Cannot bind to domain %s: %s", map->map_domain,
102760215Seric 			yperr_string(yperr));
102860215Seric 
102960089Seric 	return FALSE;
103060089Seric }
103160089Seric 
103260089Seric 
103360089Seric /*
103457208Seric **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
103557208Seric */
103657208Seric 
103757208Seric char *
103860089Seric nis_map_lookup(map, name, av, statp)
103957208Seric 	MAP *map;
104060089Seric 	char *name;
104157208Seric 	char **av;
104259084Seric 	int *statp;
104357208Seric {
104457208Seric 	char *vp;
104557642Seric 	auto int vsize;
104659274Seric 	int buflen;
104760215Seric 	int yperr;
104860089Seric 	char keybuf[MAXNAME + 1];
104957208Seric 
105060537Seric 	if (tTd(38, 20))
105167726Seric 		printf("nis_map_lookup(%s, %s)\n",
105267726Seric 			map->map_mname, name);
105360089Seric 
105460089Seric 	buflen = strlen(name);
105560089Seric 	if (buflen > sizeof keybuf - 1)
105660089Seric 		buflen = sizeof keybuf - 1;
105760089Seric 	bcopy(name, keybuf, buflen + 1);
105860207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
105960089Seric 		makelower(keybuf);
106063753Seric 	yperr = YPERR_KEY;
106163753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
106263753Seric 	{
106363753Seric 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
106463753Seric 			     &vp, &vsize);
106563753Seric 		if (yperr == 0)
106663753Seric 			map->map_mflags &= ~MF_TRY1NULL;
106763753Seric 	}
106863753Seric 	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
106963753Seric 	{
107059274Seric 		buflen++;
107163753Seric 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
107263753Seric 			     &vp, &vsize);
107363753Seric 		if (yperr == 0)
107463753Seric 			map->map_mflags &= ~MF_TRY0NULL;
107563753Seric 	}
107660089Seric 	if (yperr != 0)
107760089Seric 	{
107860089Seric 		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
107960215Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
108057208Seric 		return NULL;
108160089Seric 	}
108260207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
108363753Seric 		return map_rewrite(map, name, strlen(name), NULL);
108463753Seric 	else
108563753Seric 		return map_rewrite(map, vp, vsize, av);
108657208Seric }
108757208Seric 
108867726Seric #endif
108957208Seric /*
1090*67848Seric **  NISPLUS Modules
1091*67848Seric **
1092*67848Seric **	This code donated by Sun Microsystems.
1093*67848Seric */
1094*67848Seric 
1095*67848Seric #ifdef NISPLUS
1096*67848Seric 
1097*67848Seric #undef NIS /* symbol conflict in nis.h */
1098*67848Seric #include <rpcsvc/nis.h>
1099*67848Seric #include <rpcsvc/nislib.h>
1100*67848Seric 
1101*67848Seric #define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
1102*67848Seric #define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
1103*67848Seric #define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
1104*67848Seric #define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
1105*67848Seric 
1106*67848Seric /*
1107*67848Seric **  NISPLUS_MAP_OPEN -- open nisplus table
1108*67848Seric */
1109*67848Seric 
1110*67848Seric bool
1111*67848Seric nisplus_map_open(map, mode)
1112*67848Seric 	MAP *map;
1113*67848Seric 	int mode;
1114*67848Seric {
1115*67848Seric 	register char *p;
1116*67848Seric 	char qbuf[MAXLINE + NIS_MAXNAMELEN];
1117*67848Seric 	nis_result *res = NULL;
1118*67848Seric 	u_int objs_len;
1119*67848Seric 	nis_object *obj_ptr;
1120*67848Seric 	int retry_cnt, max_col, i;
1121*67848Seric 
1122*67848Seric 	if (tTd(38, 2))
1123*67848Seric 		printf("nisplus_map_open(%s, %s, %d)\n",
1124*67848Seric 			map->map_mname, map->map_file, mode);
1125*67848Seric 
1126*67848Seric 	if (mode != O_RDONLY)
1127*67848Seric 	{
1128*67848Seric 		errno = ENODEV;
1129*67848Seric 		return FALSE;
1130*67848Seric 	}
1131*67848Seric 
1132*67848Seric 	if (*map->map_file == '\0')
1133*67848Seric 		map->map_file = "mail_aliases.org_dir";
1134*67848Seric 
1135*67848Seric 	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
1136*67848Seric 	{
1137*67848Seric 		/* set default NISPLUS Domain to $m */
1138*67848Seric 		extern char *nisplus_default_domain();
1139*67848Seric 
1140*67848Seric 		map->map_domain = newstr(nisplus_default_domain());
1141*67848Seric 		if (tTd(38, 2))
1142*67848Seric 			printf("nisplus_map_open(%s): using domain %s\n",
1143*67848Seric 				 map->map_file, map->map_domain);
1144*67848Seric 	}
1145*67848Seric 	if (!PARTIAL_NAME(map->map_file))
1146*67848Seric 		map->map_domain = newstr("");
1147*67848Seric 
1148*67848Seric 	/* check to see if this map actually exists */
1149*67848Seric 	if (PARTIAL_NAME(map->map_file))
1150*67848Seric 		sprintf(qbuf, "%s.%s", map->map_file, map->map_domain);
1151*67848Seric 	else
1152*67848Seric 		strcpy(qbuf, map->map_file);
1153*67848Seric 
1154*67848Seric 	retry_cnt = 0;
1155*67848Seric 	while (res == NULL || res->status != NIS_SUCCESS)
1156*67848Seric 	{
1157*67848Seric 		res = nis_lookup(qbuf, FOLLOW_LINKS);
1158*67848Seric 		switch (res->status)
1159*67848Seric 		{
1160*67848Seric 		  case NIS_SUCCESS:
1161*67848Seric 		  case NIS_TRYAGAIN:
1162*67848Seric 		  case NIS_RPCERROR:
1163*67848Seric 		  case NIS_NAMEUNREACHABLE:
1164*67848Seric 			break;
1165*67848Seric 
1166*67848Seric 		  default:		/* all other nisplus errors */
1167*67848Seric #if 0
1168*67848Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
1169*67848Seric 				syserr("Cannot find table %s.%s: %s",
1170*67848Seric 					map->map_file, map->map_domain,
1171*67848Seric 					nis_sperrno(res->status));
1172*67848Seric #endif
1173*67848Seric 			errno = EBADR;
1174*67848Seric 			return FALSE;
1175*67848Seric 		}
1176*67848Seric 		sleep(2);		/* try not to overwhelm hosed server */
1177*67848Seric 		if (retry_cnt++ > 4)
1178*67848Seric 		{
1179*67848Seric 			errno = EBADR;
1180*67848Seric 			return FALSE;
1181*67848Seric 		}
1182*67848Seric 	}
1183*67848Seric 
1184*67848Seric 	if (NIS_RES_NUMOBJ(res) != 1 ||
1185*67848Seric 	    (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
1186*67848Seric 	{
1187*67848Seric 		if (tTd(38, 10))
1188*67848Seric 			printf("nisplus_map_open: %s is not a table\n", qbuf);
1189*67848Seric #if 0
1190*67848Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
1191*67848Seric 			syserr("%s.%s: %s is not a table",
1192*67848Seric 				map->map_file, map->map_domain,
1193*67848Seric 				nis_sperrno(res->status));
1194*67848Seric #endif
1195*67848Seric 		errno = EBADR;
1196*67848Seric 		return FALSE;
1197*67848Seric 	}
1198*67848Seric 	/* default key column is column 0 */
1199*67848Seric 	if (map->map_keycolnm == NULL)
1200*67848Seric 		map->map_keycolnm = newstr(COL_NAME(res,0));
1201*67848Seric 
1202*67848Seric 	max_col = COL_MAX(res);
1203*67848Seric 
1204*67848Seric 	/* verify the key column exist */
1205*67848Seric 	for (i=0; i< max_col; i++)
1206*67848Seric 	{
1207*67848Seric 		if (!strcmp(map->map_keycolnm, COL_NAME(res,i)))
1208*67848Seric 			break;
1209*67848Seric 	}
1210*67848Seric 	if (i == max_col)
1211*67848Seric 	{
1212*67848Seric 		if (tTd(38, 2))
1213*67848Seric 			printf("nisplus_map_open(%s): can not find key column %s\n",
1214*67848Seric 				map->map_file, map->map_keycolnm);
1215*67848Seric 		errno = EBADR;
1216*67848Seric 		return FALSE;
1217*67848Seric 	}
1218*67848Seric 
1219*67848Seric 	/* default value column is the last column */
1220*67848Seric 	if (map->map_valcolnm == NULL)
1221*67848Seric 	{
1222*67848Seric 		map->map_valcolno = max_col - 1;
1223*67848Seric 		return TRUE;
1224*67848Seric 	}
1225*67848Seric 
1226*67848Seric 	for (i=0; i< max_col; i++)
1227*67848Seric 	{
1228*67848Seric 		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
1229*67848Seric 		{
1230*67848Seric 			map->map_valcolno = i;
1231*67848Seric 			return TRUE;
1232*67848Seric 		}
1233*67848Seric 	}
1234*67848Seric 
1235*67848Seric 	if (tTd(38, 2))
1236*67848Seric 		printf("nisplus_map_open(%s): can not find column %s\n",
1237*67848Seric 			 map->map_file, map->map_keycolnm);
1238*67848Seric 	errno = EBADR;
1239*67848Seric 	return FALSE;
1240*67848Seric }
1241*67848Seric 
1242*67848Seric 
1243*67848Seric /*
1244*67848Seric **  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
1245*67848Seric */
1246*67848Seric 
1247*67848Seric char *
1248*67848Seric nisplus_map_lookup(map, name, av, statp)
1249*67848Seric 	MAP *map;
1250*67848Seric 	char *name;
1251*67848Seric 	char **av;
1252*67848Seric 	int *statp;
1253*67848Seric {
1254*67848Seric 	char *vp;
1255*67848Seric 	auto int vsize;
1256*67848Seric 	int buflen;
1257*67848Seric 	char search_key[MAXNAME + 1];
1258*67848Seric 	char qbuf[MAXLINE + NIS_MAXNAMELEN];
1259*67848Seric 	nis_result *result;
1260*67848Seric 
1261*67848Seric 	if (tTd(38, 20))
1262*67848Seric 		printf("nisplus_map_lookup(%s, %s)\n",
1263*67848Seric 			map->map_mname, name);
1264*67848Seric 
1265*67848Seric 	if (!bitset(MF_OPEN, map->map_mflags))
1266*67848Seric 	{
1267*67848Seric 		if (nisplus_map_open(map, O_RDONLY))
1268*67848Seric 			map->map_mflags |= MF_OPEN;
1269*67848Seric 		else
1270*67848Seric 		{
1271*67848Seric 			*statp = EX_UNAVAILABLE;
1272*67848Seric 			return NULL;
1273*67848Seric 		}
1274*67848Seric 	}
1275*67848Seric 
1276*67848Seric 	buflen = strlen(name);
1277*67848Seric 	if (buflen > sizeof search_key - 1)
1278*67848Seric 		buflen = sizeof search_key - 1;
1279*67848Seric 	bcopy(name, search_key, buflen + 1);
1280*67848Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
1281*67848Seric 		makelower(search_key);
1282*67848Seric 
1283*67848Seric 	/* construct the query */
1284*67848Seric 	if (PARTIAL_NAME(map->map_file))
1285*67848Seric 		sprintf(qbuf, "[%s=%s],%s.%s", map->map_keycolnm,
1286*67848Seric 			search_key, map->map_file, map->map_domain);
1287*67848Seric 	else
1288*67848Seric 		sprintf(qbuf, "[%s=%s],%s", map->map_keycolnm,
1289*67848Seric 			search_key, map->map_file);
1290*67848Seric 
1291*67848Seric 	if (tTd(38, 20))
1292*67848Seric 		printf("qbuf=%s\n", qbuf);
1293*67848Seric 	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
1294*67848Seric 	if (result->status == NIS_SUCCESS)
1295*67848Seric 	{
1296*67848Seric 		int count;
1297*67848Seric 		char *str;
1298*67848Seric 
1299*67848Seric 		if ((count = NIS_RES_NUMOBJ(result)) != 1)
1300*67848Seric 		{
1301*67848Seric 			if (LogLevel > 10)
1302*67848Seric 				syslog(LOG_WARNING,
1303*67848Seric 				  "%s:Lookup error, expected 1 entry, got (%d)",
1304*67848Seric 				    map->map_file, count);
1305*67848Seric 
1306*67848Seric 			/* ignore second entry */
1307*67848Seric 			if (tTd(38, 20))
1308*67848Seric 				printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
1309*67848Seric 					name, count);
1310*67848Seric 		}
1311*67848Seric 
1312*67848Seric 		vp = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
1313*67848Seric 		/* set the length of the result */
1314*67848Seric 		if (vp == NULL)
1315*67848Seric 			vp = "";
1316*67848Seric 		vsize = strlen(vp);
1317*67848Seric 		if (tTd(38, 20))
1318*67848Seric 			printf("nisplus_map_lookup(%s), found %s\n",
1319*67848Seric 				name, vp);
1320*67848Seric 		if (bitset(MF_MATCHONLY, map->map_mflags))
1321*67848Seric 			str = map_rewrite(map, name, strlen(name), NULL);
1322*67848Seric 		else
1323*67848Seric 			str = map_rewrite(map, vp, vsize, av);
1324*67848Seric 		nis_freeresult(result);
1325*67848Seric #ifdef MAP_EXIT_STAT
1326*67848Seric 		*statp = EX_OK;
1327*67848Seric #endif
1328*67848Seric 		return str;
1329*67848Seric 	}
1330*67848Seric 	else
1331*67848Seric 	{
1332*67848Seric #ifdef MAP_EXIT_STAT
1333*67848Seric 		if (result->status == NIS_NOTFOUND)
1334*67848Seric 			*statp = EX_NOTFOUND;
1335*67848Seric 		else if (result->status == NIS_TRYAGAIN)
1336*67848Seric 			*statp = EX_TEMPFAIL;
1337*67848Seric 		else
1338*67848Seric 		{
1339*67848Seric 			*statp = EX_UNAVAILABLE;
1340*67848Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
1341*67848Seric 		}
1342*67848Seric #else
1343*67848Seric 		if ((result->status != NIS_NOTFOUND) &&
1344*67848Seric 		    (result->status != NIS_TRYAGAIN))
1345*67848Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
1346*67848Seric #endif
1347*67848Seric 	}
1348*67848Seric 	if (tTd(38, 20))
1349*67848Seric 		printf("nisplus_map_lookup(%s), failed\n", name);
1350*67848Seric 	nis_freeresult(result);
1351*67848Seric 	return NULL;
1352*67848Seric }
1353*67848Seric 
1354*67848Seric 
1355*67848Seric char *
1356*67848Seric nisplus_default_domain()
1357*67848Seric {
1358*67848Seric 	static char default_domain[MAXNAME] = "";
1359*67848Seric 	nis_result *res = NULL;
1360*67848Seric 	char *p;
1361*67848Seric 
1362*67848Seric 	if (default_domain[0] != '\0')
1363*67848Seric 		return(default_domain);
1364*67848Seric 
1365*67848Seric 	if (VendorCode == VENDOR_SUN && ConfigLevel < 2)
1366*67848Seric 	{
1367*67848Seric 		/* for old config, user nis+ local directory        */
1368*67848Seric 		/* have to be backward compatible with bugs too :-( */
1369*67848Seric 		p = nis_local_directory();
1370*67848Seric 		strcpy(default_domain, p);
1371*67848Seric 		return default_domain;
1372*67848Seric 	}
1373*67848Seric 
1374*67848Seric 	if ((p = macvalue('m', CurEnv)) == NULL)
1375*67848Seric 	{
1376*67848Seric 		p = nis_local_directory();
1377*67848Seric 		strcpy(default_domain, p);
1378*67848Seric 		return default_domain;
1379*67848Seric 	}
1380*67848Seric 
1381*67848Seric 	strcpy(default_domain, p);
1382*67848Seric 	if (PARTIAL_NAME(default_domain))
1383*67848Seric 		strcat(default_domain, ".");
1384*67848Seric 
1385*67848Seric 	res = nis_lookup(default_domain, FOLLOW_LINKS);
1386*67848Seric 	if (res->status == NIS_NOTFOUND)
1387*67848Seric 	{
1388*67848Seric 		p = nis_local_directory();
1389*67848Seric 		strcpy(default_domain, p);
1390*67848Seric 	}
1391*67848Seric 	return(default_domain);
1392*67848Seric }
1393*67848Seric 
1394*67848Seric #endif /* NISPLUS */
1395*67848Seric /*
139667832Seric **  HESIOD Modules
139767832Seric **
139867832Seric **	Only works for aliases (for now).
139967832Seric */
140067832Seric 
140167832Seric #ifdef HESIOD
140267832Seric 
140367832Seric char *
140467832Seric hes_map_lookup(map, name, av, statp)
140567832Seric         MAP *map;
140667832Seric         char *name;
140767832Seric         char **av;
140867832Seric         int *statp;
140967832Seric {
141067832Seric 	struct hes_postoffice *pobox;
141167832Seric 	char keybuf[MAXNAME + 1];
141267832Seric 
141367832Seric 	if (tTd(38, 20))
141467832Seric 		printf("hes_map_lookup(%s)\n", name);
141567832Seric 
141667832Seric 	pobox = hes_getmailhost(name);
141767832Seric 	if (pobox == NULL)
141867832Seric 		return NULL;
141967832Seric 
142067832Seric 	/* We only know how to deal with the SMTP types right now */
142167832Seric 	if (strcmp(pobox->po_type, "SMTP") != 0 &&
142267832Seric 	    strcmp(pobox->po_type, "ESMTP") != 0)
142367832Seric 		return NULL;
142467832Seric 
142567832Seric 	/* if just checking for a match, we are done */
142667832Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
142767832Seric 		return map_rewrite(map, name, strlen(name), NULL);
142867832Seric 
142967832Seric 	/* Do the rewriting with new values */
143067832Seric 	if (strlen(pobox->po_name) + strlen(pobox->po_host) + 1 > sizeof keybuf)
1431*67848Seric 	{
1432*67848Seric 		*statp = EX_DATAERR;
143367832Seric 		return NULL;
1434*67848Seric 	}
143567832Seric 	(void) sprintf(keybuf, "%s@%s", pobox->po_name, pobox->po_host);
143667832Seric 	return map_rewrite(map, keybuf, strlen(keybuf), av);
143767832Seric }
143867832Seric 
143967832Seric #endif
144067832Seric /*
144167842Seric **  NeXT NETINFO Modules
144267842Seric */
144367842Seric 
144467842Seric #ifdef NETINFO
144567842Seric 
144667842Seric #define NETINFO_DEFAULT_DIR		"/aliases"
144767842Seric #define NETINFO_DEFAULT_PROPERTY	"members"
144867842Seric 
144967842Seric 
145067842Seric /*
145167842Seric **  NI_MAP_OPEN -- open NetInfo Aliases
145267842Seric */
145367842Seric 
1454*67848Seric bool
145567842Seric ni_map_open(map, mode)
145667842Seric 	MAP *map;
145767842Seric 	int mode;
145867842Seric {
145967842Seric 	char *p;
146067842Seric 
146167842Seric 	if (tTd(38, 20))
146267842Seric 		printf("ni_map_open: %s\n", map->map_file);
146367842Seric 
146467842Seric 	p = strchr(map->map_file, '@');
146567842Seric 	if (p != NULL)
146667842Seric 	{
146767842Seric 		*p++ = '\0';
146867842Seric 		if (*p != '\0')
146967842Seric 			map->map_domain = p;
147067842Seric 	}
147167842Seric 	if (*map->map_file == '\0')
147267842Seric 		map->map_file = NETINFO_DEFAULT_DIR;
147367842Seric 
147467842Seric 	if (map->map_domain == NULL)
147567842Seric 		map->map_domain = NETINFO_DEFAULT_PROPERTY;
147667842Seric 
147767842Seric 	if (map->map_sepchar == '\0' && bitset(MF_ALIAS, map->map_mflags))
147867842Seric 		map->map_sepchar = ',';
147967842Seric 
148067842Seric 	return TRUE;
148167842Seric }
148267842Seric 
148367842Seric 
148467842Seric /*
148567842Seric **  NI_MAP_LOOKUP -- look up a datum in NetInfo
148667842Seric */
148767842Seric 
148867842Seric char *
148967842Seric ni_map_lookup(map, name, av, statp)
149067842Seric 	MAP *map;
149167842Seric 	char *name;
149267842Seric 	char **av;
149367842Seric 	int *statp;
149467842Seric {
149567842Seric 	char *res;
149667842Seric 	char *propval;
149767842Seric 	extern char *ni_propval();
149867842Seric 
149967842Seric 	if (tTd(38, 20))
1500*67848Seric 		printf("ni_map_lookup(%s, %s)\n",
150167842Seric 			map->map_mname, name);
150267842Seric 
150367842Seric 	propval = ni_propval(map->map_file, map->map_keycolnm, name,
150467842Seric 			     map->map_valcolnm, map->map_coldelim);
150567842Seric 
1506*67848Seric 	if (propval == NULL)
150767842Seric 		return NULL;
150867842Seric 
150967842Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
151067842Seric 		res = map_rewrite(map, name, strlen(name), NULL);
151167842Seric 	else
151267842Seric 		res = map_rewrite(map, propval, strlen(propval), av);
151367842Seric 	free(propval);
151467842Seric 	return res;
151567842Seric }
151667842Seric 
151767842Seric #endif
151867842Seric /*
1519*67848Seric **  TEXT (unindexed text file) Modules
1520*67848Seric **
1521*67848Seric **	This code donated by Sun Microsystems.
1522*67848Seric */
1523*67848Seric 
1524*67848Seric 
1525*67848Seric /*
1526*67848Seric **  TEXT_MAP_OPEN -- open text table
1527*67848Seric */
1528*67848Seric 
1529*67848Seric bool
1530*67848Seric text_map_open(map, mode)
1531*67848Seric 	MAP *map;
1532*67848Seric 	int mode;
1533*67848Seric {
1534*67848Seric 	struct stat sbuf;
1535*67848Seric 
1536*67848Seric 	if (tTd(38, 2))
1537*67848Seric 		printf("text_map_open(%s, %s, %d)\n",
1538*67848Seric 			map->map_mname, map->map_file, mode);
1539*67848Seric 
1540*67848Seric 	if (mode != O_RDONLY)
1541*67848Seric 	{
1542*67848Seric 		errno = ENODEV;
1543*67848Seric 		return FALSE;
1544*67848Seric 	}
1545*67848Seric 
1546*67848Seric 	if (*map->map_file == '\0')
1547*67848Seric 	{
1548*67848Seric 		if (tTd(38, 2))
1549*67848Seric 			printf("text_map_open: file name required\n");
1550*67848Seric 		return FALSE;
1551*67848Seric 	}
1552*67848Seric 
1553*67848Seric 	if (map->map_file[0] != '/')
1554*67848Seric 	{
1555*67848Seric 		if (tTd(38, 2))
1556*67848Seric 			printf("text_map_open(%s): file name must be fully qualified\n",
1557*67848Seric 				map->map_file);
1558*67848Seric 		return FALSE;
1559*67848Seric 	}
1560*67848Seric 	/* check to see if this map actually accessable */
1561*67848Seric 	if (access(map->map_file, R_OK) <0)
1562*67848Seric 		return FALSE;
1563*67848Seric 
1564*67848Seric 	/* check to see if this map actually exist */
1565*67848Seric 	if (stat(map->map_file, &sbuf) <0)
1566*67848Seric 	{
1567*67848Seric 		if (tTd(38, 2))
1568*67848Seric 			printf("text_map_open(%s): can not stat %s\n",
1569*67848Seric 				map->map_file, map->map_file);
1570*67848Seric 		return FALSE;
1571*67848Seric 	}
1572*67848Seric 
1573*67848Seric 	if (!S_ISREG(sbuf.st_mode))
1574*67848Seric 	{
1575*67848Seric 		if (tTd(38, 2))
1576*67848Seric 			printf("text_map_open(%s): %s is not a file\n",
1577*67848Seric 				map->map_file, map->map_file);
1578*67848Seric 		return FALSE;
1579*67848Seric 	}
1580*67848Seric 
1581*67848Seric 	if (map->map_keycolnm == NULL)
1582*67848Seric 		map->map_keycolno = 0;
1583*67848Seric 	else
1584*67848Seric 	{
1585*67848Seric 		if (!isdigit(*map->map_keycolnm))
1586*67848Seric 		{
1587*67848Seric 			if (tTd(38, 2))
1588*67848Seric 				printf("text_map_open(%s): -k should specify a number, not %s\n",
1589*67848Seric 					map->map_file, map->map_keycolnm);
1590*67848Seric 			return FALSE;
1591*67848Seric 		}
1592*67848Seric 		map->map_keycolno = atoi(map->map_keycolnm);
1593*67848Seric 	}
1594*67848Seric 
1595*67848Seric 	if (map->map_valcolnm == NULL)
1596*67848Seric 		map->map_valcolno = 0;
1597*67848Seric 	else
1598*67848Seric 	{
1599*67848Seric 		if (!isdigit(*map->map_valcolnm))
1600*67848Seric 		{
1601*67848Seric 			if (tTd(38, 2))
1602*67848Seric 				printf("text_map_open(%s): -v should specify a number, not %s\n",
1603*67848Seric 					map->map_file, map->map_valcolnm);
1604*67848Seric 			return FALSE;
1605*67848Seric 		}
1606*67848Seric 		map->map_valcolno = atoi(map->map_valcolnm);
1607*67848Seric 	}
1608*67848Seric 
1609*67848Seric 	if (map->map_coldelim == '\0')
1610*67848Seric 		map->map_coldelim = ':';
1611*67848Seric 
1612*67848Seric 	if (tTd(38, 2))
1613*67848Seric 	{
1614*67848Seric 		printf("text_map_open(%s): delimiter = %c\n",
1615*67848Seric 			map->map_file, map->map_coldelim);
1616*67848Seric 	}
1617*67848Seric 
1618*67848Seric 	return TRUE;
1619*67848Seric }
1620*67848Seric 
1621*67848Seric 
1622*67848Seric /*
1623*67848Seric **  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
1624*67848Seric */
1625*67848Seric 
1626*67848Seric char *
1627*67848Seric text_map_lookup(map, name, av, statp)
1628*67848Seric 	MAP *map;
1629*67848Seric 	char *name;
1630*67848Seric 	char **av;
1631*67848Seric 	int *statp;
1632*67848Seric {
1633*67848Seric 	char *vp;
1634*67848Seric 	auto int vsize;
1635*67848Seric 	int buflen;
1636*67848Seric 	char search_key[MAXNAME + 1];
1637*67848Seric 	char linebuf[MAXLINE];
1638*67848Seric 	FILE *f;
1639*67848Seric 	char buf[MAXNAME+1];
1640*67848Seric 	char delim;
1641*67848Seric 	int key_idx;
1642*67848Seric 	bool found_it;
1643*67848Seric 	extern char *get_column();
1644*67848Seric 
1645*67848Seric 
1646*67848Seric 	found_it = FALSE;
1647*67848Seric 	if (tTd(38, 20))
1648*67848Seric 		printf("text_map_lookup(%s)\n", name);
1649*67848Seric 
1650*67848Seric 	buflen = strlen(name);
1651*67848Seric 	if (buflen > sizeof search_key - 1)
1652*67848Seric 		buflen = sizeof search_key - 1;
1653*67848Seric 	bcopy(name, search_key, buflen + 1);
1654*67848Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
1655*67848Seric 		makelower(search_key);
1656*67848Seric 
1657*67848Seric 	f = fopen(map->map_file, "r");
1658*67848Seric 	if (f == NULL)
1659*67848Seric 	{
1660*67848Seric 		map->map_mflags &= ~(MF_VALID|MF_OPEN);
1661*67848Seric 		*statp = EX_UNAVAILABLE;
1662*67848Seric 		return NULL;
1663*67848Seric 	}
1664*67848Seric 	key_idx = map->map_keycolno;
1665*67848Seric 	delim = map->map_coldelim;
1666*67848Seric 	while (fgets(linebuf, MAXLINE, f))
1667*67848Seric 	{
1668*67848Seric 		char *lf;
1669*67848Seric 		if (linebuf[0] == '#')
1670*67848Seric 			continue; /* skip comment line */
1671*67848Seric 		if (lf = strchr(linebuf, '\n'))
1672*67848Seric 			*lf = '\0';
1673*67848Seric 		if (!strcasecmp(search_key,
1674*67848Seric 				get_column(linebuf, key_idx, delim, buf)))
1675*67848Seric 		{
1676*67848Seric 			found_it = TRUE;
1677*67848Seric 			break;
1678*67848Seric 		}
1679*67848Seric 	}
1680*67848Seric 	fclose(f);
1681*67848Seric 	if (!found_it)
1682*67848Seric 	{
1683*67848Seric #ifdef MAP_EXIT_STAT
1684*67848Seric 		*statp = EX_NOTFOUND;
1685*67848Seric #endif
1686*67848Seric 		return(NULL);
1687*67848Seric 	}
1688*67848Seric 	vp = get_column(linebuf, map->map_valcolno, delim, buf);
1689*67848Seric 	vsize = strlen(vp);
1690*67848Seric #ifdef MAP_EXIT_STAT
1691*67848Seric 	*statp = EX_OK;
1692*67848Seric #endif
1693*67848Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
1694*67848Seric 		return map_rewrite(map, name, strlen(name), NULL);
1695*67848Seric 	else
1696*67848Seric 		return map_rewrite(map, vp, vsize, av);
1697*67848Seric }
1698*67848Seric /*
169960089Seric **  STAB (Symbol Table) Modules
170060089Seric */
170160089Seric 
170260089Seric 
170360089Seric /*
170460207Seric **  STAB_MAP_LOOKUP -- look up alias in symbol table
170560089Seric */
170660089Seric 
170760089Seric char *
170861707Seric stab_map_lookup(map, name, av, pstat)
170960089Seric 	register MAP *map;
171060089Seric 	char *name;
171161707Seric 	char **av;
171261707Seric 	int *pstat;
171360089Seric {
171460089Seric 	register STAB *s;
171560089Seric 
171660537Seric 	if (tTd(38, 20))
171767726Seric 		printf("stab_lookup(%s, %s)\n",
171867726Seric 			map->map_mname, name);
171960089Seric 
172060089Seric 	s = stab(name, ST_ALIAS, ST_FIND);
172160089Seric 	if (s != NULL)
172260089Seric 		return (s->s_alias);
172360089Seric 	return (NULL);
172460089Seric }
172560089Seric 
172660089Seric 
172760089Seric /*
172860207Seric **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
172960089Seric */
173060089Seric 
173160089Seric void
173260089Seric stab_map_store(map, lhs, rhs)
173360089Seric 	register MAP *map;
173460089Seric 	char *lhs;
173560089Seric 	char *rhs;
173660089Seric {
173760089Seric 	register STAB *s;
173860089Seric 
173960089Seric 	s = stab(lhs, ST_ALIAS, ST_ENTER);
174060089Seric 	s->s_alias = newstr(rhs);
174160089Seric }
174260089Seric 
174360089Seric 
174460089Seric /*
174560207Seric **  STAB_MAP_OPEN -- initialize (reads data file)
174660207Seric **
174760207Seric **	This is a wierd case -- it is only intended as a fallback for
174860207Seric **	aliases.  For this reason, opens for write (only during a
174960207Seric **	"newaliases") always fails, and opens for read open the
175060207Seric **	actual underlying text file instead of the database.
175160089Seric */
175260089Seric 
175360089Seric bool
175460089Seric stab_map_open(map, mode)
175560089Seric 	register MAP *map;
175660089Seric 	int mode;
175760089Seric {
175863835Seric 	FILE *af;
175964284Seric 	struct stat st;
176063835Seric 
176160537Seric 	if (tTd(38, 2))
176267726Seric 		printf("stab_map_open(%s, %s)\n",
176367726Seric 			map->map_mname, map->map_file);
176460089Seric 
176560089Seric 	if (mode != O_RDONLY)
176660207Seric 	{
176760207Seric 		errno = ENODEV;
176860089Seric 		return FALSE;
176960207Seric 	}
177060089Seric 
177163835Seric 	af = fopen(map->map_file, "r");
177263835Seric 	if (af == NULL)
177363835Seric 		return FALSE;
177467263Seric 	readaliases(map, af, FALSE, FALSE);
177564284Seric 
177664284Seric 	if (fstat(fileno(af), &st) >= 0)
177764284Seric 		map->map_mtime = st.st_mtime;
177863835Seric 	fclose(af);
177963835Seric 
178060089Seric 	return TRUE;
178160089Seric }
178260089Seric /*
178360089Seric **  Implicit Modules
178456822Seric **
178560089Seric **	Tries several types.  For back compatibility of aliases.
178656822Seric */
178756822Seric 
178860089Seric 
178960089Seric /*
179060207Seric **  IMPL_MAP_LOOKUP -- lookup in best open database
179160089Seric */
179260089Seric 
179360089Seric char *
179460089Seric impl_map_lookup(map, name, av, pstat)
179560089Seric 	MAP *map;
179660089Seric 	char *name;
179756822Seric 	char **av;
179860089Seric 	int *pstat;
179956822Seric {
180060537Seric 	if (tTd(38, 20))
180167726Seric 		printf("impl_map_lookup(%s, %s)\n",
180267726Seric 			map->map_mname, name);
180356822Seric 
180460089Seric #ifdef NEWDB
180560207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
180660089Seric 		return db_map_lookup(map, name, av, pstat);
180760089Seric #endif
180860089Seric #ifdef NDBM
180960207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
181060089Seric 		return ndbm_map_lookup(map, name, av, pstat);
181160089Seric #endif
181260089Seric 	return stab_map_lookup(map, name, av, pstat);
181360089Seric }
181460089Seric 
181560089Seric /*
181660207Seric **  IMPL_MAP_STORE -- store in open databases
181760089Seric */
181860089Seric 
181960089Seric void
182060089Seric impl_map_store(map, lhs, rhs)
182160089Seric 	MAP *map;
182260089Seric 	char *lhs;
182360089Seric 	char *rhs;
182460089Seric {
182560089Seric #ifdef NEWDB
182660207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
182760089Seric 		db_map_store(map, lhs, rhs);
182860089Seric #endif
182960089Seric #ifdef NDBM
183060207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
183160089Seric 		ndbm_map_store(map, lhs, rhs);
183260089Seric #endif
183360089Seric 	stab_map_store(map, lhs, rhs);
183460089Seric }
183560089Seric 
183660089Seric /*
183760089Seric **  IMPL_MAP_OPEN -- implicit database open
183860089Seric */
183960089Seric 
184060089Seric bool
184160089Seric impl_map_open(map, mode)
184260089Seric 	MAP *map;
184360089Seric 	int mode;
184460089Seric {
184560089Seric 	struct stat stb;
184660089Seric 
184760537Seric 	if (tTd(38, 2))
184867726Seric 		printf("impl_map_open(%s, %s, %d)\n",
184967726Seric 			map->map_mname, map->map_file, mode);
185060089Seric 
185160089Seric 	if (stat(map->map_file, &stb) < 0)
185256822Seric 	{
185360089Seric 		/* no alias file at all */
185464718Seric 		if (tTd(38, 3))
185564718Seric 			printf("no map file\n");
185660089Seric 		return FALSE;
185756822Seric 	}
185856822Seric 
185960089Seric #ifdef NEWDB
186060207Seric 	map->map_mflags |= MF_IMPL_HASH;
186160089Seric 	if (hash_map_open(map, mode))
186256822Seric 	{
186364250Seric #if defined(NDBM) && defined(NIS)
186460561Seric 		if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0)
186560207Seric #endif
186660207Seric 			return TRUE;
186760089Seric 	}
186860207Seric 	else
186960207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
187060089Seric #endif
187160089Seric #ifdef NDBM
187260207Seric 	map->map_mflags |= MF_IMPL_NDBM;
187360089Seric 	if (ndbm_map_open(map, mode))
187460089Seric 	{
187560089Seric 		return TRUE;
187660089Seric 	}
187760207Seric 	else
187860207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
187960089Seric #endif
188056822Seric 
188164650Seric #if defined(NEWDB) || defined(NDBM)
188260089Seric 	if (Verbose)
188360089Seric 		message("WARNING: cannot open alias database %s", map->map_file);
188464964Seric #else
188564964Seric 	if (mode != O_RDONLY)
188664964Seric 		usrerr("Cannot rebuild aliases: no database format defined");
188760207Seric #endif
188860089Seric 
188960207Seric 	return stab_map_open(map, mode);
189056822Seric }
189160089Seric 
189260207Seric 
189360089Seric /*
189460207Seric **  IMPL_MAP_CLOSE -- close any open database(s)
189560089Seric */
189660089Seric 
189760089Seric void
189860207Seric impl_map_close(map)
189960089Seric 	MAP *map;
190060089Seric {
190160089Seric #ifdef NEWDB
190260207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
190360089Seric 	{
190460207Seric 		db_map_close(map);
190560207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
190660089Seric 	}
190760089Seric #endif
190860089Seric 
190960089Seric #ifdef NDBM
191060207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
191160089Seric 	{
191260207Seric 		ndbm_map_close(map);
191360207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
191460089Seric 	}
191560089Seric #endif
191660089Seric }
191760207Seric /*
191867726Seric **  User map class.
191967726Seric **
192067726Seric **	Provides access to the system password file.
192167726Seric */
192267726Seric 
192367726Seric /*
192467726Seric **  USER_MAP_OPEN -- open user map
192567726Seric **
192667726Seric **	Really just binds field names to field numbers.
192767726Seric */
192867726Seric 
192967726Seric bool
193067726Seric user_map_open(map, mode)
193167726Seric 	MAP *map;
193267726Seric 	int mode;
193367726Seric {
193467726Seric 	if (tTd(38, 2))
193567726Seric 		printf("user_map_open(%s)\n", map->map_mname);
193667726Seric 
193767726Seric 	if (mode != O_RDONLY)
193867726Seric 	{
193967726Seric 		/* issue a pseudo-error message */
194067726Seric #ifdef ENOSYS
194167726Seric 		errno = ENOSYS;
194267726Seric #else
194367726Seric # ifdef EFTYPE
194467726Seric 		errno = EFTYPE;
194567726Seric # else
194667726Seric 		errno = ENXIO;
194767726Seric # endif
194867726Seric #endif
194967726Seric 		return FALSE;
195067726Seric 	}
195167726Seric 	if (map->map_valcolnm == NULL)
195267726Seric 		/* nothing */ ;
195367726Seric 	else if (strcasecmp(map->map_valcolnm, "name") == 0)
195467726Seric 		map->map_valcolno = 1;
195567726Seric 	else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
195667726Seric 		map->map_valcolno = 2;
195767726Seric 	else if (strcasecmp(map->map_valcolnm, "uid") == 0)
195867726Seric 		map->map_valcolno = 3;
195967726Seric 	else if (strcasecmp(map->map_valcolnm, "gid") == 0)
196067726Seric 		map->map_valcolno = 4;
196167726Seric 	else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
196267726Seric 		map->map_valcolno = 5;
196367726Seric 	else if (strcasecmp(map->map_valcolnm, "dir") == 0)
196467726Seric 		map->map_valcolno = 6;
196567726Seric 	else if (strcasecmp(map->map_valcolnm, "shell") == 0)
196667726Seric 		map->map_valcolno = 7;
196767726Seric 	else
196867726Seric 	{
196967726Seric 		syserr("User map %s: unknown column name %s",
197067726Seric 			map->map_mname, map->map_valcolnm);
197167726Seric 		return FALSE;
197267726Seric 	}
197367726Seric 	return TRUE;
197467726Seric }
197567726Seric 
197667726Seric 
197767726Seric /*
197867726Seric **  USER_MAP_LOOKUP -- look up a user in the passwd file.
197967726Seric */
198067726Seric 
198167726Seric #include <pwd.h>
198267726Seric 
198367726Seric char *
198467726Seric user_map_lookup(map, key, av, statp)
198567726Seric 	MAP *map;
198667726Seric 	char *key;
198767726Seric 	char **av;
198867726Seric 	int *statp;
198967726Seric {
199067726Seric 	struct passwd *pw;
199167726Seric 
199267726Seric 	if (tTd(38, 20))
199367726Seric 		printf("user_map_lookup(%s, %s)\n",
199467726Seric 			map->map_mname, key);
199567726Seric 
199667726Seric 	pw = getpwnam(key);
199767726Seric 	if (pw == NULL)
199867726Seric 		return NULL;
199967726Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
200067726Seric 		return map_rewrite(map, key, strlen(key), NULL);
200167726Seric 	else
200267726Seric 	{
200367726Seric 		char *rwval;
200467726Seric 		char buf[30];
200567726Seric 
200667726Seric 		switch (map->map_valcolno)
200767726Seric 		{
200867726Seric 		  case 0:
200967726Seric 		  case 1:
2010*67848Seric 			rwval = pw->pw_name;
201167726Seric 			break;
201267726Seric 
201367726Seric 		  case 2:
201467726Seric 			rwval = pw->pw_passwd;
201567726Seric 			break;
201667726Seric 
201767726Seric 		  case 3:
201867726Seric 			sprintf(buf, "%d", pw->pw_uid);
201967726Seric 			rwval = buf;
202067726Seric 			break;
202167726Seric 
202267726Seric 		  case 4:
202367726Seric 			sprintf(buf, "%d", pw->pw_gid);
202467726Seric 			rwval = buf;
202567726Seric 			break;
202667726Seric 
202767726Seric 		  case 5:
202867726Seric 			rwval = pw->pw_gecos;
202967726Seric 			break;
203067726Seric 
203167726Seric 		  case 6:
203267726Seric 			rwval = pw->pw_dir;
203367726Seric 			break;
203467726Seric 
203567726Seric 		  case 7:
203667726Seric 			rwval = pw->pw_shell;
203767726Seric 			break;
203867726Seric 		}
203967726Seric 		return map_rewrite(map, rwval, strlen(rwval), av);
204067726Seric 	}
204167726Seric }
204267726Seric /*
204367726Seric **  Sequenced map type.
204467726Seric **
204567726Seric **	Tries each map in order until something matches, much like
204667726Seric **	implicit.  Stores go to the first map in the list that can
204767726Seric **	support storing.
2048*67848Seric **
2049*67848Seric **	This is slightly unusual in that there are two interfaces.
2050*67848Seric **	The "sequence" interface lets you stack maps arbitrarily.
2051*67848Seric **	The "switch" interface builds a sequence map by looking
2052*67848Seric **	at a system-dependent configuration file such as
2053*67848Seric **	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
2054*67848Seric **
2055*67848Seric **	We don't need an explicit open, since all maps are
2056*67848Seric **	opened during startup, including underlying maps.
205767726Seric */
205867726Seric 
205967726Seric /*
206067726Seric **  SEQ_MAP_PARSE -- Sequenced map parsing
206167726Seric */
206267726Seric 
206367726Seric bool
206467726Seric seq_map_parse(map, ap)
206567726Seric 	MAP *map;
206667726Seric 	char *ap;
206767726Seric {
206867726Seric 	int maxmap;
206967726Seric 
207067726Seric 	if (tTd(38, 2))
207167726Seric 		printf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
207267726Seric 	maxmap = 0;
207367726Seric 	while (*ap != '\0')
207467726Seric 	{
207567726Seric 		register char *p;
207667726Seric 		STAB *s;
207767726Seric 
207867726Seric 		/* find beginning of map name */
207967726Seric 		while (isascii(*ap) && isspace(*ap))
208067726Seric 			ap++;
208167726Seric 		for (p = ap; isascii(*p) && isalnum(*p); p++)
208267726Seric 			continue;
208367726Seric 		if (*p != '\0')
208467726Seric 			*p++ = '\0';
208567726Seric 		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
208667726Seric 			p++;
208767726Seric 		if (*ap == '\0')
208867726Seric 		{
208967726Seric 			ap = p;
209067726Seric 			continue;
209167726Seric 		}
209267726Seric 		s = stab(ap, ST_MAP, ST_FIND);
209367726Seric 		if (s == NULL)
209467726Seric 		{
209567726Seric 			syserr("Sequence map %s: unknown member map %s",
209667726Seric 				map->map_mname, ap);
209767726Seric 		}
209867726Seric 		else if (maxmap == MAXMAPSTACK)
209967726Seric 		{
210067726Seric 			syserr("Sequence map %s: too many member maps (%d max)",
210167726Seric 				map->map_mname, MAXMAPSTACK);
210267726Seric 			maxmap++;
210367726Seric 		}
210467726Seric 		else if (maxmap < MAXMAPSTACK)
210567726Seric 		{
210667726Seric 			map->map_stack[maxmap++] = &s->s_map;
210767726Seric 		}
210867726Seric 		ap = p;
210967726Seric 	}
211067726Seric 	return TRUE;
211167726Seric }
211267726Seric 
211367726Seric 
211467726Seric /*
2115*67848Seric **  SWITCH_MAP_OPEN -- open a switched map
2116*67848Seric **
2117*67848Seric **	This looks at the system-dependent configuration and builds
2118*67848Seric **	a sequence map that does the same thing.
2119*67848Seric **
2120*67848Seric **	Every system must define a switch_map_find routine in conf.c
2121*67848Seric **	that will return the list of service types associated with a
2122*67848Seric **	given service class.
2123*67848Seric */
2124*67848Seric 
2125*67848Seric bool
2126*67848Seric switch_map_open(map, mode)
2127*67848Seric 	MAP *map;
2128*67848Seric 	int mode;
2129*67848Seric {
2130*67848Seric 	int mapno;
2131*67848Seric 	int nmaps;
2132*67848Seric 	char *maptype[MAXMAPSTACK];
2133*67848Seric 
2134*67848Seric 	if (tTd(38, 2))
2135*67848Seric 		printf("switch_map_open(%s, %s, %d)\n",
2136*67848Seric 			map->map_mname, map->map_file, mode);
2137*67848Seric 
2138*67848Seric 	nmaps = switch_map_find(map->map_file, maptype);
2139*67848Seric 	if (tTd(38, 19))
2140*67848Seric 	{
2141*67848Seric 		printf("\tswitch_map_find => %d\n", nmaps);
2142*67848Seric 		for (mapno = 0; mapno < nmaps; mapno++)
2143*67848Seric 			printf("\t\t%s\n", maptype[mapno]);
2144*67848Seric 	}
2145*67848Seric 	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
2146*67848Seric 		return FALSE;
2147*67848Seric 
2148*67848Seric 	for (mapno = 0; mapno < nmaps; mapno++)
2149*67848Seric 	{
2150*67848Seric 		register STAB *s;
2151*67848Seric 		char nbuf[MAXNAME + 1];
2152*67848Seric 
2153*67848Seric 		if (maptype[mapno] == NULL)
2154*67848Seric 			continue;
2155*67848Seric 		(void) sprintf(nbuf, "%s.%s", map->map_file, maptype[mapno]);
2156*67848Seric 		s = stab(nbuf, ST_MAP, ST_FIND);
2157*67848Seric 		if (s == NULL)
2158*67848Seric 		{
2159*67848Seric 			syserr("Switch map %s: unknown member map %s",
2160*67848Seric 				map->map_mname, nbuf);
2161*67848Seric 		}
2162*67848Seric 		else
2163*67848Seric 		{
2164*67848Seric 			map->map_stack[mapno] = &s->s_map;
2165*67848Seric 			if (tTd(38, 4))
2166*67848Seric 				printf("\tmap_stack[%d] = %s:%s\n",
2167*67848Seric 					mapno, s->s_map.map_class->map_cname,
2168*67848Seric 					nbuf);
2169*67848Seric 		}
2170*67848Seric 	}
2171*67848Seric 	return TRUE;
2172*67848Seric }
2173*67848Seric 
2174*67848Seric 
2175*67848Seric /*
2176*67848Seric **  SEQ_MAP_CLOSE -- close all underlying maps
2177*67848Seric */
2178*67848Seric 
2179*67848Seric seq_map_close(map)
2180*67848Seric 	MAP *map;
2181*67848Seric {
2182*67848Seric 	int mapno;
2183*67848Seric 
2184*67848Seric 	if (tTd(38, 20))
2185*67848Seric 		printf("seq_map_close(%s)\n", map->map_mname);
2186*67848Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
2187*67848Seric 	{
2188*67848Seric 		MAP *mm = map->map_stack[mapno];
2189*67848Seric 
2190*67848Seric 		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
2191*67848Seric 			continue;
2192*67848Seric 		mm->map_class->map_close(mm);
2193*67848Seric 	}
2194*67848Seric }
2195*67848Seric 
2196*67848Seric 
2197*67848Seric /*
219867726Seric **  SEQ_MAP_LOOKUP -- sequenced map lookup
219967726Seric */
220067726Seric 
220167726Seric char *
220267726Seric seq_map_lookup(map, key, args, pstat)
220367726Seric 	MAP *map;
220467726Seric 	char *key;
220567726Seric 	char **args;
220667726Seric 	int *pstat;
220767726Seric {
220867726Seric 	int mapno;
220967726Seric 	int mapbit = 0x01;
221067726Seric 
221167726Seric 	if (tTd(38, 20))
221267726Seric 		printf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
221367726Seric 
221467726Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
221567726Seric 	{
221667726Seric 		MAP *mm = map->map_stack[mapno];
221767726Seric 		int stat = 0;
221867726Seric 		char *rv;
221967726Seric 
222067726Seric 		if (mm == NULL)
222167726Seric 			continue;
222267726Seric 		if (!bitset(MF_OPEN, mm->map_mflags))
222367726Seric 		{
222467726Seric 			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
2225*67848Seric 			{
2226*67848Seric 				*pstat = EX_UNAVAILABLE;
222767726Seric 				return NULL;
2228*67848Seric 			}
222967726Seric 			continue;
223067726Seric 		}
223167726Seric 		rv = mm->map_class->map_lookup(mm, key, args, &stat);
223267726Seric 		if (rv != NULL)
223367726Seric 			return rv;
223467726Seric 		if (stat == 0 && bitset(mapbit, map->map_return[MA_NOTFOUND]))
223567726Seric 			return NULL;
223667726Seric 		if (stat != 0 && bitset(mapbit, map->map_return[MA_TRYAGAIN]))
223767726Seric 		{
223867726Seric 			*pstat = stat;
223967726Seric 			return NULL;
224067726Seric 		}
224167726Seric 	}
224267726Seric 	return NULL;
224367726Seric }
224467726Seric 
224567726Seric 
224667726Seric /*
224767726Seric **  SEQ_MAP_STORE -- sequenced map store
224867726Seric */
224967726Seric 
225067726Seric void
225167726Seric seq_map_store(map, key, val)
225267726Seric 	MAP *map;
225367726Seric 	char *key;
225467726Seric 	char *val;
225567726Seric {
225667726Seric 	int mapno;
225767726Seric 
225867726Seric 	if (tTd(38, 12))
225967726Seric 		printf("seq_map_store(%s, %s, %s)\n",
226067726Seric 			map->map_mname, key, val);
226167726Seric 
226267726Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
226367726Seric 	{
226467726Seric 		MAP *mm = map->map_stack[mapno];
226567726Seric 
226667726Seric 		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
226767726Seric 			continue;
226867726Seric 
226967726Seric 		mm->map_class->map_store(mm, key, val);
227067726Seric 		return;
227167726Seric 	}
227267726Seric 	syserr("seq_map_store(%s, %s, %s): no writable map",
227367726Seric 		map->map_mname, key, val);
227467726Seric }
227567726Seric /*
227660207Seric **  NULL stubs
227760089Seric */
227860089Seric 
227960207Seric bool
228060207Seric null_map_open(map, mode)
228160089Seric 	MAP *map;
228260207Seric 	int mode;
228360089Seric {
228460207Seric 	return TRUE;
228560089Seric }
228660089Seric 
228760207Seric void
228860207Seric null_map_close(map)
228960207Seric 	MAP *map;
229060089Seric {
229160207Seric 	return;
229260207Seric }
229360089Seric 
229460207Seric void
229560207Seric null_map_store(map, key, val)
229660207Seric 	MAP *map;
229760207Seric 	char *key;
229860207Seric 	char *val;
229960089Seric {
230060207Seric 	return;
230160089Seric }
2302