xref: /csrg-svn/usr.sbin/sendmail/src/map.c (revision 69954)
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*69954Seric static char sccsid[] = "@(#)map.c	8.79 (Berkeley) 06/20/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
2269651Seric   struct dom_binding;	/* forward reference 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.
6069401Seric **
6169401Seric **	This file also includes the implementation for getcanonname.
6269401Seric **	It is currently implemented in a pretty ad-hoc manner; it ought
6369401Seric **	to be more properly integrated into the map structure.
6460089Seric */
6560089Seric 
6660089Seric #define DBMMODE		0644
6764718Seric 
6864718Seric extern bool	aliaswait __P((MAP *, char *, int));
6969833Seric extern bool	extract_canonname __P((char *, char *, char[]));
7060089Seric /*
7160089Seric **  MAP_PARSEARGS -- parse config line arguments for database lookup
7260089Seric **
7360089Seric **	This is a generic version of the map_parse method.
7460089Seric **
7556822Seric **	Parameters:
7660089Seric **		map -- the map being initialized.
7760089Seric **		ap -- a pointer to the args on the config line.
7856822Seric **
7956822Seric **	Returns:
8060089Seric **		TRUE -- if everything parsed OK.
8156822Seric **		FALSE -- otherwise.
8256822Seric **
8356822Seric **	Side Effects:
8460089Seric **		null terminates the filename; stores it in map
8556822Seric */
8656822Seric 
8756822Seric bool
map_parseargs(map,ap)8860089Seric map_parseargs(map, ap)
8956822Seric 	MAP *map;
9060089Seric 	char *ap;
9156822Seric {
9260089Seric 	register char *p = ap;
9356822Seric 
9463753Seric 	map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
9560089Seric 	for (;;)
9660089Seric 	{
9760089Seric 		while (isascii(*p) && isspace(*p))
9860089Seric 			p++;
9960089Seric 		if (*p != '-')
10060089Seric 			break;
10160089Seric 		switch (*++p)
10260089Seric 		{
10360089Seric 		  case 'N':
10460207Seric 			map->map_mflags |= MF_INCLNULL;
10563753Seric 			map->map_mflags &= ~MF_TRY0NULL;
10660089Seric 			break;
10760089Seric 
10863753Seric 		  case 'O':
10963753Seric 			map->map_mflags &= ~MF_TRY1NULL;
11063753Seric 			break;
11163753Seric 
11260089Seric 		  case 'o':
11360207Seric 			map->map_mflags |= MF_OPTIONAL;
11460089Seric 			break;
11560089Seric 
11660089Seric 		  case 'f':
11760207Seric 			map->map_mflags |= MF_NOFOLDCASE;
11860089Seric 			break;
11960089Seric 
12060089Seric 		  case 'm':
12160207Seric 			map->map_mflags |= MF_MATCHONLY;
12260089Seric 			break;
12360089Seric 
12468497Seric 		  case 'A':
12568497Seric 			map->map_mflags |= MF_APPEND;
12668497Seric 			break;
12768497Seric 
12869703Seric 		  case 'q':
12969703Seric 			map->map_mflags |= MF_KEEPQUOTES;
13069703Seric 			break;
13169703Seric 
13260089Seric 		  case 'a':
13360089Seric 			map->map_app = ++p;
13460089Seric 			break;
13568350Seric 
13668350Seric 		  case 'k':
13768350Seric 			while (isascii(*++p) && isspace(*p))
13868350Seric 				continue;
13968350Seric 			map->map_keycolnm = p;
14068350Seric 			break;
14168350Seric 
14268350Seric 		  case 'v':
14368350Seric 			while (isascii(*++p) && isspace(*p))
14468350Seric 				continue;
14568350Seric 			map->map_valcolnm = p;
14668350Seric 			break;
14768350Seric 
14868350Seric 		  case 'z':
14968350Seric 			if (*++p != '\\')
15068350Seric 				map->map_coldelim = *p;
15168350Seric 			else
15268350Seric 			{
15368350Seric 				switch (*++p)
15468350Seric 				{
15568350Seric 				  case 'n':
15668350Seric 					map->map_coldelim = '\n';
15768350Seric 					break;
15868350Seric 
15968350Seric 				  case 't':
16068350Seric 					map->map_coldelim = '\t';
16168350Seric 					break;
16268350Seric 
16368350Seric 				  default:
16468350Seric 					map->map_coldelim = '\\';
16568350Seric 				}
16668350Seric 			}
16768350Seric 			break;
16868497Seric #ifdef RESERVED_FOR_SUN
16968497Seric 		  case 'd':
17068497Seric 			map->map_mflags |= MF_DOMAIN_WIDE;
17168497Seric 			break;
17268497Seric 
17368497Seric 		  case 's':
17468497Seric 			/* info type */
17568497Seric 			break;
17668497Seric #endif
17760089Seric 		}
17860089Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
17960089Seric 			p++;
18060089Seric 		if (*p != '\0')
18160089Seric 			*p++ = '\0';
18260089Seric 	}
18360089Seric 	if (map->map_app != NULL)
18460089Seric 		map->map_app = newstr(map->map_app);
18568350Seric 	if (map->map_keycolnm != NULL)
18668350Seric 		map->map_keycolnm = newstr(map->map_keycolnm);
18768350Seric 	if (map->map_valcolnm != NULL)
18868350Seric 		map->map_valcolnm = newstr(map->map_valcolnm);
18960089Seric 
19060089Seric 	if (*p != '\0')
19160089Seric 	{
19260089Seric 		map->map_file = p;
19360089Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
19460089Seric 			p++;
19560089Seric 		if (*p != '\0')
19660089Seric 			*p++ = '\0';
19760089Seric 		map->map_file = newstr(map->map_file);
19860089Seric 	}
19960089Seric 
20060089Seric 	while (*p != '\0' && isascii(*p) && isspace(*p))
20160089Seric 		p++;
20260089Seric 	if (*p != '\0')
20360089Seric 		map->map_rebuild = newstr(p);
20460089Seric 
20568350Seric 	if (map->map_file == NULL &&
20668350Seric 	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
20757208Seric 	{
20860089Seric 		syserr("No file name for %s map %s",
20960089Seric 			map->map_class->map_cname, map->map_mname);
21056822Seric 		return FALSE;
21157208Seric 	}
21260089Seric 	return TRUE;
21360089Seric }
21460089Seric /*
21560089Seric **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
21660089Seric **
21760089Seric **	It also adds the map_app string.  It can be used as a utility
21860089Seric **	in the map_lookup method.
21960089Seric **
22060089Seric **	Parameters:
22160089Seric **		map -- the map that causes this.
22260089Seric **		s -- the string to rewrite, NOT necessarily null terminated.
22360089Seric **		slen -- the length of s.
22460089Seric **		av -- arguments to interpolate into buf.
22560089Seric **
22660089Seric **	Returns:
22767895Seric **		Pointer to rewritten result.  This is static data that
22867895Seric **		should be copied if it is to be saved!
22960089Seric **
23060089Seric **	Side Effects:
23160089Seric **		none.
23260089Seric */
23360089Seric 
23460089Seric char *
map_rewrite(map,s,slen,av)23560089Seric map_rewrite(map, s, slen, av)
23660089Seric 	register MAP *map;
23760089Seric 	register char *s;
23860089Seric 	int slen;
23960089Seric 	char **av;
24060089Seric {
24160089Seric 	register char *bp;
24260089Seric 	register char c;
24360089Seric 	char **avp;
24460089Seric 	register char *ap;
24560089Seric 	int i;
24660089Seric 	int len;
24767895Seric 	static int buflen = -1;
24867895Seric 	static char *buf = NULL;
24960089Seric 
25060537Seric 	if (tTd(39, 1))
25160089Seric 	{
25260256Seric 		printf("map_rewrite(%.*s), av =", slen, s);
25360256Seric 		if (av == NULL)
25460256Seric 			printf(" (nullv)");
25560256Seric 		else
25660256Seric 		{
25760256Seric 			for (avp = av; *avp != NULL; avp++)
25860256Seric 				printf("\n\t%s", *avp);
25960256Seric 		}
26060256Seric 		printf("\n");
26160089Seric 	}
26260089Seric 
26360089Seric 	/* count expected size of output (can safely overestimate) */
26460089Seric 	i = len = slen;
26560089Seric 	if (av != NULL)
26660089Seric 	{
26760089Seric 		bp = s;
26860089Seric 		for (i = slen; --i >= 0 && (c = *bp++) != 0; )
26960089Seric 		{
27060089Seric 			if (c != '%')
27160089Seric 				continue;
27260089Seric 			if (--i < 0)
27360089Seric 				break;
27460089Seric 			c = *bp++;
27560089Seric 			if (!(isascii(c) && isdigit(c)))
27660089Seric 				continue;
27763937Seric 			for (avp = av; --c >= '0' && *avp != NULL; avp++)
27860089Seric 				continue;
27960089Seric 			if (*avp == NULL)
28060089Seric 				continue;
28160089Seric 			len += strlen(*avp);
28260089Seric 		}
28360089Seric 	}
28460089Seric 	if (map->map_app != NULL)
28560089Seric 		len += strlen(map->map_app);
28667895Seric 	if (buflen < ++len)
28760089Seric 	{
28860089Seric 		/* need to malloc additional space */
28967895Seric 		buflen = len;
29067895Seric 		if (buf != NULL)
29167895Seric 			free(buf);
29267895Seric 		buf = xalloc(buflen);
29360089Seric 	}
29460089Seric 
29567895Seric 	bp = buf;
29660089Seric 	if (av == NULL)
29760089Seric 	{
29860089Seric 		bcopy(s, bp, slen);
29960089Seric 		bp += slen;
30060089Seric 	}
30160089Seric 	else
30260089Seric 	{
30360089Seric 		while (--slen >= 0 && (c = *s++) != '\0')
30460089Seric 		{
30560089Seric 			if (c != '%')
30660089Seric 			{
30760089Seric   pushc:
30860089Seric 				*bp++ = c;
30960089Seric 				continue;
31060089Seric 			}
31160089Seric 			if (--slen < 0 || (c = *s++) == '\0')
31260089Seric 				c = '%';
31360089Seric 			if (c == '%')
31460089Seric 				goto pushc;
31560089Seric 			if (!(isascii(c) && isdigit(c)))
31660089Seric 			{
31760089Seric 				*bp++ = '%';
31860089Seric 				goto pushc;
31960089Seric 			}
32063937Seric 			for (avp = av; --c >= '0' && *avp != NULL; avp++)
32160089Seric 				continue;
32260089Seric 			if (*avp == NULL)
32360089Seric 				continue;
32460089Seric 
32560089Seric 			/* transliterate argument into output string */
32660089Seric 			for (ap = *avp; (c = *ap++) != '\0'; )
32760089Seric 				*bp++ = c;
32860089Seric 		}
32960089Seric 	}
33060089Seric 	if (map->map_app != NULL)
33160089Seric 		strcpy(bp, map->map_app);
33260089Seric 	else
33360089Seric 		*bp = '\0';
33460537Seric 	if (tTd(39, 1))
33567895Seric 		printf("map_rewrite => %s\n", buf);
33667895Seric 	return buf;
33760089Seric }
33860089Seric /*
33960537Seric **  INITMAPS -- initialize for aliasing
34060537Seric **
34160537Seric **	Parameters:
34260537Seric **		rebuild -- if TRUE, this rebuilds the cached versions.
34360537Seric **		e -- current envelope.
34460537Seric **
34560537Seric **	Returns:
34660537Seric **		none.
34760537Seric **
34860537Seric **	Side Effects:
34960537Seric **		initializes aliases:
35060537Seric **		if NDBM:  opens the database.
35160537Seric **		if ~NDBM: reads the aliases into the symbol table.
35260537Seric */
35360537Seric 
35469748Seric void
initmaps(rebuild,e)35560537Seric initmaps(rebuild, e)
35660537Seric 	bool rebuild;
35760537Seric 	register ENVELOPE *e;
35860537Seric {
35960537Seric 	extern void map_init();
36060537Seric 
36169881Seric #if XDEBUG
36264671Seric 	checkfd012("entering initmaps");
36364671Seric #endif
36460537Seric 	CurEnv = e;
36565085Seric 	if (rebuild)
36665085Seric 	{
36765085Seric 		stabapply(map_init, 1);
36865085Seric 		stabapply(map_init, 2);
36965085Seric 	}
37065085Seric 	else
37165085Seric 	{
37265085Seric 		stabapply(map_init, 0);
37365085Seric 	}
37469881Seric #if XDEBUG
37564671Seric 	checkfd012("exiting initmaps");
37664671Seric #endif
37760537Seric }
37860537Seric 
37960537Seric void
map_init(s,rebuild)38060537Seric map_init(s, rebuild)
38160537Seric 	register STAB *s;
38260537Seric 	int rebuild;
38360537Seric {
38460537Seric 	register MAP *map;
38560537Seric 
38660537Seric 	/* has to be a map */
38760537Seric 	if (s->s_type != ST_MAP)
38860537Seric 		return;
38960537Seric 
39060537Seric 	map = &s->s_map;
39160537Seric 	if (!bitset(MF_VALID, map->map_mflags))
39260537Seric 		return;
39360537Seric 
39460537Seric 	if (tTd(38, 2))
39568350Seric 		printf("map_init(%s:%s, %s, %d)\n",
39664690Seric 			map->map_class->map_cname == NULL ? "NULL" :
39764690Seric 				map->map_class->map_cname,
39868350Seric 			map->map_mname == NULL ? "NULL" : map->map_mname,
39965085Seric 			map->map_file == NULL ? "NULL" : map->map_file,
40065085Seric 			rebuild);
40160537Seric 
40265085Seric 	if (rebuild == (bitset(MF_ALIAS, map->map_mflags) &&
40365085Seric 		    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2))
40465085Seric 	{
40565085Seric 		if (tTd(38, 3))
40665085Seric 			printf("\twrong pass\n");
40765085Seric 		return;
40865085Seric 	}
40965085Seric 
41060537Seric 	/* if already open, close it (for nested open) */
41160537Seric 	if (bitset(MF_OPEN, map->map_mflags))
41260537Seric 	{
41360537Seric 		map->map_class->map_close(map);
41460537Seric 		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
41560537Seric 	}
41660537Seric 
41765085Seric 	if (rebuild == 2)
41860537Seric 	{
41965085Seric 		rebuildaliases(map, FALSE);
42060537Seric 	}
42160537Seric 	else
42260537Seric 	{
42360537Seric 		if (map->map_class->map_open(map, O_RDONLY))
42460537Seric 		{
42560537Seric 			if (tTd(38, 4))
42668350Seric 				printf("\t%s:%s %s: valid\n",
42764690Seric 					map->map_class->map_cname == NULL ? "NULL" :
42864690Seric 						map->map_class->map_cname,
42968350Seric 					map->map_mname == NULL ? "NULL" :
43068350Seric 						map->map_mname,
43164690Seric 					map->map_file == NULL ? "NULL" :
43264690Seric 						map->map_file);
43360537Seric 			map->map_mflags |= MF_OPEN;
43460537Seric 		}
43568350Seric 		else
43668350Seric 		{
43768350Seric 			if (tTd(38, 4))
43868350Seric 				printf("\t%s:%s %s: invalid: %s\n",
43968350Seric 					map->map_class->map_cname == NULL ? "NULL" :
44068350Seric 						map->map_class->map_cname,
44168350Seric 					map->map_mname == NULL ? "NULL" :
44268350Seric 						map->map_mname,
44368350Seric 					map->map_file == NULL ? "NULL" :
44468350Seric 						map->map_file,
44568350Seric 					errstring(errno));
44668350Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
44768350Seric 			{
44868350Seric 				extern MAPCLASS BogusMapClass;
44968350Seric 
45068350Seric 				map->map_class = &BogusMapClass;
45168350Seric 				map->map_mflags |= MF_OPEN;
45268350Seric 			}
45368350Seric 		}
45460537Seric 	}
45560537Seric }
45660537Seric /*
45769802Seric **  GETCANONNAME -- look up name using service switch
45869802Seric **
45969802Seric **	Parameters:
46069802Seric **		host -- the host name to look up.
46169802Seric **		hbsize -- the size of the host buffer.
46269802Seric **		trymx -- if set, try MX records.
46369802Seric **
46469802Seric **	Returns:
46569802Seric **		TRUE -- if the host was found.
46669802Seric **		FALSE -- otherwise.
46769802Seric */
46869802Seric 
46969802Seric bool
getcanonname(host,hbsize,trymx)47069802Seric getcanonname(host, hbsize, trymx)
47169802Seric 	char *host;
47269802Seric 	int hbsize;
47369802Seric 	bool trymx;
47469802Seric {
47569802Seric 	int nmaps;
47669802Seric 	int mapno;
47769802Seric 	bool found = FALSE;
47869802Seric 	auto int stat;
47969802Seric 	char *maptype[MAXMAPSTACK];
48069802Seric 	short mapreturn[MAXMAPACTIONS];
48169802Seric 
48269802Seric 	nmaps = switch_map_find("hosts", maptype, mapreturn);
48369802Seric 	for (mapno = 0; mapno < nmaps; mapno++)
48469802Seric 	{
48569802Seric 		int i;
48669802Seric 
48769802Seric 		if (tTd(38, 20))
48869802Seric 			printf("getcanonname(%s), trying %s\n",
48969802Seric 				host, maptype[mapno]);
49069802Seric 		if (strcmp("files", maptype[mapno]) == 0)
49169802Seric 		{
49269802Seric 			extern bool text_getcanonname __P((char *, int, int *));
49369802Seric 
49469802Seric 			found = text_getcanonname(host, hbsize, &stat);
49569802Seric 		}
49669802Seric #ifdef NIS
49769802Seric 		else if (strcmp("nis", maptype[mapno]) == 0)
49869802Seric 		{
49969802Seric 			extern bool nis_getcanonname __P((char *, int, int *));
50069802Seric 
50169802Seric 			found = nis_getcanonname(host, hbsize, &stat);
50269802Seric 		}
50369802Seric #endif
50469802Seric #ifdef NISPLUS
50569802Seric 		else if (strcmp("nisplus", maptype[mapno]) == 0)
50669802Seric 		{
50769802Seric 			extern bool nisplus_getcanonname __P((char *, int, int *));
50869802Seric 
50969802Seric 			found = nisplus_getcanonname(host, hbsize, &stat);
51069802Seric 		}
51169802Seric #endif
51269802Seric #if NAMED_BIND
51369802Seric 		else if (strcmp("dns", maptype[mapno]) == 0)
51469802Seric 		{
51569802Seric 			extern bool dns_getcanonname __P((char *, int, bool, int *));
51669802Seric 
51769802Seric 			found = dns_getcanonname(host, hbsize, trymx, &stat);
51869802Seric 		}
51969802Seric #endif
52069802Seric 		else
52169802Seric 		{
52269802Seric 			found = FALSE;
52369802Seric 			stat = EX_UNAVAILABLE;
52469802Seric 		}
52569802Seric 		if (found)
52669802Seric 			break;
52769802Seric 
52869802Seric 		/* see if we should continue */
52969802Seric 		if (stat == EX_TEMPFAIL)
53069802Seric 			i = MA_TRYAGAIN;
53169802Seric 		else if (stat == EX_NOHOST)
53269802Seric 			i = MA_NOTFOUND;
53369802Seric 		else
53469802Seric 			i = MA_UNAVAIL;
53569802Seric 		if (bitset(1 << mapno, mapreturn[i]))
53669802Seric 			break;
53769802Seric 	}
53869802Seric 
53969802Seric 	if (found)
54069802Seric 	{
54169802Seric 		char *d;
54269802Seric 
54369802Seric 		if (tTd(38, 20))
54469802Seric 			printf("getcanonname(%s), found\n", host);
54569802Seric 
54669802Seric 		/*
54769802Seric 		**  If returned name is still single token, compensate
54869802Seric 		**  by tagging on $m.  This is because some sites set
54969802Seric 		**  up their DNS or NIS databases wrong.
55069802Seric 		*/
55169802Seric 
55269802Seric 		if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
55369802Seric 		{
55469802Seric 			d = macvalue('m', CurEnv);
55569802Seric 			if (d != NULL &&
55669802Seric 			    hbsize > (int) (strlen(host) + strlen(d) + 1))
55769802Seric 			{
55869802Seric 				if (host[strlen(host) - 1] != '.')
55969802Seric 					strcat(host, ".");
56069802Seric 				strcat(host, d);
56169802Seric 			}
56269802Seric 			else
56369802Seric 			{
56469802Seric 				return FALSE;
56569802Seric 			}
56669802Seric 		}
56769802Seric 		return TRUE;
56869802Seric 	}
56969802Seric 
57069802Seric 	if (tTd(38, 20))
57169802Seric 		printf("getcanonname(%s), failed, stat=%d\n", host, stat);
57269802Seric 
57369802Seric #if NAMED_BIND
57469802Seric 	if (stat == EX_NOHOST)
57569802Seric 		h_errno = HOST_NOT_FOUND;
57669802Seric 	else
57769802Seric 		h_errno = TRY_AGAIN;
57869802Seric #endif
57969802Seric 
58069802Seric 	return FALSE;
58169802Seric }
58269802Seric /*
58369833Seric **  EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
58469833Seric **
58569833Seric **	Parameters:
58669833Seric **		name -- the name against which to match.
58769833Seric **		line -- the /etc/hosts line.
58869833Seric **		cbuf -- the location to store the result.
58969833Seric **
59069833Seric **	Returns:
59169833Seric **		TRUE -- if the line matched the desired name.
59269833Seric **		FALSE -- otherwise.
59369833Seric */
59469833Seric 
59569833Seric bool
extract_canonname(name,line,cbuf)59669833Seric extract_canonname(name, line, cbuf)
59769833Seric 	char *name;
59869833Seric 	char *line;
59969833Seric 	char cbuf[];
60069833Seric {
60169833Seric 	int i;
60269833Seric 	char *p;
60369833Seric 	bool found = FALSE;
60469833Seric 	extern char *get_column();
60569833Seric 
60669833Seric 	cbuf[0] = '\0';
60769833Seric 	if (line[0] == '#')
60869833Seric 		return FALSE;
60969833Seric 
61069876Seric 	for (i = 1; ; i++)
61169833Seric 	{
61269833Seric 		char nbuf[MAXNAME + 1];
61369833Seric 
61469833Seric 		p = get_column(line, i, '\0', nbuf);
61569833Seric 		if (p == NULL)
61669833Seric 			break;
61769833Seric 		if (cbuf[0] == '\0' ||
61869833Seric 		    (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
61969833Seric 			strcpy(cbuf, p);
62069833Seric 		if (strcasecmp(name, p) == 0)
62169833Seric 			found = TRUE;
62269833Seric 	}
62369833Seric 	if (found && strchr(cbuf, '.') == NULL)
62469833Seric 	{
62569833Seric 		/* try to add a domain on the end of the name */
62669833Seric 		char *domain = macvalue('m', CurEnv);
62769833Seric 
62869833Seric 		if (domain != NULL &&
62969833Seric 		    strlen(domain) + strlen(cbuf) + 1 < MAXNAME)
63069833Seric 		{
63169833Seric 			p = &cbuf[strlen(cbuf)];
63269833Seric 			*p++ = '.';
63369833Seric 			strcpy(p, domain);
63469833Seric 		}
63569833Seric 	}
63669833Seric 	return found;
63769833Seric }
63869833Seric /*
63960089Seric **  NDBM modules
64060089Seric */
64160089Seric 
64260089Seric #ifdef NDBM
64360089Seric 
64460089Seric /*
64560089Seric **  DBM_MAP_OPEN -- DBM-style map open
64660089Seric */
64760089Seric 
64860089Seric bool
ndbm_map_open(map,mode)64960089Seric ndbm_map_open(map, mode)
65060089Seric 	MAP *map;
65160089Seric 	int mode;
65260089Seric {
65364284Seric 	register DBM *dbm;
65464284Seric 	struct stat st;
65560089Seric 
65660537Seric 	if (tTd(38, 2))
65768350Seric 		printf("ndbm_map_open(%s, %s, %d)\n",
65868350Seric 			map->map_mname, map->map_file, mode);
65960089Seric 
66060207Seric 	if (mode == O_RDWR)
66160207Seric 		mode |= O_CREAT|O_TRUNC;
66260207Seric 
66360089Seric 	/* open the database */
66460089Seric 	dbm = dbm_open(map->map_file, mode, DBMMODE);
66556822Seric 	if (dbm == NULL)
66656822Seric 	{
66764718Seric 		if (aliaswait(map, ".pag", FALSE))
66864718Seric 			return TRUE;
66960207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
67056836Seric 			syserr("Cannot open DBM database %s", map->map_file);
67156822Seric 		return FALSE;
67256822Seric 	}
67360089Seric 	map->map_db1 = (void *) dbm;
67464964Seric 	if (mode == O_RDONLY)
67564964Seric 	{
67664964Seric 		if (bitset(MF_ALIAS, map->map_mflags) &&
67764964Seric 		    !aliaswait(map, ".pag", TRUE))
67864718Seric 			return FALSE;
67964964Seric 	}
68064964Seric 	else
68164964Seric 	{
68264964Seric 		int fd;
68364964Seric 
68464964Seric 		/* exclusive lock for duration of rebuild */
68564964Seric 		fd = dbm_dirfno((DBM *) map->map_db1);
68664964Seric 		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) &&
68764964Seric 		    lockfile(fd, map->map_file, ".dir", LOCK_EX))
68864964Seric 			map->map_mflags |= MF_LOCKED;
68964964Seric 	}
69064718Seric 	if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0)
69164284Seric 		map->map_mtime = st.st_mtime;
69256822Seric 	return TRUE;
69356822Seric }
69460089Seric 
69560089Seric 
69660089Seric /*
69756822Seric **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
69856822Seric */
69956822Seric 
70056822Seric char *
ndbm_map_lookup(map,name,av,statp)70160089Seric ndbm_map_lookup(map, name, av, statp)
70256822Seric 	MAP *map;
70360089Seric 	char *name;
70456822Seric 	char **av;
70559084Seric 	int *statp;
70656822Seric {
70756822Seric 	datum key, val;
70864373Seric 	int fd;
70960089Seric 	char keybuf[MAXNAME + 1];
71056822Seric 
71160537Seric 	if (tTd(38, 20))
71268350Seric 		printf("ndbm_map_lookup(%s, %s)\n",
71368350Seric 			map->map_mname, name);
71460089Seric 
71560089Seric 	key.dptr = name;
71660089Seric 	key.dsize = strlen(name);
71760207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
71857014Seric 	{
71960089Seric 		if (key.dsize > sizeof keybuf - 1)
72060089Seric 			key.dsize = sizeof keybuf - 1;
72160089Seric 		bcopy(key.dptr, keybuf, key.dsize + 1);
72260089Seric 		makelower(keybuf);
72360089Seric 		key.dptr = keybuf;
72457014Seric 	}
72564373Seric 	fd = dbm_dirfno((DBM *) map->map_db1);
72664388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
72764373Seric 		(void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
72863753Seric 	val.dptr = NULL;
72963753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
73063753Seric 	{
73163753Seric 		val = dbm_fetch((DBM *) map->map_db1, key);
73263753Seric 		if (val.dptr != NULL)
73363753Seric 			map->map_mflags &= ~MF_TRY1NULL;
73463753Seric 	}
73563753Seric 	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
73663753Seric 	{
73756822Seric 		key.dsize++;
73863753Seric 		val = dbm_fetch((DBM *) map->map_db1, key);
73963753Seric 		if (val.dptr != NULL)
74063753Seric 			map->map_mflags &= ~MF_TRY0NULL;
74163753Seric 	}
74264388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
74364373Seric 		(void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
74456822Seric 	if (val.dptr == NULL)
74556822Seric 		return NULL;
74660207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
74763753Seric 		return map_rewrite(map, name, strlen(name), NULL);
74863753Seric 	else
74963753Seric 		return map_rewrite(map, val.dptr, val.dsize, av);
75056822Seric }
75156822Seric 
75256822Seric 
75356822Seric /*
75460089Seric **  DBM_MAP_STORE -- store a datum in the database
75556822Seric */
75656822Seric 
75760089Seric void
ndbm_map_store(map,lhs,rhs)75860089Seric ndbm_map_store(map, lhs, rhs)
75960089Seric 	register MAP *map;
76060089Seric 	char *lhs;
76160089Seric 	char *rhs;
76260089Seric {
76360089Seric 	datum key;
76460089Seric 	datum data;
76560089Seric 	int stat;
76660089Seric 
76760537Seric 	if (tTd(38, 12))
76868350Seric 		printf("ndbm_map_store(%s, %s, %s)\n",
76968350Seric 			map->map_mname, lhs, rhs);
77060089Seric 
77160089Seric 	key.dsize = strlen(lhs);
77260089Seric 	key.dptr = lhs;
77360089Seric 
77460089Seric 	data.dsize = strlen(rhs);
77560089Seric 	data.dptr = rhs;
77660089Seric 
77760207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
77860089Seric 	{
77960089Seric 		key.dsize++;
78060089Seric 		data.dsize++;
78160089Seric 	}
78260089Seric 
78360089Seric 	stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
78460089Seric 	if (stat > 0)
78560089Seric 	{
78668497Seric 		if (!bitset(MF_APPEND, map->map_mflags))
78768497Seric 			usrerr("050 Warning: duplicate alias name %s", lhs);
78868497Seric 		else
78968497Seric 		{
79068497Seric 			static char *buf = NULL;
79168497Seric 			static int bufsiz = 0;
79268879Seric 			auto int xstat;
79368497Seric 			datum old;
79468497Seric 
79568879Seric 			old.dptr = ndbm_map_lookup(map, key.dptr, NULL, &xstat);
79668497Seric 			if (old.dptr != NULL && *old.dptr != '\0')
79768497Seric 			{
79868497Seric 				old.dsize = strlen(old.dptr);
79968497Seric 				if (data.dsize + old.dsize + 2 > bufsiz)
80068497Seric 				{
80168497Seric 					if (buf != NULL)
80268497Seric 						(void) free(buf);
80368497Seric 					bufsiz = data.dsize + old.dsize + 2;
80468497Seric 					buf = xalloc(bufsiz);
80568497Seric 				}
80668497Seric 				sprintf(buf, "%s,%s", data.dptr, old.dptr);
80768497Seric 				data.dsize = data.dsize + old.dsize + 1;
80868497Seric 				data.dptr = buf;
80968497Seric 				if (tTd(38, 9))
81068497Seric 					printf("ndbm_map_store append=%s\n", data.dptr);
81168497Seric 			}
81268497Seric 		}
81360089Seric 		stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
81460089Seric 	}
81560089Seric 	if (stat != 0)
81660089Seric 		syserr("readaliases: dbm put (%s)", lhs);
81760089Seric }
81860089Seric 
81960089Seric 
82060089Seric /*
82160207Seric **  NDBM_MAP_CLOSE -- close the database
82260089Seric */
82360089Seric 
82460089Seric void
ndbm_map_close(map)82560089Seric ndbm_map_close(map)
82660089Seric 	register MAP  *map;
82760089Seric {
82866773Seric 	if (tTd(38, 9))
82968350Seric 		printf("ndbm_map_close(%s, %s, %x)\n",
83068350Seric 			map->map_mname, map->map_file, map->map_mflags);
83166773Seric 
83260207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
83360089Seric 	{
83464250Seric #ifdef NIS
83564075Seric 		bool inclnull;
83660089Seric 		char buf[200];
83760089Seric 
83864075Seric 		inclnull = bitset(MF_INCLNULL, map->map_mflags);
83964075Seric 		map->map_mflags &= ~MF_INCLNULL;
84064075Seric 
84169651Seric 		if (strstr(map->map_file, "/yp/") != NULL)
84269651Seric 		{
84369651Seric 			(void) sprintf(buf, "%010ld", curtime());
84469651Seric 			ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
84560089Seric 
84669651Seric 			(void) gethostname(buf, sizeof buf);
84769651Seric 			ndbm_map_store(map, "YP_MASTER_NAME", buf);
84869651Seric 		}
84964075Seric 
85064075Seric 		if (inclnull)
85164075Seric 			map->map_mflags |= MF_INCLNULL;
85260089Seric #endif
85360089Seric 
85460089Seric 		/* write out the distinguished alias */
85560089Seric 		ndbm_map_store(map, "@", "@");
85660089Seric 	}
85760089Seric 	dbm_close((DBM *) map->map_db1);
85860089Seric }
85960089Seric 
86060089Seric #endif
86160089Seric /*
86260582Seric **  NEWDB (Hash and BTree) Modules
86360089Seric */
86460089Seric 
86560089Seric #ifdef NEWDB
86660089Seric 
86760089Seric /*
86860582Seric **  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
86960582Seric **
87060582Seric **	These do rather bizarre locking.  If you can lock on open,
87160582Seric **	do that to avoid the condition of opening a database that
87260582Seric **	is being rebuilt.  If you don't, we'll try to fake it, but
87360582Seric **	there will be a race condition.  If opening for read-only,
87460582Seric **	we immediately release the lock to avoid freezing things up.
87560582Seric **	We really ought to hold the lock, but guarantee that we won't
87660582Seric **	be pokey about it.  That's hard to do.
87760089Seric */
87860089Seric 
87956822Seric bool
bt_map_open(map,mode)88060089Seric bt_map_open(map, mode)
88156822Seric 	MAP *map;
88260089Seric 	int mode;
88356822Seric {
88456822Seric 	DB *db;
88560228Seric 	int i;
88660582Seric 	int omode;
88764373Seric 	int fd;
88864284Seric 	struct stat st;
88968528Seric 	char buf[MAXNAME + 1];
89056822Seric 
89160537Seric 	if (tTd(38, 2))
89268350Seric 		printf("bt_map_open(%s, %s, %d)\n",
89368350Seric 			map->map_mname, map->map_file, mode);
89460089Seric 
89560582Seric 	omode = mode;
89660582Seric 	if (omode == O_RDWR)
89760582Seric 	{
89860582Seric 		omode |= O_CREAT|O_TRUNC;
89965830Seric #if defined(O_EXLOCK) && HASFLOCK
90060582Seric 		omode |= O_EXLOCK;
90166843Seric # if !OLD_NEWDB
90260582Seric 	}
90360582Seric 	else
90460582Seric 	{
90560582Seric 		omode |= O_SHLOCK;
90660582Seric # endif
90760582Seric #endif
90860582Seric 	}
90960207Seric 
91060228Seric 	(void) strcpy(buf, map->map_file);
91160228Seric 	i = strlen(buf);
91260228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
91360228Seric 		(void) strcat(buf, ".db");
91460582Seric 	db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
91556822Seric 	if (db == NULL)
91656822Seric 	{
91764718Seric #ifdef MAYBENEXTRELEASE
91864718Seric 		if (aliaswait(map, ".db", FALSE))
91964718Seric 			return TRUE;
92064718Seric #endif
92160207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
92256836Seric 			syserr("Cannot open BTREE database %s", map->map_file);
92356822Seric 		return FALSE;
92456822Seric 	}
92568350Seric #if !OLD_NEWDB
92664373Seric 	fd = db->fd(db);
92768778Seric # if defined(O_EXLOCK) && HASFLOCK
92868778Seric 	if (fd >= 0)
92968778Seric 	{
93068778Seric 		if (mode == O_RDONLY)
93168778Seric 			(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
93268778Seric 		else
93368778Seric 			map->map_mflags |= MF_LOCKED;
93468778Seric 	}
93568778Seric # else
93664373Seric 	if (mode == O_RDWR && fd >= 0)
93764388Seric 	{
93864388Seric 		if (lockfile(fd, map->map_file, ".db", LOCK_EX))
93964388Seric 			map->map_mflags |= MF_LOCKED;
94064388Seric 	}
94160582Seric # endif
94260582Seric #endif
94360585Seric 
94460585Seric 	/* try to make sure that at least the database header is on disk */
94560585Seric 	if (mode == O_RDWR)
94666843Seric #if OLD_NEWDB
94764373Seric 		(void) db->sync(db);
94864373Seric #else
94960585Seric 		(void) db->sync(db, 0);
95060585Seric 
95164373Seric 	if (fd >= 0 && fstat(fd, &st) >= 0)
95264284Seric 		map->map_mtime = st.st_mtime;
95364284Seric #endif
95464284Seric 
95560089Seric 	map->map_db2 = (void *) db;
95660207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
95764718Seric 		if (!aliaswait(map, ".db", TRUE))
95864718Seric 			return FALSE;
95956822Seric 	return TRUE;
96056822Seric }
96156822Seric 
96256822Seric 
96356822Seric /*
96456822Seric **  HASH_MAP_INIT -- HASH-style map initialization
96556822Seric */
96656822Seric 
96756822Seric bool
hash_map_open(map,mode)96860089Seric hash_map_open(map, mode)
96956822Seric 	MAP *map;
97060089Seric 	int mode;
97156822Seric {
97256822Seric 	DB *db;
97360228Seric 	int i;
97460582Seric 	int omode;
97564373Seric 	int fd;
97664284Seric 	struct stat st;
97768528Seric 	char buf[MAXNAME + 1];
97856822Seric 
97960537Seric 	if (tTd(38, 2))
98068350Seric 		printf("hash_map_open(%s, %s, %d)\n",
98168350Seric 			map->map_mname, map->map_file, mode);
98260089Seric 
98360582Seric 	omode = mode;
98460582Seric 	if (omode == O_RDWR)
98560582Seric 	{
98660582Seric 		omode |= O_CREAT|O_TRUNC;
98765830Seric #if defined(O_EXLOCK) && HASFLOCK
98860582Seric 		omode |= O_EXLOCK;
98966843Seric # if !OLD_NEWDB
99060582Seric 	}
99160582Seric 	else
99260582Seric 	{
99360582Seric 		omode |= O_SHLOCK;
99460582Seric # endif
99560582Seric #endif
99660582Seric 	}
99760207Seric 
99860228Seric 	(void) strcpy(buf, map->map_file);
99960228Seric 	i = strlen(buf);
100060228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
100160228Seric 		(void) strcat(buf, ".db");
100260582Seric 	db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
100356822Seric 	if (db == NULL)
100456822Seric 	{
100564718Seric #ifdef MAYBENEXTRELEASE
100664718Seric 		if (aliaswait(map, ".db", FALSE))
100764718Seric 			return TRUE;
100864718Seric #endif
100960207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
101056836Seric 			syserr("Cannot open HASH database %s", map->map_file);
101156822Seric 		return FALSE;
101256822Seric 	}
101368350Seric #if !OLD_NEWDB
101464373Seric 	fd = db->fd(db);
101568778Seric # if defined(O_EXLOCK) && HASFLOCK
101668778Seric 	if (fd >= 0)
101768778Seric 	{
101868778Seric 		if (mode == O_RDONLY)
101968778Seric 			(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
102068778Seric 		else
102168778Seric 			map->map_mflags |= MF_LOCKED;
102268778Seric 	}
102368778Seric # else
102464373Seric 	if (mode == O_RDWR && fd >= 0)
102564388Seric 	{
102664388Seric 		if (lockfile(fd, map->map_file, ".db", LOCK_EX))
102764388Seric 			map->map_mflags |= MF_LOCKED;
102864388Seric 	}
102960582Seric # endif
103060582Seric #endif
103160585Seric 
103260585Seric 	/* try to make sure that at least the database header is on disk */
103360585Seric 	if (mode == O_RDWR)
103466843Seric #if OLD_NEWDB
103564373Seric 		(void) db->sync(db);
103664373Seric #else
103760585Seric 		(void) db->sync(db, 0);
103860585Seric 
103964373Seric 	if (fd >= 0 && fstat(fd, &st) >= 0)
104064284Seric 		map->map_mtime = st.st_mtime;
104164284Seric #endif
104264284Seric 
104360089Seric 	map->map_db2 = (void *) db;
104460207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
104564718Seric 		if (!aliaswait(map, ".db", TRUE))
104664718Seric 			return FALSE;
104756822Seric 	return TRUE;
104856822Seric }
104956822Seric 
105056822Seric 
105156822Seric /*
105256822Seric **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
105356822Seric */
105456822Seric 
105556822Seric char *
db_map_lookup(map,name,av,statp)105660089Seric db_map_lookup(map, name, av, statp)
105756822Seric 	MAP *map;
105860089Seric 	char *name;
105956822Seric 	char **av;
106059084Seric 	int *statp;
106156822Seric {
106256822Seric 	DBT key, val;
106360422Seric 	register DB *db = (DB *) map->map_db2;
106460422Seric 	int st;
106560422Seric 	int saveerrno;
106664373Seric 	int fd;
106760089Seric 	char keybuf[MAXNAME + 1];
106856822Seric 
106960537Seric 	if (tTd(38, 20))
107068350Seric 		printf("db_map_lookup(%s, %s)\n",
107168350Seric 			map->map_mname, name);
107260089Seric 
107360089Seric 	key.size = strlen(name);
107460089Seric 	if (key.size > sizeof keybuf - 1)
107560089Seric 		key.size = sizeof keybuf - 1;
107660089Seric 	key.data = keybuf;
107760089Seric 	bcopy(name, keybuf, key.size + 1);
107860207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
107960089Seric 		makelower(keybuf);
108066843Seric #if !OLD_NEWDB
108164388Seric 	fd = db->fd(db);
108264388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
108364388Seric 		(void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH);
108460422Seric #endif
108563753Seric 	st = 1;
108663753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
108763753Seric 	{
108863753Seric 		st = db->get(db, &key, &val, 0);
108963753Seric 		if (st == 0)
109063753Seric 			map->map_mflags &= ~MF_TRY1NULL;
109163753Seric 	}
109263753Seric 	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
109363753Seric 	{
109463753Seric 		key.size++;
109563753Seric 		st = db->get(db, &key, &val, 0);
109663753Seric 		if (st == 0)
109763753Seric 			map->map_mflags &= ~MF_TRY0NULL;
109863753Seric 	}
109960422Seric 	saveerrno = errno;
110066843Seric #if !OLD_NEWDB
110164388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
110264373Seric 		(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
110360422Seric #endif
110460422Seric 	if (st != 0)
110560422Seric 	{
110660422Seric 		errno = saveerrno;
110760422Seric 		if (st < 0)
110860422Seric 			syserr("db_map_lookup: get (%s)", name);
110956822Seric 		return NULL;
111060422Seric 	}
111160207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
111263753Seric 		return map_rewrite(map, name, strlen(name), NULL);
111363753Seric 	else
111463753Seric 		return map_rewrite(map, val.data, val.size, av);
111556822Seric }
111656822Seric 
111760089Seric 
111860089Seric /*
111960089Seric **  DB_MAP_STORE -- store a datum in the NEWDB database
112056822Seric */
112156822Seric 
112260089Seric void
db_map_store(map,lhs,rhs)112360089Seric db_map_store(map, lhs, rhs)
112460089Seric 	register MAP *map;
112560089Seric 	char *lhs;
112660089Seric 	char *rhs;
112756822Seric {
112860089Seric 	int stat;
112960089Seric 	DBT key;
113060089Seric 	DBT data;
113160089Seric 	register DB *db = map->map_db2;
113256822Seric 
113360537Seric 	if (tTd(38, 20))
113468350Seric 		printf("db_map_store(%s, %s, %s)\n",
113568350Seric 			map->map_mname, lhs, rhs);
113660089Seric 
113760089Seric 	key.size = strlen(lhs);
113860089Seric 	key.data = lhs;
113960089Seric 
114060089Seric 	data.size = strlen(rhs);
114160089Seric 	data.data = rhs;
114260089Seric 
114360207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
114456822Seric 	{
114560089Seric 		key.size++;
114660089Seric 		data.size++;
114760089Seric 	}
114856836Seric 
114960089Seric 	stat = db->put(db, &key, &data, R_NOOVERWRITE);
115060089Seric 	if (stat > 0)
115160089Seric 	{
115268497Seric 		if (!bitset(MF_APPEND, map->map_mflags))
115368497Seric 			usrerr("050 Warning: duplicate alias name %s", lhs);
115468497Seric 		else
115568497Seric 		{
115668497Seric 			static char *buf = NULL;
115768497Seric 			static int bufsiz = 0;
115868497Seric 			DBT old;
115968497Seric 
116068497Seric 			old.data = db_map_lookup(map, key.data, NULL, &stat);
116168497Seric 			if (old.data != NULL)
116268497Seric 			{
116368497Seric 				old.size = strlen(old.data);
116468497Seric 				if (data.size + old.size + 2 > bufsiz)
116568497Seric 				{
116668497Seric 					if (buf != NULL)
116768497Seric 						(void) free(buf);
116868497Seric 					bufsiz = data.size + old.size + 2;
116968497Seric 					buf = xalloc(bufsiz);
117068497Seric 				}
117168497Seric 				sprintf(buf, "%s,%s", data.data, old.data);
117268497Seric 				data.size = data.size + old.size + 1;
117368497Seric 				data.data = buf;
117468497Seric 				if (tTd(38, 9))
117568497Seric 					printf("db_map_store append=%s\n", data.data);
117668497Seric 			}
117768497Seric 		}
117860089Seric 		stat = db->put(db, &key, &data, 0);
117960089Seric 	}
118060089Seric 	if (stat != 0)
118160089Seric 		syserr("readaliases: db put (%s)", lhs);
118260089Seric }
118356836Seric 
118456847Seric 
118560089Seric /*
118660089Seric **  DB_MAP_CLOSE -- add distinguished entries and close the database
118760089Seric */
118860089Seric 
118960089Seric void
db_map_close(map)119060089Seric db_map_close(map)
119160089Seric 	MAP *map;
119260089Seric {
119360089Seric 	register DB *db = map->map_db2;
119460089Seric 
119560537Seric 	if (tTd(38, 9))
119668350Seric 		printf("db_map_close(%s, %s, %x)\n",
119768350Seric 			map->map_mname, map->map_file, map->map_mflags);
119860089Seric 
119960207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
120058804Seric 	{
120160089Seric 		/* write out the distinguished alias */
120260089Seric 		db_map_store(map, "@", "@");
120358804Seric 	}
120458963Seric 
120560089Seric 	if (db->close(db) != 0)
120660089Seric 		syserr("readaliases: db close failure");
120756822Seric }
120857208Seric 
120960089Seric #endif
121060089Seric /*
121160089Seric **  NIS Modules
121260089Seric */
121360089Seric 
121460089Seric # ifdef NIS
121560089Seric 
121664369Seric # ifndef YPERR_BUSY
121764369Seric #  define YPERR_BUSY	16
121864369Seric # endif
121964369Seric 
122057208Seric /*
122160089Seric **  NIS_MAP_OPEN -- open DBM map
122257208Seric */
122357208Seric 
122457208Seric bool
nis_map_open(map,mode)122560089Seric nis_map_open(map, mode)
122657208Seric 	MAP *map;
122760089Seric 	int mode;
122857208Seric {
122957216Seric 	int yperr;
123060215Seric 	register char *p;
123160215Seric 	auto char *vp;
123260215Seric 	auto int vsize;
123357216Seric 
123460537Seric 	if (tTd(38, 2))
123568350Seric 		printf("nis_map_open(%s, %s)\n",
123668350Seric 			map->map_mname, map->map_file);
123760089Seric 
123860207Seric 	if (mode != O_RDONLY)
123960207Seric 	{
124064650Seric 		/* issue a pseudo-error message */
124164650Seric #ifdef ENOSYS
124264650Seric 		errno = ENOSYS;
124364650Seric #else
124464650Seric # ifdef EFTYPE
124564650Seric 		errno = EFTYPE;
124664650Seric # else
124764650Seric 		errno = ENXIO;
124864650Seric # endif
124964650Seric #endif
125060207Seric 		return FALSE;
125160207Seric 	}
125260207Seric 
125360089Seric 	p = strchr(map->map_file, '@');
125460089Seric 	if (p != NULL)
125560089Seric 	{
125660089Seric 		*p++ = '\0';
125760089Seric 		if (*p != '\0')
125860089Seric 			map->map_domain = p;
125960089Seric 	}
126060215Seric 
126160089Seric 	if (*map->map_file == '\0')
126260089Seric 		map->map_file = "mail.aliases";
126360089Seric 
126466157Seric 	if (map->map_domain == NULL)
126566157Seric 	{
126666157Seric 		yperr = yp_get_default_domain(&map->map_domain);
126766157Seric 		if (yperr != 0)
126866157Seric 		{
126966744Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
127068350Seric 				syserr("421 NIS map %s specified, but NIS not running\n",
127166744Seric 					map->map_file);
127266157Seric 			return FALSE;
127366157Seric 		}
127466157Seric 	}
127566157Seric 
127660215Seric 	/* check to see if this map actually exists */
127760089Seric 	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
127860089Seric 			&vp, &vsize);
127960537Seric 	if (tTd(38, 10))
128060089Seric 		printf("nis_map_open: yp_match(%s, %s) => %s\n",
128160089Seric 			map->map_domain, map->map_file, yperr_string(yperr));
128260089Seric 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
128368350Seric 	{
128468350Seric 		if (!bitset(MF_ALIAS, map->map_mflags) ||
128568350Seric 		    aliaswait(map, NULL, TRUE))
128668350Seric 			return TRUE;
128768350Seric 	}
128860215Seric 
128960215Seric 	if (!bitset(MF_OPTIONAL, map->map_mflags))
129068735Seric 	{
129168735Seric 		syserr("421 Cannot bind to map %s in domain %s: %s",
129268735Seric 			map->map_file, map->map_domain, yperr_string(yperr));
129368735Seric 	}
129460215Seric 
129560089Seric 	return FALSE;
129660089Seric }
129760089Seric 
129860089Seric 
129960089Seric /*
130057208Seric **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
130157208Seric */
130257208Seric 
130357208Seric char *
nis_map_lookup(map,name,av,statp)130460089Seric nis_map_lookup(map, name, av, statp)
130557208Seric 	MAP *map;
130660089Seric 	char *name;
130757208Seric 	char **av;
130859084Seric 	int *statp;
130957208Seric {
131057208Seric 	char *vp;
131157642Seric 	auto int vsize;
131259274Seric 	int buflen;
131360215Seric 	int yperr;
131460089Seric 	char keybuf[MAXNAME + 1];
131557208Seric 
131660537Seric 	if (tTd(38, 20))
131768350Seric 		printf("nis_map_lookup(%s, %s)\n",
131868350Seric 			map->map_mname, name);
131960089Seric 
132060089Seric 	buflen = strlen(name);
132160089Seric 	if (buflen > sizeof keybuf - 1)
132260089Seric 		buflen = sizeof keybuf - 1;
132360089Seric 	bcopy(name, keybuf, buflen + 1);
132460207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
132560089Seric 		makelower(keybuf);
132663753Seric 	yperr = YPERR_KEY;
132763753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
132863753Seric 	{
132963753Seric 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
133063753Seric 			     &vp, &vsize);
133163753Seric 		if (yperr == 0)
133263753Seric 			map->map_mflags &= ~MF_TRY1NULL;
133363753Seric 	}
133463753Seric 	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
133563753Seric 	{
133659274Seric 		buflen++;
133763753Seric 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
133863753Seric 			     &vp, &vsize);
133963753Seric 		if (yperr == 0)
134063753Seric 			map->map_mflags &= ~MF_TRY0NULL;
134163753Seric 	}
134260089Seric 	if (yperr != 0)
134360089Seric 	{
134460089Seric 		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
134560215Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
134657208Seric 		return NULL;
134760089Seric 	}
134860207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
134963753Seric 		return map_rewrite(map, name, strlen(name), NULL);
135063753Seric 	else
135163753Seric 		return map_rewrite(map, vp, vsize, av);
135257208Seric }
135357208Seric 
135469401Seric 
135569401Seric /*
135669401Seric **  NIS_GETCANONNAME -- look up canonical name in NIS
135769401Seric */
135869401Seric 
135969401Seric bool
nis_getcanonname(name,hbsize,statp)136069401Seric nis_getcanonname(name, hbsize, statp)
136169401Seric 	char *name;
136269401Seric 	int hbsize;
136369401Seric 	int *statp;
136469401Seric {
136569401Seric 	char *vp;
136669401Seric 	auto int vsize;
136769401Seric 	int keylen;
136869401Seric 	int yperr;
136969401Seric 	static bool try0null = TRUE;
137069401Seric 	static bool try1null = TRUE;
137169401Seric 	static char *yp_domain = NULL;
137269748Seric 	char *domain;
137369401Seric 	char host_record[MAXLINE];
137469833Seric 	char cbuf[MAXNAME];
137569780Seric 	char nbuf[MAXNAME + 1];
137669401Seric 	extern char *get_column();
137769401Seric 
137869401Seric 	if (tTd(38, 20))
137969401Seric 		printf("nis_getcanonname(%s)\n", name);
138069401Seric 
138169780Seric 	if (strlen(name) >= sizeof nbuf)
138269780Seric 	{
138369780Seric 		*statp = EX_UNAVAILABLE;
138469780Seric 		return FALSE;
138569780Seric 	}
138669780Seric 	(void) strcpy(nbuf, name);
138769780Seric 	shorten_hostname(nbuf);
138869401Seric 
138969401Seric 	/* we only accept single token search key */
139069780Seric 	if (strchr(nbuf, '.'))
139169401Seric 	{
139269401Seric 		*statp = EX_NOHOST;
139369401Seric 		return FALSE;
139469401Seric 	}
139569401Seric 
139669780Seric 	keylen = strlen(nbuf);
139769401Seric 
139869401Seric 	if (yp_domain == NULL)
139969401Seric 		yp_get_default_domain(&yp_domain);
140069780Seric 	makelower(nbuf);
140169401Seric 	yperr = YPERR_KEY;
140269401Seric 	if (try0null)
140369401Seric 	{
140469780Seric 		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
140569401Seric 			     &vp, &vsize);
140669401Seric 		if (yperr == 0)
140769401Seric 			try1null = FALSE;
140869401Seric 	}
140969401Seric 	if (yperr == YPERR_KEY && try1null)
141069401Seric 	{
141169401Seric 		keylen++;
141269780Seric 		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
141369401Seric 			     &vp, &vsize);
141469401Seric 		if (yperr == 0)
141569401Seric 			try0null = FALSE;
141669401Seric 	}
141769401Seric 	if (yperr != 0)
141869401Seric 	{
141969401Seric 		if (yperr == YPERR_KEY)
142069401Seric 			*statp = EX_NOHOST;
142169401Seric 		else if (yperr == YPERR_BUSY)
142269401Seric 			*statp = EX_TEMPFAIL;
142369401Seric 		else
142469401Seric 			*statp = EX_UNAVAILABLE;
142569401Seric 		return FALSE;
142669401Seric 	}
142769401Seric 	strncpy(host_record, vp, vsize);
142869401Seric 	host_record[vsize] = '\0';
142969663Seric 	if (tTd(38, 44))
143069663Seric 		printf("got record `%s'\n", host_record);
143169833Seric 	if (!extract_canonname(nbuf, host_record, cbuf))
143269401Seric 	{
143369401Seric 		/* this should not happen, but.... */
143469401Seric 		*statp = EX_NOHOST;
143569401Seric 		return FALSE;
143669401Seric 	}
143769833Seric 	if (hbsize < strlen(cbuf))
143869401Seric 	{
143969833Seric 		*statp = EX_UNAVAILABLE;
144069833Seric 		return FALSE;
144169703Seric 	}
144269833Seric 	strcpy(name, cbuf);
144369833Seric 	*statp = EX_OK;
144469833Seric 	return TRUE;
144569401Seric }
144669401Seric 
144768350Seric #endif
144868350Seric /*
144968350Seric **  NISPLUS Modules
145068350Seric **
145168350Seric **	This code donated by Sun Microsystems.
145268350Seric */
145367848Seric 
145468350Seric #ifdef NISPLUS
145568350Seric 
145668350Seric #undef NIS /* symbol conflict in nis.h */
145768350Seric #include <rpcsvc/nis.h>
145868350Seric #include <rpcsvc/nislib.h>
145968350Seric 
146068350Seric #define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
146168350Seric #define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
146268350Seric #define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
146368350Seric #define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
146468350Seric 
146567848Seric /*
146668350Seric **  NISPLUS_MAP_OPEN -- open nisplus table
146767848Seric */
146867848Seric 
146968350Seric bool
nisplus_map_open(map,mode)147068350Seric nisplus_map_open(map, mode)
147167848Seric 	MAP *map;
147268350Seric 	int mode;
147367848Seric {
147468350Seric 	register char *p;
147568350Seric 	char qbuf[MAXLINE + NIS_MAXNAMELEN];
147668350Seric 	nis_result *res = NULL;
147768350Seric 	u_int objs_len;
147868350Seric 	nis_object *obj_ptr;
147968350Seric 	int retry_cnt, max_col, i;
148068350Seric 
148168350Seric 	if (tTd(38, 2))
148268350Seric 		printf("nisplus_map_open(%s, %s, %d)\n",
148368350Seric 			map->map_mname, map->map_file, mode);
148468350Seric 
148568350Seric 	if (mode != O_RDONLY)
148668350Seric 	{
148768350Seric 		errno = ENODEV;
148868350Seric 		return FALSE;
148968350Seric 	}
149068350Seric 
149168350Seric 	if (*map->map_file == '\0')
149268350Seric 		map->map_file = "mail_aliases.org_dir";
149368350Seric 
149468350Seric 	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
149568350Seric 	{
149668350Seric 		/* set default NISPLUS Domain to $m */
149768350Seric 		extern char *nisplus_default_domain();
149868350Seric 
149968350Seric 		map->map_domain = newstr(nisplus_default_domain());
150068350Seric 		if (tTd(38, 2))
150168350Seric 			printf("nisplus_map_open(%s): using domain %s\n",
150268350Seric 				 map->map_file, map->map_domain);
150368350Seric 	}
150468350Seric 	if (!PARTIAL_NAME(map->map_file))
150568350Seric 		map->map_domain = newstr("");
150668350Seric 
150768350Seric 	/* check to see if this map actually exists */
150868350Seric 	if (PARTIAL_NAME(map->map_file))
150968350Seric 		sprintf(qbuf, "%s.%s", map->map_file, map->map_domain);
151068350Seric 	else
151168350Seric 		strcpy(qbuf, map->map_file);
151268350Seric 
151368350Seric 	retry_cnt = 0;
151468350Seric 	while (res == NULL || res->status != NIS_SUCCESS)
151568350Seric 	{
151668350Seric 		res = nis_lookup(qbuf, FOLLOW_LINKS);
151768350Seric 		switch (res->status)
151868350Seric 		{
151968350Seric 		  case NIS_SUCCESS:
152068350Seric 		  case NIS_TRYAGAIN:
152168350Seric 		  case NIS_RPCERROR:
152268350Seric 		  case NIS_NAMEUNREACHABLE:
152368350Seric 			break;
152468350Seric 
152568350Seric 		  default:		/* all other nisplus errors */
152668350Seric #if 0
152768350Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
152868350Seric 				syserr("421 Cannot find table %s.%s: %s",
152968350Seric 					map->map_file, map->map_domain,
153068350Seric 					nis_sperrno(res->status));
153168350Seric #endif
153268350Seric 			errno = EBADR;
153368350Seric 			return FALSE;
153468350Seric 		}
153568350Seric 		sleep(2);		/* try not to overwhelm hosed server */
153668350Seric 		if (retry_cnt++ > 4)
153768350Seric 		{
153868350Seric 			errno = EBADR;
153968350Seric 			return FALSE;
154068350Seric 		}
154168350Seric 	}
154268350Seric 
154368350Seric 	if (NIS_RES_NUMOBJ(res) != 1 ||
154468350Seric 	    (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
154568350Seric 	{
154668350Seric 		if (tTd(38, 10))
154768350Seric 			printf("nisplus_map_open: %s is not a table\n", qbuf);
154868350Seric #if 0
154968350Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
155068350Seric 			syserr("421 %s.%s: %s is not a table",
155168350Seric 				map->map_file, map->map_domain,
155268350Seric 				nis_sperrno(res->status));
155368350Seric #endif
155468350Seric 		errno = EBADR;
155568350Seric 		return FALSE;
155668350Seric 	}
155768350Seric 	/* default key column is column 0 */
155868350Seric 	if (map->map_keycolnm == NULL)
155968350Seric 		map->map_keycolnm = newstr(COL_NAME(res,0));
156068350Seric 
156168350Seric 	max_col = COL_MAX(res);
156268350Seric 
156368350Seric 	/* verify the key column exist */
156468350Seric 	for (i=0; i< max_col; i++)
156568350Seric 	{
156668350Seric 		if (!strcmp(map->map_keycolnm, COL_NAME(res,i)))
156768350Seric 			break;
156868350Seric 	}
156968350Seric 	if (i == max_col)
157068350Seric 	{
157168350Seric 		if (tTd(38, 2))
157268350Seric 			printf("nisplus_map_open(%s): can not find key column %s\n",
157368350Seric 				map->map_file, map->map_keycolnm);
157468350Seric 		errno = EBADR;
157568350Seric 		return FALSE;
157668350Seric 	}
157768350Seric 
157868350Seric 	/* default value column is the last column */
157968350Seric 	if (map->map_valcolnm == NULL)
158068350Seric 	{
158168350Seric 		map->map_valcolno = max_col - 1;
158268350Seric 		return TRUE;
158368350Seric 	}
158468350Seric 
158568350Seric 	for (i=0; i< max_col; i++)
158668350Seric 	{
158768350Seric 		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
158868350Seric 		{
158968350Seric 			map->map_valcolno = i;
159068350Seric 			return TRUE;
159168350Seric 		}
159268350Seric 	}
159368350Seric 
159468350Seric 	if (tTd(38, 2))
159568350Seric 		printf("nisplus_map_open(%s): can not find column %s\n",
159668350Seric 			 map->map_file, map->map_keycolnm);
159768350Seric 	errno = EBADR;
159868350Seric 	return FALSE;
159967848Seric }
160067848Seric 
160167848Seric 
160267848Seric /*
160368350Seric **  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
160467848Seric */
160567848Seric 
160668350Seric char *
nisplus_map_lookup(map,name,av,statp)160768350Seric nisplus_map_lookup(map, name, av, statp)
160867848Seric 	MAP *map;
160968350Seric 	char *name;
161068350Seric 	char **av;
161168350Seric 	int *statp;
161267848Seric {
161368350Seric 	char *vp;
161468350Seric 	auto int vsize;
161568350Seric 	int buflen;
161668350Seric 	char search_key[MAXNAME + 1];
161768350Seric 	char qbuf[MAXLINE + NIS_MAXNAMELEN];
161868350Seric 	nis_result *result;
161968350Seric 
162068350Seric 	if (tTd(38, 20))
162168350Seric 		printf("nisplus_map_lookup(%s, %s)\n",
162268350Seric 			map->map_mname, name);
162368350Seric 
162468350Seric 	if (!bitset(MF_OPEN, map->map_mflags))
162568350Seric 	{
162668350Seric 		if (nisplus_map_open(map, O_RDONLY))
162768350Seric 			map->map_mflags |= MF_OPEN;
162868350Seric 		else
162968350Seric 		{
163068350Seric 			*statp = EX_UNAVAILABLE;
163168350Seric 			return NULL;
163268350Seric 		}
163368350Seric 	}
163468350Seric 
163568350Seric 	buflen = strlen(name);
163668350Seric 	if (buflen > sizeof search_key - 1)
163768350Seric 		buflen = sizeof search_key - 1;
163868350Seric 	bcopy(name, search_key, buflen + 1);
163968350Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
164068350Seric 		makelower(search_key);
164168350Seric 
164268350Seric 	/* construct the query */
164368350Seric 	if (PARTIAL_NAME(map->map_file))
164468350Seric 		sprintf(qbuf, "[%s=%s],%s.%s", map->map_keycolnm,
164568350Seric 			search_key, map->map_file, map->map_domain);
164668350Seric 	else
164768350Seric 		sprintf(qbuf, "[%s=%s],%s", map->map_keycolnm,
164868350Seric 			search_key, map->map_file);
164968350Seric 
165068350Seric 	if (tTd(38, 20))
165168350Seric 		printf("qbuf=%s\n", qbuf);
165268350Seric 	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
165368350Seric 	if (result->status == NIS_SUCCESS)
165468350Seric 	{
165568350Seric 		int count;
165668350Seric 		char *str;
165768350Seric 
165868350Seric 		if ((count = NIS_RES_NUMOBJ(result)) != 1)
165968350Seric 		{
166068350Seric 			if (LogLevel > 10)
166168350Seric 				syslog(LOG_WARNING,
166268350Seric 				  "%s:Lookup error, expected 1 entry, got (%d)",
166368350Seric 				    map->map_file, count);
166468350Seric 
166568350Seric 			/* ignore second entry */
166668350Seric 			if (tTd(38, 20))
166768350Seric 				printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
166868350Seric 					name, count);
166968350Seric 		}
167068350Seric 
167168350Seric 		vp = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
167268350Seric 		/* set the length of the result */
167368350Seric 		if (vp == NULL)
167468350Seric 			vp = "";
167568350Seric 		vsize = strlen(vp);
167668350Seric 		if (tTd(38, 20))
167768350Seric 			printf("nisplus_map_lookup(%s), found %s\n",
167868350Seric 				name, vp);
167968350Seric 		if (bitset(MF_MATCHONLY, map->map_mflags))
168068350Seric 			str = map_rewrite(map, name, strlen(name), NULL);
168168350Seric 		else
168268350Seric 			str = map_rewrite(map, vp, vsize, av);
168368350Seric 		nis_freeresult(result);
168468350Seric #ifdef MAP_EXIT_STAT
168568350Seric 		*statp = EX_OK;
168668350Seric #endif
168768350Seric 		return str;
168868350Seric 	}
168968350Seric 	else
169068350Seric 	{
169168350Seric #ifdef MAP_EXIT_STAT
169268350Seric 		if (result->status == NIS_NOTFOUND)
169368350Seric 			*statp = EX_NOTFOUND;
169468350Seric 		else if (result->status == NIS_TRYAGAIN)
169568350Seric 			*statp = EX_TEMPFAIL;
169668350Seric 		else
169768350Seric 		{
169868350Seric 			*statp = EX_UNAVAILABLE;
169968350Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
170068350Seric 		}
170168350Seric #else
170268350Seric 		if ((result->status != NIS_NOTFOUND) &&
170368350Seric 		    (result->status != NIS_TRYAGAIN))
170468350Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
170568350Seric #endif
170668350Seric 	}
170768350Seric 	if (tTd(38, 20))
170868350Seric 		printf("nisplus_map_lookup(%s), failed\n", name);
170968350Seric 	nis_freeresult(result);
171068350Seric 	return NULL;
171167848Seric }
171267848Seric 
171368350Seric 
171469401Seric 
171569401Seric /*
171669401Seric **  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
171769401Seric */
171869401Seric 
171969401Seric bool
nisplus_getcanonname(name,hbsize,statp)172069401Seric nisplus_getcanonname(name, hbsize, statp)
172169401Seric 	char *name;
172269401Seric 	int hbsize;
172369401Seric 	int *statp;
172469401Seric {
172569401Seric 	char *vp;
172669401Seric 	auto int vsize;
172769401Seric 	int buflen;
172869401Seric 	nis_result *result;
172969401Seric 	char *p;
173069401Seric 	int len;
173169780Seric 	char nbuf[MAXNAME + 1];
173269780Seric 	char qbuf[MAXLINE + NIS_MAXNAMELEN];
173369401Seric 
173469780Seric 	if (strlen(name) >= sizeof nbuf)
173569780Seric 	{
173669780Seric 		*statp = EX_UNAVAILABLE;
173769780Seric 		return FALSE;
173869780Seric 	}
173969780Seric 	(void) strcpy(nbuf, name);
174069780Seric 	shorten_hostname(nbuf);
174169401Seric 
174269780Seric 	p = strchr(nbuf, '.');
174369401Seric 	if (p == NULL)
174469401Seric 	{
174569401Seric 		/* single token */
174669780Seric 		sprintf(qbuf, "[name=%s],hosts.org_dir", nbuf);
174769401Seric 	}
174869401Seric 	else if (p[1] != '\0')
174969401Seric 	{
175069780Seric 		/* multi token -- take only first token in nbuf */
175169401Seric 		*p = '\0';
175269780Seric 		sprintf(qbuf, "[name=%s],hosts.org_dir.%s", nbuf, &p[1]);
175369401Seric 	}
175469401Seric 	else
175569401Seric 	{
175669401Seric 		*statp = EX_NOHOST;
175769401Seric 		return FALSE;
175869401Seric 	}
175969401Seric 
176069401Seric 	if (tTd(38, 20))
176169478Seric 		printf("\nnisplus_getcanoname(%s), qbuf=%s\n",
176269780Seric 			 name, qbuf);
176369401Seric 
176469780Seric 	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
176569401Seric 		NULL, NULL);
176669401Seric 
176769401Seric 	if (result->status == NIS_SUCCESS)
176869401Seric 	{
176969401Seric 		int count;
177069401Seric 		char *str;
177169401Seric 		char *domain;
177269401Seric 
177369401Seric 		if ((count = NIS_RES_NUMOBJ(result)) != 1)
177469401Seric 		{
177569401Seric #ifdef LOG
177669401Seric 			if (LogLevel > 10)
177769401Seric 				syslog(LOG_WARNING,
177869401Seric 				       "nisplus_getcanonname: Lookup error, expected 1 entry, got (%d)",
177969401Seric 				       count);
178069401Seric #endif
178169401Seric 
178269401Seric 			/* ignore second entry */
178369401Seric 			if (tTd(38, 20))
178469401Seric 				printf("nisplus_getcanoname(%s), got %d entries, addtional entries ignores\n", name);
178569401Seric 		}
178669401Seric 
178769401Seric 		if (tTd(38, 20))
178869401Seric 			printf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
178969401Seric 			       name, (NIS_RES_OBJECT(result))->zo_domain);
179069401Seric 
179169401Seric 
179269401Seric 		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
179369401Seric 		vsize = strlen(vp);
179469401Seric 		if (tTd(38, 20))
179569401Seric 			printf("nisplus_getcanonname(%s), found %s\n",
179669401Seric 				name, vp);
179769703Seric 		if (strchr(vp, '.') != NULL)
179869703Seric 		{
179969636Seric 			domain = "";
180069703Seric 		}
180169703Seric 		else
180269703Seric 		{
180369703Seric 			domain = macvalue('m', CurEnv);
180469703Seric 			if (domain == NULL)
180569703Seric 				domain = "";
180669703Seric 		}
180769636Seric 		if (hbsize > vsize + (int) strlen(domain) + 1)
180869401Seric 		{
180969636Seric 			if (domain[0] == '\0')
181069636Seric 				strcpy(name, vp);
181169636Seric 			else
181269636Seric 				sprintf(name, "%s.%s", vp, domain);
181369401Seric 			*statp = EX_OK;
181469401Seric 		}
181569401Seric 		else
181669401Seric 			*statp = EX_NOHOST;
181769401Seric 		nis_freeresult(result);
181869401Seric 		return TRUE;
181969401Seric 	}
182069401Seric 	else
182169401Seric 	{
182269401Seric 		if (result->status == NIS_NOTFOUND)
182369401Seric 			*statp = EX_NOHOST;
182469401Seric 		else if (result->status == NIS_TRYAGAIN)
182569401Seric 			*statp = EX_TEMPFAIL;
182669401Seric 		else
182769401Seric 			*statp = EX_UNAVAILABLE;
182869401Seric 	}
182969401Seric 	if (tTd(38, 20))
183069401Seric 		printf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
183169401Seric 			name, result->status, *statp);
183269401Seric 	nis_freeresult(result);
183369401Seric 	return FALSE;
183469401Seric }
183569401Seric 
183669401Seric 
183768350Seric char *
nisplus_default_domain()183868350Seric nisplus_default_domain()
183968350Seric {
184068528Seric 	static char default_domain[MAXNAME + 1] = "";
184168350Seric 	char *p;
184268350Seric 
184368350Seric 	if (default_domain[0] != '\0')
184468350Seric 		return(default_domain);
184568350Seric 
184668458Seric 	p = nis_local_directory();
184768350Seric 	strcpy(default_domain, p);
184868458Seric 	return default_domain;
184968350Seric }
185068350Seric 
185168350Seric #endif /* NISPLUS */
185267848Seric /*
185368350Seric **  HESIOD Modules
185468350Seric */
185568350Seric 
185668350Seric #ifdef HESIOD
185768350Seric 
185868350Seric #include <hesiod.h>
185968350Seric 
186068350Seric char *
hes_map_lookup(map,name,av,statp)186168350Seric hes_map_lookup(map, name, av, statp)
186268350Seric         MAP *map;
186368350Seric         char *name;
186468350Seric         char **av;
186568350Seric         int *statp;
186668350Seric {
186768350Seric 	char **hp;
186868350Seric 
186968350Seric 	if (tTd(38, 20))
187068350Seric 		printf("hes_map_lookup(%s, %s)\n", map->map_file, name);
187168350Seric 
187269688Seric 	if (name[0] == '\\')
187369688Seric 	{
187469688Seric 		char *np;
187569688Seric 		int nl;
187669688Seric 		char nbuf[MAXNAME];
187769688Seric 
187869688Seric 		nl = strlen(name);
187969688Seric 		if (nl < sizeof nbuf - 1)
188069688Seric 			np = nbuf;
188169688Seric 		else
188269688Seric 			np = xalloc(strlen(name) + 2);
188369688Seric 		np[0] = '\\';
188469688Seric 		strcpy(&np[1], name);
188569688Seric 		hp = hes_resolve(np, map->map_file);
188669688Seric 		if (np != nbuf)
188769688Seric 			free(np);
188869688Seric 	}
188969688Seric 	else
189069688Seric 	{
189169688Seric 		hp = hes_resolve(name, map->map_file);
189269688Seric 	}
189369623Seric 	if (hp == NULL || hp[0] == NULL)
189468350Seric 		return NULL;
189568350Seric 
189669623Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
189769623Seric 		return map_rewrite(map, name, strlen(name), NULL);
189869623Seric 	else
189969623Seric 		return map_rewrite(map, hp[0], strlen(hp[0]), av);
190068350Seric }
190168350Seric 
190268350Seric #endif
190368350Seric /*
190468350Seric **  NeXT NETINFO Modules
190568350Seric */
190668350Seric 
190769881Seric #if NETINFO
190868350Seric 
190968350Seric #define NETINFO_DEFAULT_DIR		"/aliases"
191068350Seric #define NETINFO_DEFAULT_PROPERTY	"members"
191168350Seric 
191268350Seric 
191368350Seric /*
191468350Seric **  NI_MAP_OPEN -- open NetInfo Aliases
191568350Seric */
191668350Seric 
191768350Seric bool
ni_map_open(map,mode)191868350Seric ni_map_open(map, mode)
191968350Seric 	MAP *map;
192068350Seric 	int mode;
192168350Seric {
192268350Seric 	char *p;
192368350Seric 
192468350Seric 	if (tTd(38, 20))
192568350Seric 		printf("ni_map_open: %s\n", map->map_file);
192668350Seric 
192768350Seric 	if (*map->map_file == '\0')
192868350Seric 		map->map_file = NETINFO_DEFAULT_DIR;
192968350Seric 
193068350Seric 	if (map->map_valcolnm == NULL)
193168350Seric 		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
193268350Seric 
193368350Seric 	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
193468350Seric 		map->map_coldelim = ',';
193568350Seric 
193668350Seric 	return TRUE;
193768350Seric }
193868350Seric 
193968350Seric 
194068350Seric /*
194168350Seric **  NI_MAP_LOOKUP -- look up a datum in NetInfo
194268350Seric */
194368350Seric 
194468350Seric char *
ni_map_lookup(map,name,av,statp)194568350Seric ni_map_lookup(map, name, av, statp)
194668350Seric 	MAP *map;
194768350Seric 	char *name;
194868350Seric 	char **av;
194968350Seric 	int *statp;
195068350Seric {
195168350Seric 	char *res;
195268350Seric 	char *propval;
195368350Seric 	extern char *ni_propval();
195468350Seric 
195568350Seric 	if (tTd(38, 20))
195668350Seric 		printf("ni_map_lookup(%s, %s)\n",
195768350Seric 			map->map_mname, name);
195868350Seric 
195968350Seric 	propval = ni_propval(map->map_file, map->map_keycolnm, name,
196068350Seric 			     map->map_valcolnm, map->map_coldelim);
196168350Seric 
196268350Seric 	if (propval == NULL)
196368350Seric 		return NULL;
196468350Seric 
196568350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
196668350Seric 		res = map_rewrite(map, name, strlen(name), NULL);
196768350Seric 	else
196868350Seric 		res = map_rewrite(map, propval, strlen(propval), av);
196968350Seric 	free(propval);
197068350Seric 	return res;
197168350Seric }
197268350Seric 
197368350Seric #endif
197468350Seric /*
197568350Seric **  TEXT (unindexed text file) Modules
197668350Seric **
197768350Seric **	This code donated by Sun Microsystems.
197868350Seric */
197968350Seric 
198068350Seric 
198168350Seric /*
198268350Seric **  TEXT_MAP_OPEN -- open text table
198368350Seric */
198468350Seric 
198568350Seric bool
text_map_open(map,mode)198668350Seric text_map_open(map, mode)
198768350Seric 	MAP *map;
198868350Seric 	int mode;
198968350Seric {
199068350Seric 	struct stat sbuf;
199168350Seric 
199268350Seric 	if (tTd(38, 2))
199368350Seric 		printf("text_map_open(%s, %s, %d)\n",
199468350Seric 			map->map_mname, map->map_file, mode);
199568350Seric 
199668350Seric 	if (mode != O_RDONLY)
199768350Seric 	{
199868350Seric 		errno = ENODEV;
199968350Seric 		return FALSE;
200068350Seric 	}
200168350Seric 
200268350Seric 	if (*map->map_file == '\0')
200368350Seric 	{
200468350Seric 		if (tTd(38, 2))
200568350Seric 			printf("text_map_open: file name required\n");
200668350Seric 		return FALSE;
200768350Seric 	}
200868350Seric 
200968350Seric 	if (map->map_file[0] != '/')
201068350Seric 	{
201168350Seric 		if (tTd(38, 2))
201268350Seric 			printf("text_map_open(%s): file name must be fully qualified\n",
201368350Seric 				map->map_file);
201468350Seric 		return FALSE;
201568350Seric 	}
201668350Seric 	/* check to see if this map actually accessable */
201768350Seric 	if (access(map->map_file, R_OK) <0)
201868350Seric 		return FALSE;
201968350Seric 
202068350Seric 	/* check to see if this map actually exist */
202168350Seric 	if (stat(map->map_file, &sbuf) <0)
202268350Seric 	{
202368350Seric 		if (tTd(38, 2))
202468350Seric 			printf("text_map_open(%s): can not stat %s\n",
202568350Seric 				map->map_file, map->map_file);
202668350Seric 		return FALSE;
202768350Seric 	}
202868350Seric 
202968350Seric 	if (!S_ISREG(sbuf.st_mode))
203068350Seric 	{
203168350Seric 		if (tTd(38, 2))
203268350Seric 			printf("text_map_open(%s): %s is not a file\n",
203368350Seric 				map->map_file, map->map_file);
203468350Seric 		return FALSE;
203568350Seric 	}
203668350Seric 
203768350Seric 	if (map->map_keycolnm == NULL)
203868350Seric 		map->map_keycolno = 0;
203968350Seric 	else
204068350Seric 	{
204168350Seric 		if (!isdigit(*map->map_keycolnm))
204268350Seric 		{
204368350Seric 			if (tTd(38, 2))
204468350Seric 				printf("text_map_open(%s): -k should specify a number, not %s\n",
204568350Seric 					map->map_file, map->map_keycolnm);
204668350Seric 			return FALSE;
204768350Seric 		}
204868350Seric 		map->map_keycolno = atoi(map->map_keycolnm);
204968350Seric 	}
205068350Seric 
205168350Seric 	if (map->map_valcolnm == NULL)
205268350Seric 		map->map_valcolno = 0;
205368350Seric 	else
205468350Seric 	{
205568350Seric 		if (!isdigit(*map->map_valcolnm))
205668350Seric 		{
205768350Seric 			if (tTd(38, 2))
205868350Seric 				printf("text_map_open(%s): -v should specify a number, not %s\n",
205968350Seric 					map->map_file, map->map_valcolnm);
206068350Seric 			return FALSE;
206168350Seric 		}
206268350Seric 		map->map_valcolno = atoi(map->map_valcolnm);
206368350Seric 	}
206468350Seric 
206568350Seric 	if (tTd(38, 2))
206668350Seric 	{
206768520Seric 		printf("text_map_open(%s): delimiter = ",
206868520Seric 			map->map_file);
206968520Seric 		if (map->map_coldelim == '\0')
207068520Seric 			printf("(white space)\n");
207168520Seric 		else
207268520Seric 			printf("%c\n", map->map_coldelim);
207368350Seric 	}
207468350Seric 
207568350Seric 	return TRUE;
207668350Seric }
207768350Seric 
207868350Seric 
207968350Seric /*
208068350Seric **  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
208168350Seric */
208268350Seric 
208368350Seric char *
text_map_lookup(map,name,av,statp)208468350Seric text_map_lookup(map, name, av, statp)
208568350Seric 	MAP *map;
208668350Seric 	char *name;
208768350Seric 	char **av;
208868350Seric 	int *statp;
208968350Seric {
209068350Seric 	char *vp;
209168350Seric 	auto int vsize;
209268350Seric 	int buflen;
209368350Seric 	char search_key[MAXNAME + 1];
209468350Seric 	char linebuf[MAXLINE];
209568350Seric 	FILE *f;
209668528Seric 	char buf[MAXNAME + 1];
209768350Seric 	char delim;
209868350Seric 	int key_idx;
209968350Seric 	bool found_it;
210068350Seric 	extern char *get_column();
210168350Seric 
210268350Seric 
210368350Seric 	found_it = FALSE;
210468350Seric 	if (tTd(38, 20))
210568350Seric 		printf("text_map_lookup(%s)\n", name);
210668350Seric 
210768350Seric 	buflen = strlen(name);
210868350Seric 	if (buflen > sizeof search_key - 1)
210968350Seric 		buflen = sizeof search_key - 1;
211068350Seric 	bcopy(name, search_key, buflen + 1);
211168350Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
211268350Seric 		makelower(search_key);
211368350Seric 
211468350Seric 	f = fopen(map->map_file, "r");
211568350Seric 	if (f == NULL)
211668350Seric 	{
211768350Seric 		map->map_mflags &= ~(MF_VALID|MF_OPEN);
211868350Seric 		*statp = EX_UNAVAILABLE;
211968350Seric 		return NULL;
212068350Seric 	}
212168350Seric 	key_idx = map->map_keycolno;
212268350Seric 	delim = map->map_coldelim;
212368350Seric 	while (fgets(linebuf, MAXLINE, f))
212468350Seric 	{
212568350Seric 		char *lf;
212668350Seric 		if (linebuf[0] == '#')
212768350Seric 			continue; /* skip comment line */
212868350Seric 		if (lf = strchr(linebuf, '\n'))
212968350Seric 			*lf = '\0';
213068350Seric 		if (!strcasecmp(search_key,
213168350Seric 				get_column(linebuf, key_idx, delim, buf)))
213268350Seric 		{
213368350Seric 			found_it = TRUE;
213468350Seric 			break;
213568350Seric 		}
213668350Seric 	}
213768350Seric 	fclose(f);
213868350Seric 	if (!found_it)
213968350Seric 	{
214068350Seric #ifdef MAP_EXIT_STAT
214168350Seric 		*statp = EX_NOTFOUND;
214268350Seric #endif
214368350Seric 		return(NULL);
214468350Seric 	}
214568350Seric 	vp = get_column(linebuf, map->map_valcolno, delim, buf);
214668350Seric 	vsize = strlen(vp);
214768350Seric #ifdef MAP_EXIT_STAT
214868350Seric 	*statp = EX_OK;
214968350Seric #endif
215068350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
215168350Seric 		return map_rewrite(map, name, strlen(name), NULL);
215268350Seric 	else
215368350Seric 		return map_rewrite(map, vp, vsize, av);
215468350Seric }
215569401Seric 
215669401Seric 
215769401Seric /*
215869401Seric **  TEXT_GETCANONNAME -- look up canonical name in hosts file
215969401Seric */
216069401Seric 
216169401Seric bool
text_getcanonname(name,hbsize,statp)216269401Seric text_getcanonname(name, hbsize, statp)
216369401Seric 	char *name;
216469401Seric 	int hbsize;
216569401Seric 	int *statp;
216669401Seric {
216769401Seric 	int key_idx;
216869401Seric 	bool found;
216969401Seric 	FILE *f;
217069401Seric 	char linebuf[MAXLINE];
217169401Seric 	char cbuf[MAXNAME + 1];
217269780Seric 	char fbuf[MAXNAME + 1];
217369780Seric 	char nbuf[MAXNAME + 1];
217469401Seric 	extern char *get_column();
217569401Seric 
217669780Seric 	if (strlen(name) >= sizeof nbuf)
217769780Seric 	{
217869780Seric 		*statp = EX_UNAVAILABLE;
217969780Seric 		return FALSE;
218069780Seric 	}
218169780Seric 	(void) strcpy(nbuf, name);
218269780Seric 	shorten_hostname(nbuf);
218369401Seric 
218469401Seric 	/* we only accept single token search key */
218569780Seric 	if (strchr(nbuf, '.') != NULL)
218669401Seric 	{
218769401Seric 		*statp = EX_NOHOST;
218869401Seric 		return FALSE;
218969401Seric 	}
219069401Seric 
219169401Seric 	found = FALSE;
219269401Seric 
219369401Seric 	f = fopen(HostsFile, "r");
219469401Seric 	if (f == NULL)
219569401Seric 	{
219669401Seric #ifdef MAP_EXIT_STAT
219769401Seric 		*statp = EX_UNAVAILABLE;
219869401Seric #endif
219969401Seric 		return FALSE;
220069401Seric 	}
220169401Seric 	while (!found && fgets(linebuf, MAXLINE, f) != NULL)
220269401Seric 	{
220369401Seric 		char *p;
220469401Seric 
220569401Seric 		if (linebuf[0] == '#')
220669401Seric 			continue;
220769401Seric 		if ((p = strchr(linebuf, '\n')) != NULL)
220869401Seric 			*p = '\0';
220969833Seric 		found = extract_canonname(nbuf, linebuf, cbuf);
221069401Seric 	}
221169401Seric 	fclose(f);
221269401Seric 	if (!found)
221369401Seric 	{
221469401Seric 		*statp = EX_NOHOST;
221569401Seric 		return FALSE;
221669401Seric 	}
221769401Seric 
221869833Seric 	if (hbsize >= strlen(cbuf))
221969401Seric 	{
222069833Seric 		strcpy(name, cbuf);
222169401Seric 		*statp = EX_OK;
222269401Seric 		return TRUE;
222369401Seric 	}
222469401Seric 	*statp = EX_UNAVAILABLE;
222569401Seric 	return FALSE;
222669401Seric }
222768350Seric /*
222860089Seric **  STAB (Symbol Table) Modules
222960089Seric */
223060089Seric 
223160089Seric 
223260089Seric /*
223360207Seric **  STAB_MAP_LOOKUP -- look up alias in symbol table
223460089Seric */
223560089Seric 
223660089Seric char *
stab_map_lookup(map,name,av,pstat)223761707Seric stab_map_lookup(map, name, av, pstat)
223860089Seric 	register MAP *map;
223960089Seric 	char *name;
224061707Seric 	char **av;
224161707Seric 	int *pstat;
224260089Seric {
224360089Seric 	register STAB *s;
224460089Seric 
224560537Seric 	if (tTd(38, 20))
224668350Seric 		printf("stab_lookup(%s, %s)\n",
224768350Seric 			map->map_mname, name);
224860089Seric 
224960089Seric 	s = stab(name, ST_ALIAS, ST_FIND);
225060089Seric 	if (s != NULL)
225160089Seric 		return (s->s_alias);
225260089Seric 	return (NULL);
225360089Seric }
225460089Seric 
225560089Seric 
225660089Seric /*
225760207Seric **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
225860089Seric */
225960089Seric 
226060089Seric void
stab_map_store(map,lhs,rhs)226160089Seric stab_map_store(map, lhs, rhs)
226260089Seric 	register MAP *map;
226360089Seric 	char *lhs;
226460089Seric 	char *rhs;
226560089Seric {
226660089Seric 	register STAB *s;
226760089Seric 
226860089Seric 	s = stab(lhs, ST_ALIAS, ST_ENTER);
226960089Seric 	s->s_alias = newstr(rhs);
227060089Seric }
227160089Seric 
227260089Seric 
227360089Seric /*
227460207Seric **  STAB_MAP_OPEN -- initialize (reads data file)
227560207Seric **
227660207Seric **	This is a wierd case -- it is only intended as a fallback for
227760207Seric **	aliases.  For this reason, opens for write (only during a
227860207Seric **	"newaliases") always fails, and opens for read open the
227960207Seric **	actual underlying text file instead of the database.
228060089Seric */
228160089Seric 
228260089Seric bool
stab_map_open(map,mode)228360089Seric stab_map_open(map, mode)
228460089Seric 	register MAP *map;
228560089Seric 	int mode;
228660089Seric {
228763835Seric 	FILE *af;
228864284Seric 	struct stat st;
228963835Seric 
229060537Seric 	if (tTd(38, 2))
229168350Seric 		printf("stab_map_open(%s, %s)\n",
229268350Seric 			map->map_mname, map->map_file);
229360089Seric 
229460089Seric 	if (mode != O_RDONLY)
229560207Seric 	{
229660207Seric 		errno = ENODEV;
229760089Seric 		return FALSE;
229860207Seric 	}
229960089Seric 
230063835Seric 	af = fopen(map->map_file, "r");
230163835Seric 	if (af == NULL)
230263835Seric 		return FALSE;
230368350Seric 	readaliases(map, af, FALSE, FALSE);
230464284Seric 
230564284Seric 	if (fstat(fileno(af), &st) >= 0)
230664284Seric 		map->map_mtime = st.st_mtime;
230763835Seric 	fclose(af);
230863835Seric 
230960089Seric 	return TRUE;
231060089Seric }
231160089Seric /*
231260089Seric **  Implicit Modules
231356822Seric **
231460089Seric **	Tries several types.  For back compatibility of aliases.
231556822Seric */
231656822Seric 
231760089Seric 
231860089Seric /*
231960207Seric **  IMPL_MAP_LOOKUP -- lookup in best open database
232060089Seric */
232160089Seric 
232260089Seric char *
impl_map_lookup(map,name,av,pstat)232360089Seric impl_map_lookup(map, name, av, pstat)
232460089Seric 	MAP *map;
232560089Seric 	char *name;
232656822Seric 	char **av;
232760089Seric 	int *pstat;
232856822Seric {
232960537Seric 	if (tTd(38, 20))
233068350Seric 		printf("impl_map_lookup(%s, %s)\n",
233168350Seric 			map->map_mname, name);
233256822Seric 
233360089Seric #ifdef NEWDB
233460207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
233560089Seric 		return db_map_lookup(map, name, av, pstat);
233660089Seric #endif
233760089Seric #ifdef NDBM
233860207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
233960089Seric 		return ndbm_map_lookup(map, name, av, pstat);
234060089Seric #endif
234160089Seric 	return stab_map_lookup(map, name, av, pstat);
234260089Seric }
234360089Seric 
234460089Seric /*
234560207Seric **  IMPL_MAP_STORE -- store in open databases
234660089Seric */
234760089Seric 
234860089Seric void
impl_map_store(map,lhs,rhs)234960089Seric impl_map_store(map, lhs, rhs)
235060089Seric 	MAP *map;
235160089Seric 	char *lhs;
235260089Seric 	char *rhs;
235360089Seric {
235460089Seric #ifdef NEWDB
235560207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
235660089Seric 		db_map_store(map, lhs, rhs);
235760089Seric #endif
235860089Seric #ifdef NDBM
235960207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
236060089Seric 		ndbm_map_store(map, lhs, rhs);
236160089Seric #endif
236260089Seric 	stab_map_store(map, lhs, rhs);
236360089Seric }
236460089Seric 
236560089Seric /*
236660089Seric **  IMPL_MAP_OPEN -- implicit database open
236760089Seric */
236860089Seric 
236960089Seric bool
impl_map_open(map,mode)237060089Seric impl_map_open(map, mode)
237160089Seric 	MAP *map;
237260089Seric 	int mode;
237360089Seric {
237460089Seric 	struct stat stb;
237560089Seric 
237660537Seric 	if (tTd(38, 2))
237768350Seric 		printf("impl_map_open(%s, %s, %d)\n",
237868350Seric 			map->map_mname, map->map_file, mode);
237960089Seric 
238060089Seric 	if (stat(map->map_file, &stb) < 0)
238156822Seric 	{
238260089Seric 		/* no alias file at all */
238364718Seric 		if (tTd(38, 3))
238464718Seric 			printf("no map file\n");
238560089Seric 		return FALSE;
238656822Seric 	}
238756822Seric 
238860089Seric #ifdef NEWDB
238960207Seric 	map->map_mflags |= MF_IMPL_HASH;
239060089Seric 	if (hash_map_open(map, mode))
239156822Seric 	{
239264250Seric #if defined(NDBM) && defined(NIS)
239369651Seric 		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
239460207Seric #endif
239560207Seric 			return TRUE;
239660089Seric 	}
239760207Seric 	else
239860207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
239960089Seric #endif
240060089Seric #ifdef NDBM
240160207Seric 	map->map_mflags |= MF_IMPL_NDBM;
240260089Seric 	if (ndbm_map_open(map, mode))
240360089Seric 	{
240460089Seric 		return TRUE;
240560089Seric 	}
240660207Seric 	else
240760207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
240860089Seric #endif
240956822Seric 
241064650Seric #if defined(NEWDB) || defined(NDBM)
241160089Seric 	if (Verbose)
241260089Seric 		message("WARNING: cannot open alias database %s", map->map_file);
241364964Seric #else
241464964Seric 	if (mode != O_RDONLY)
241564964Seric 		usrerr("Cannot rebuild aliases: no database format defined");
241660207Seric #endif
241760089Seric 
241860207Seric 	return stab_map_open(map, mode);
241956822Seric }
242060089Seric 
242160207Seric 
242260089Seric /*
242360207Seric **  IMPL_MAP_CLOSE -- close any open database(s)
242460089Seric */
242560089Seric 
242660089Seric void
impl_map_close(map)242760207Seric impl_map_close(map)
242860089Seric 	MAP *map;
242960089Seric {
243068350Seric 	if (tTd(38, 20))
243168350Seric 		printf("impl_map_close(%s, %s, %x)\n",
243268350Seric 			map->map_mname, map->map_file, map->map_mflags);
243360089Seric #ifdef NEWDB
243460207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
243560089Seric 	{
243660207Seric 		db_map_close(map);
243760207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
243860089Seric 	}
243960089Seric #endif
244060089Seric 
244160089Seric #ifdef NDBM
244260207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
244360089Seric 	{
244460207Seric 		ndbm_map_close(map);
244560207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
244660089Seric 	}
244760089Seric #endif
244860089Seric }
244960207Seric /*
245068350Seric **  User map class.
245168350Seric **
245268350Seric **	Provides access to the system password file.
245368350Seric */
245468350Seric 
245568350Seric /*
245668350Seric **  USER_MAP_OPEN -- open user map
245768350Seric **
245868350Seric **	Really just binds field names to field numbers.
245968350Seric */
246068350Seric 
246168350Seric bool
user_map_open(map,mode)246268350Seric user_map_open(map, mode)
246368350Seric 	MAP *map;
246468350Seric 	int mode;
246568350Seric {
246668350Seric 	if (tTd(38, 2))
246768350Seric 		printf("user_map_open(%s)\n", map->map_mname);
246868350Seric 
246968350Seric 	if (mode != O_RDONLY)
247068350Seric 	{
247168350Seric 		/* issue a pseudo-error message */
247268350Seric #ifdef ENOSYS
247368350Seric 		errno = ENOSYS;
247468350Seric #else
247568350Seric # ifdef EFTYPE
247668350Seric 		errno = EFTYPE;
247768350Seric # else
247868350Seric 		errno = ENXIO;
247968350Seric # endif
248068350Seric #endif
248168350Seric 		return FALSE;
248268350Seric 	}
248368350Seric 	if (map->map_valcolnm == NULL)
248468350Seric 		/* nothing */ ;
248568350Seric 	else if (strcasecmp(map->map_valcolnm, "name") == 0)
248668350Seric 		map->map_valcolno = 1;
248768350Seric 	else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
248868350Seric 		map->map_valcolno = 2;
248968350Seric 	else if (strcasecmp(map->map_valcolnm, "uid") == 0)
249068350Seric 		map->map_valcolno = 3;
249168350Seric 	else if (strcasecmp(map->map_valcolnm, "gid") == 0)
249268350Seric 		map->map_valcolno = 4;
249368350Seric 	else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
249468350Seric 		map->map_valcolno = 5;
249568350Seric 	else if (strcasecmp(map->map_valcolnm, "dir") == 0)
249668350Seric 		map->map_valcolno = 6;
249768350Seric 	else if (strcasecmp(map->map_valcolnm, "shell") == 0)
249868350Seric 		map->map_valcolno = 7;
249968350Seric 	else
250068350Seric 	{
250168350Seric 		syserr("User map %s: unknown column name %s",
250268350Seric 			map->map_mname, map->map_valcolnm);
250368350Seric 		return FALSE;
250468350Seric 	}
250568350Seric 	return TRUE;
250668350Seric }
250768350Seric 
250868350Seric 
250968350Seric /*
251068350Seric **  USER_MAP_LOOKUP -- look up a user in the passwd file.
251168350Seric */
251268350Seric 
251368350Seric char *
user_map_lookup(map,key,av,statp)251468350Seric user_map_lookup(map, key, av, statp)
251568350Seric 	MAP *map;
251668350Seric 	char *key;
251768350Seric 	char **av;
251868350Seric 	int *statp;
251968350Seric {
252068350Seric 	struct passwd *pw;
252168350Seric 
252268350Seric 	if (tTd(38, 20))
252368350Seric 		printf("user_map_lookup(%s, %s)\n",
252468350Seric 			map->map_mname, key);
252568350Seric 
252668693Seric 	pw = sm_getpwnam(key);
252768350Seric 	if (pw == NULL)
252868350Seric 		return NULL;
252968350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
253068350Seric 		return map_rewrite(map, key, strlen(key), NULL);
253168350Seric 	else
253268350Seric 	{
253368433Seric 		char *rwval = NULL;
253468350Seric 		char buf[30];
253568350Seric 
253668350Seric 		switch (map->map_valcolno)
253768350Seric 		{
253868350Seric 		  case 0:
253968350Seric 		  case 1:
254068350Seric 			rwval = pw->pw_name;
254168350Seric 			break;
254268350Seric 
254368350Seric 		  case 2:
254468350Seric 			rwval = pw->pw_passwd;
254568350Seric 			break;
254668350Seric 
254768350Seric 		  case 3:
254868350Seric 			sprintf(buf, "%d", pw->pw_uid);
254968350Seric 			rwval = buf;
255068350Seric 			break;
255168350Seric 
255268350Seric 		  case 4:
255368350Seric 			sprintf(buf, "%d", pw->pw_gid);
255468350Seric 			rwval = buf;
255568350Seric 			break;
255668350Seric 
255768350Seric 		  case 5:
255868350Seric 			rwval = pw->pw_gecos;
255968350Seric 			break;
256068350Seric 
256168350Seric 		  case 6:
256268350Seric 			rwval = pw->pw_dir;
256368350Seric 			break;
256468350Seric 
256568350Seric 		  case 7:
256668350Seric 			rwval = pw->pw_shell;
256768350Seric 			break;
256868350Seric 		}
256968350Seric 		return map_rewrite(map, rwval, strlen(rwval), av);
257068350Seric 	}
257168350Seric }
257268350Seric /*
257369453Seric **  Program map type.
257469453Seric **
257569453Seric **	This provides access to arbitrary programs.  It should be used
257669453Seric **	only very sparingly, since there is no way to bound the cost
257769453Seric **	of invoking an arbitrary program.
257869453Seric */
257969453Seric 
258069453Seric char *
prog_map_lookup(map,name,av,statp)258169453Seric prog_map_lookup(map, name, av, statp)
258269453Seric 	MAP *map;
258369453Seric 	char *name;
258469453Seric 	char **av;
258569453Seric 	int *statp;
258669453Seric {
258769453Seric 	int i;
258869453Seric 	register char *p;
258969453Seric 	int fd;
259069453Seric 	auto pid_t pid;
259169827Seric 	char *rval;
259269827Seric 	int stat;
259369453Seric 	char *argv[MAXPV + 1];
259469453Seric 	char buf[MAXLINE];
259569453Seric 
259669453Seric 	if (tTd(38, 20))
259769453Seric 		printf("prog_map_lookup(%s, %s) %s\n",
259869453Seric 			map->map_mname, name, map->map_file);
259969453Seric 
260069453Seric 	i = 0;
260169453Seric 	argv[i++] = map->map_file;
260269453Seric 	strcpy(buf, map->map_rebuild);
260369453Seric 	for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
260469453Seric 	{
260569453Seric 		if (i >= MAXPV - 1)
260669453Seric 			break;
260769453Seric 		argv[i++] = p;
260869453Seric 	}
260969453Seric 	argv[i++] = name;
261069453Seric 	argv[i] = NULL;
261169453Seric 	pid = prog_open(argv, &fd, CurEnv);
261269453Seric 	if (pid < 0)
261369453Seric 	{
261469827Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
261569827Seric 			syserr("prog_map_lookup(%s) failed (%s) -- closing",
261669827Seric 				map->map_mname, errstring(errno));
261769827Seric 		else if (tTd(38, 9))
261869453Seric 			printf("prog_map_lookup(%s) failed (%s) -- closing",
261969453Seric 				map->map_mname, errstring(errno));
262069453Seric 		map->map_mflags &= ~(MF_VALID|MF_OPEN);
262169827Seric 		*statp = EX_OSFILE;
262269453Seric 		return NULL;
262369453Seric 	}
262469453Seric 	i = read(fd, buf, sizeof buf - 1);
262569827Seric 	if (i < 0)
262669827Seric 	{
262769827Seric 		syserr("prog_map_lookup(%s): read error %s\n",
262869562Seric 			map->map_mname, errstring(errno));
262969827Seric 		rval = NULL;
263069827Seric 	}
263169827Seric 	else if (i == 0 && tTd(38, 2))
263269827Seric 	{
263369827Seric 		printf("prog_map_lookup(%s): empty answer\n",
263469827Seric 			map->map_mname);
263569827Seric 		rval = NULL;
263669827Seric 	}
263769453Seric 	if (i > 0)
263869453Seric 	{
263969453Seric 		buf[i] = '\0';
264069453Seric 		p = strchr(buf, '\n');
264169453Seric 		if (p != NULL)
264269453Seric 			*p = '\0';
264369453Seric 
264469453Seric 		/* collect the return value */
264569453Seric 		if (bitset(MF_MATCHONLY, map->map_mflags))
264669453Seric 			rval = map_rewrite(map, name, strlen(name), NULL);
264769453Seric 		else
264869453Seric 			rval = map_rewrite(map, buf, strlen(buf), NULL);
264969453Seric 
265069453Seric 		/* now flush any additional output */
265169453Seric 		while ((i = read(fd, buf, sizeof buf)) > 0)
265269453Seric 			continue;
265369827Seric 	}
265469453Seric 
265569827Seric 	/* wait for the process to terminate */
265669827Seric 	close(fd);
265769827Seric 	stat = waitfor(pid);
265869453Seric 
265969827Seric 	if (stat == -1)
266069827Seric 	{
266169827Seric 		syserr("prog_map_lookup(%s): wait error %s\n",
266269827Seric 			map->map_mname, errstring(errno));
266369827Seric 		*statp = EX_SOFTWARE;
266469827Seric 		rval = NULL;
266569453Seric 	}
266669872Seric 	else if (WIFEXITED(stat))
266769827Seric 	{
266869872Seric 		*statp = WEXITSTATUS(stat);
266969827Seric 	}
267069827Seric 	else
267169827Seric 	{
267269827Seric 		syserr("prog_map_lookup(%s): child died on signal %d",
267369872Seric 			map->map_mname, stat);
267469827Seric 		*statp = EX_UNAVAILABLE;
267569827Seric 		rval = NULL;
267669827Seric 	}
267769827Seric 	return rval;
267869453Seric }
267969453Seric /*
268068350Seric **  Sequenced map type.
268168350Seric **
268268350Seric **	Tries each map in order until something matches, much like
268368350Seric **	implicit.  Stores go to the first map in the list that can
268468350Seric **	support storing.
268568350Seric **
268668350Seric **	This is slightly unusual in that there are two interfaces.
268768350Seric **	The "sequence" interface lets you stack maps arbitrarily.
268868350Seric **	The "switch" interface builds a sequence map by looking
268968350Seric **	at a system-dependent configuration file such as
269068350Seric **	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
269168350Seric **
269268350Seric **	We don't need an explicit open, since all maps are
269368350Seric **	opened during startup, including underlying maps.
269468350Seric */
269568350Seric 
269668350Seric /*
269768350Seric **  SEQ_MAP_PARSE -- Sequenced map parsing
269868350Seric */
269968350Seric 
270068350Seric bool
seq_map_parse(map,ap)270168350Seric seq_map_parse(map, ap)
270268350Seric 	MAP *map;
270368350Seric 	char *ap;
270468350Seric {
270568350Seric 	int maxmap;
270668350Seric 
270768350Seric 	if (tTd(38, 2))
270868350Seric 		printf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
270968350Seric 	maxmap = 0;
271068350Seric 	while (*ap != '\0')
271168350Seric 	{
271268350Seric 		register char *p;
271368350Seric 		STAB *s;
271468350Seric 
271568350Seric 		/* find beginning of map name */
271668350Seric 		while (isascii(*ap) && isspace(*ap))
271768350Seric 			ap++;
271868350Seric 		for (p = ap; isascii(*p) && isalnum(*p); p++)
271968350Seric 			continue;
272068350Seric 		if (*p != '\0')
272168350Seric 			*p++ = '\0';
272268350Seric 		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
272368350Seric 			p++;
272468350Seric 		if (*ap == '\0')
272568350Seric 		{
272668350Seric 			ap = p;
272768350Seric 			continue;
272868350Seric 		}
272968350Seric 		s = stab(ap, ST_MAP, ST_FIND);
273068350Seric 		if (s == NULL)
273168350Seric 		{
273268350Seric 			syserr("Sequence map %s: unknown member map %s",
273368350Seric 				map->map_mname, ap);
273468350Seric 		}
273568350Seric 		else if (maxmap == MAXMAPSTACK)
273668350Seric 		{
273768350Seric 			syserr("Sequence map %s: too many member maps (%d max)",
273868350Seric 				map->map_mname, MAXMAPSTACK);
273968350Seric 			maxmap++;
274068350Seric 		}
274168350Seric 		else if (maxmap < MAXMAPSTACK)
274268350Seric 		{
274368350Seric 			map->map_stack[maxmap++] = &s->s_map;
274468350Seric 		}
274568350Seric 		ap = p;
274668350Seric 	}
274768350Seric 	return TRUE;
274868350Seric }
274968350Seric 
275068350Seric 
275168350Seric /*
275268350Seric **  SWITCH_MAP_OPEN -- open a switched map
275368350Seric **
275468350Seric **	This looks at the system-dependent configuration and builds
275568350Seric **	a sequence map that does the same thing.
275668350Seric **
275768350Seric **	Every system must define a switch_map_find routine in conf.c
275868350Seric **	that will return the list of service types associated with a
275968350Seric **	given service class.
276068350Seric */
276168350Seric 
276268350Seric bool
switch_map_open(map,mode)276368350Seric switch_map_open(map, mode)
276468350Seric 	MAP *map;
276568350Seric 	int mode;
276668350Seric {
276768350Seric 	int mapno;
276868350Seric 	int nmaps;
276968350Seric 	char *maptype[MAXMAPSTACK];
277068350Seric 
277168350Seric 	if (tTd(38, 2))
277268350Seric 		printf("switch_map_open(%s, %s, %d)\n",
277368350Seric 			map->map_mname, map->map_file, mode);
277468350Seric 
277568350Seric 	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
277668350Seric 	if (tTd(38, 19))
277768350Seric 	{
277868350Seric 		printf("\tswitch_map_find => %d\n", nmaps);
277968350Seric 		for (mapno = 0; mapno < nmaps; mapno++)
278068350Seric 			printf("\t\t%s\n", maptype[mapno]);
278168350Seric 	}
278268350Seric 	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
278368350Seric 		return FALSE;
278468350Seric 
278568350Seric 	for (mapno = 0; mapno < nmaps; mapno++)
278668350Seric 	{
278768350Seric 		register STAB *s;
278868350Seric 		char nbuf[MAXNAME + 1];
278968350Seric 
279068350Seric 		if (maptype[mapno] == NULL)
279168350Seric 			continue;
279268350Seric 		(void) sprintf(nbuf, "%s.%s", map->map_file, maptype[mapno]);
279368350Seric 		s = stab(nbuf, ST_MAP, ST_FIND);
279468350Seric 		if (s == NULL)
279568350Seric 		{
279668350Seric 			syserr("Switch map %s: unknown member map %s",
279768350Seric 				map->map_mname, nbuf);
279868350Seric 		}
279968350Seric 		else
280068350Seric 		{
280168350Seric 			map->map_stack[mapno] = &s->s_map;
280268350Seric 			if (tTd(38, 4))
280368350Seric 				printf("\tmap_stack[%d] = %s:%s\n",
280468350Seric 					mapno, s->s_map.map_class->map_cname,
280568350Seric 					nbuf);
280668350Seric 		}
280768350Seric 	}
280868350Seric 	return TRUE;
280968350Seric }
281068350Seric 
281168350Seric 
281268350Seric /*
281368350Seric **  SEQ_MAP_CLOSE -- close all underlying maps
281468350Seric */
281568350Seric 
281669748Seric void
seq_map_close(map)281768350Seric seq_map_close(map)
281868350Seric 	MAP *map;
281968350Seric {
282068350Seric 	int mapno;
282168350Seric 
282268350Seric 	if (tTd(38, 20))
282368350Seric 		printf("seq_map_close(%s)\n", map->map_mname);
282468350Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
282568350Seric 	{
282668350Seric 		MAP *mm = map->map_stack[mapno];
282768350Seric 
282868350Seric 		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
282968350Seric 			continue;
283068350Seric 		mm->map_class->map_close(mm);
283168798Seric 		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
283268350Seric 	}
283368350Seric }
283468350Seric 
283568350Seric 
283668350Seric /*
283768350Seric **  SEQ_MAP_LOOKUP -- sequenced map lookup
283868350Seric */
283968350Seric 
284068350Seric char *
seq_map_lookup(map,key,args,pstat)284168350Seric seq_map_lookup(map, key, args, pstat)
284268350Seric 	MAP *map;
284368350Seric 	char *key;
284468350Seric 	char **args;
284568350Seric 	int *pstat;
284668350Seric {
284768350Seric 	int mapno;
284868350Seric 	int mapbit = 0x01;
284968350Seric 
285068350Seric 	if (tTd(38, 20))
285168350Seric 		printf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
285268350Seric 
285368350Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
285468350Seric 	{
285568350Seric 		MAP *mm = map->map_stack[mapno];
285668350Seric 		int stat = 0;
285768350Seric 		char *rv;
285868350Seric 
285968350Seric 		if (mm == NULL)
286068350Seric 			continue;
286168350Seric 		if (!bitset(MF_OPEN, mm->map_mflags))
286268350Seric 		{
286368350Seric 			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
286468350Seric 			{
286568350Seric 				*pstat = EX_UNAVAILABLE;
286668350Seric 				return NULL;
286768350Seric 			}
286868350Seric 			continue;
286968350Seric 		}
287068350Seric 		rv = mm->map_class->map_lookup(mm, key, args, &stat);
287168350Seric 		if (rv != NULL)
287268350Seric 			return rv;
287368350Seric 		if (stat == 0 && bitset(mapbit, map->map_return[MA_NOTFOUND]))
287468350Seric 			return NULL;
287568350Seric 		if (stat != 0 && bitset(mapbit, map->map_return[MA_TRYAGAIN]))
287668350Seric 		{
287768350Seric 			*pstat = stat;
287868350Seric 			return NULL;
287968350Seric 		}
288068350Seric 	}
288168350Seric 	return NULL;
288268350Seric }
288368350Seric 
288468350Seric 
288568350Seric /*
288668350Seric **  SEQ_MAP_STORE -- sequenced map store
288768350Seric */
288868350Seric 
288968350Seric void
seq_map_store(map,key,val)289068350Seric seq_map_store(map, key, val)
289168350Seric 	MAP *map;
289268350Seric 	char *key;
289368350Seric 	char *val;
289468350Seric {
289568350Seric 	int mapno;
289668350Seric 
289768350Seric 	if (tTd(38, 12))
289868350Seric 		printf("seq_map_store(%s, %s, %s)\n",
289968350Seric 			map->map_mname, key, val);
290068350Seric 
290168350Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
290268350Seric 	{
290368350Seric 		MAP *mm = map->map_stack[mapno];
290468350Seric 
290568350Seric 		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
290668350Seric 			continue;
290768350Seric 
290868350Seric 		mm->map_class->map_store(mm, key, val);
290968350Seric 		return;
291068350Seric 	}
291168350Seric 	syserr("seq_map_store(%s, %s, %s): no writable map",
291268350Seric 		map->map_mname, key, val);
291368350Seric }
291468350Seric /*
291560207Seric **  NULL stubs
291660089Seric */
291760089Seric 
291860207Seric bool
null_map_open(map,mode)291960207Seric null_map_open(map, mode)
292060089Seric 	MAP *map;
292160207Seric 	int mode;
292260089Seric {
292360207Seric 	return TRUE;
292460089Seric }
292560089Seric 
292660207Seric void
null_map_close(map)292760207Seric null_map_close(map)
292860207Seric 	MAP *map;
292960089Seric {
293060207Seric 	return;
293160207Seric }
293260089Seric 
293360207Seric void
null_map_store(map,key,val)293460207Seric null_map_store(map, key, val)
293560207Seric 	MAP *map;
293660207Seric 	char *key;
293760207Seric 	char *val;
293860089Seric {
293960207Seric 	return;
294060089Seric }
294168350Seric 
294268350Seric 
294368350Seric /*
294468350Seric **  BOGUS stubs
294568350Seric */
294668350Seric 
294768350Seric char *
bogus_map_lookup(map,key,args,pstat)294868350Seric bogus_map_lookup(map, key, args, pstat)
294968350Seric 	MAP *map;
295068350Seric 	char *key;
295168350Seric 	char **args;
295268350Seric 	int *pstat;
295368350Seric {
295468350Seric 	*pstat = EX_TEMPFAIL;
295568350Seric 	return NULL;
295668350Seric }
295768350Seric 
295868350Seric MAPCLASS	BogusMapClass =
295968350Seric {
296068350Seric 	"bogus-map",		NULL,		0,
296168350Seric 	NULL,		bogus_map_lookup,	null_map_store,
296268350Seric 	null_map_open,	null_map_close,
296368350Seric };
2964