xref: /csrg-svn/usr.sbin/sendmail/src/map.c (revision 69872)
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*69872Seric static char sccsid[] = "@(#)map.c	8.75 (Berkeley) 06/12/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
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 *
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
35560537Seric initmaps(rebuild, e)
35660537Seric 	bool rebuild;
35760537Seric 	register ENVELOPE *e;
35860537Seric {
35960537Seric 	extern void map_init();
36060537Seric 
36164671Seric #ifdef 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 	}
37464671Seric #ifdef XDEBUG
37564671Seric 	checkfd012("exiting initmaps");
37664671Seric #endif
37760537Seric }
37860537Seric 
37960537Seric void
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
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 	extern int h_errno;
48269802Seric 
48369802Seric 	nmaps = switch_map_find("hosts", maptype, mapreturn);
48469802Seric 	for (mapno = 0; mapno < nmaps; mapno++)
48569802Seric 	{
48669802Seric 		int i;
48769802Seric 
48869802Seric 		if (tTd(38, 20))
48969802Seric 			printf("getcanonname(%s), trying %s\n",
49069802Seric 				host, maptype[mapno]);
49169802Seric 		if (strcmp("files", maptype[mapno]) == 0)
49269802Seric 		{
49369802Seric 			extern bool text_getcanonname __P((char *, int, int *));
49469802Seric 
49569802Seric 			found = text_getcanonname(host, hbsize, &stat);
49669802Seric 		}
49769802Seric #ifdef NIS
49869802Seric 		else if (strcmp("nis", maptype[mapno]) == 0)
49969802Seric 		{
50069802Seric 			extern bool nis_getcanonname __P((char *, int, int *));
50169802Seric 
50269802Seric 			found = nis_getcanonname(host, hbsize, &stat);
50369802Seric 		}
50469802Seric #endif
50569802Seric #ifdef NISPLUS
50669802Seric 		else if (strcmp("nisplus", maptype[mapno]) == 0)
50769802Seric 		{
50869802Seric 			extern bool nisplus_getcanonname __P((char *, int, int *));
50969802Seric 
51069802Seric 			found = nisplus_getcanonname(host, hbsize, &stat);
51169802Seric 		}
51269802Seric #endif
51369802Seric #if NAMED_BIND
51469802Seric 		else if (strcmp("dns", maptype[mapno]) == 0)
51569802Seric 		{
51669802Seric 			extern bool dns_getcanonname __P((char *, int, bool, int *));
51769802Seric 
51869802Seric 			found = dns_getcanonname(host, hbsize, trymx, &stat);
51969802Seric 		}
52069802Seric #endif
52169802Seric 		else
52269802Seric 		{
52369802Seric 			found = FALSE;
52469802Seric 			stat = EX_UNAVAILABLE;
52569802Seric 		}
52669802Seric 		if (found)
52769802Seric 			break;
52869802Seric 
52969802Seric 		/* see if we should continue */
53069802Seric 		if (stat == EX_TEMPFAIL)
53169802Seric 			i = MA_TRYAGAIN;
53269802Seric 		else if (stat == EX_NOHOST)
53369802Seric 			i = MA_NOTFOUND;
53469802Seric 		else
53569802Seric 			i = MA_UNAVAIL;
53669802Seric 		if (bitset(1 << mapno, mapreturn[i]))
53769802Seric 			break;
53869802Seric 	}
53969802Seric 
54069802Seric 	if (found)
54169802Seric 	{
54269802Seric 		char *d;
54369802Seric 
54469802Seric 		if (tTd(38, 20))
54569802Seric 			printf("getcanonname(%s), found\n", host);
54669802Seric 
54769802Seric 		/*
54869802Seric 		**  If returned name is still single token, compensate
54969802Seric 		**  by tagging on $m.  This is because some sites set
55069802Seric 		**  up their DNS or NIS databases wrong.
55169802Seric 		*/
55269802Seric 
55369802Seric 		if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
55469802Seric 		{
55569802Seric 			d = macvalue('m', CurEnv);
55669802Seric 			if (d != NULL &&
55769802Seric 			    hbsize > (int) (strlen(host) + strlen(d) + 1))
55869802Seric 			{
55969802Seric 				if (host[strlen(host) - 1] != '.')
56069802Seric 					strcat(host, ".");
56169802Seric 				strcat(host, d);
56269802Seric 			}
56369802Seric 			else
56469802Seric 			{
56569802Seric 				return FALSE;
56669802Seric 			}
56769802Seric 		}
56869802Seric 		return TRUE;
56969802Seric 	}
57069802Seric 
57169802Seric 	if (tTd(38, 20))
57269802Seric 		printf("getcanonname(%s), failed, stat=%d\n", host, stat);
57369802Seric 
57469802Seric #if NAMED_BIND
57569802Seric 	if (stat == EX_NOHOST)
57669802Seric 		h_errno = HOST_NOT_FOUND;
57769802Seric 	else
57869802Seric 		h_errno = TRY_AGAIN;
57969802Seric #endif
58069802Seric 
58169802Seric 	return FALSE;
58269802Seric }
58369802Seric /*
58469833Seric **  EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
58569833Seric **
58669833Seric **	Parameters:
58769833Seric **		name -- the name against which to match.
58869833Seric **		line -- the /etc/hosts line.
58969833Seric **		cbuf -- the location to store the result.
59069833Seric **
59169833Seric **	Returns:
59269833Seric **		TRUE -- if the line matched the desired name.
59369833Seric **		FALSE -- otherwise.
59469833Seric */
59569833Seric 
59669833Seric bool
59769833Seric extract_canonname(name, line, cbuf)
59869833Seric 	char *name;
59969833Seric 	char *line;
60069833Seric 	char cbuf[];
60169833Seric {
60269833Seric 	int i;
60369833Seric 	char *p;
60469833Seric 	bool found = FALSE;
60569833Seric 	extern char *get_column();
60669833Seric 
60769833Seric 	cbuf[0] = '\0';
60869833Seric 	if (line[0] == '#')
60969833Seric 		return FALSE;
61069833Seric 
61169833Seric 	for (i = 1; !found; i++)
61269833Seric 	{
61369833Seric 		char nbuf[MAXNAME + 1];
61469833Seric 
61569833Seric 		p = get_column(line, i, '\0', nbuf);
61669833Seric 		if (p == NULL)
61769833Seric 			break;
61869833Seric 		if (cbuf[0] == '\0' ||
61969833Seric 		    (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
62069833Seric 			strcpy(cbuf, p);
62169833Seric 		if (strcasecmp(name, p) == 0)
62269833Seric 			found = TRUE;
62369833Seric 	}
62469833Seric 	if (found && strchr(cbuf, '.') == NULL)
62569833Seric 	{
62669833Seric 		/* try to add a domain on the end of the name */
62769833Seric 		char *domain = macvalue('m', CurEnv);
62869833Seric 
62969833Seric 		if (domain != NULL &&
63069833Seric 		    strlen(domain) + strlen(cbuf) + 1 < MAXNAME)
63169833Seric 		{
63269833Seric 			p = &cbuf[strlen(cbuf)];
63369833Seric 			*p++ = '.';
63469833Seric 			strcpy(p, domain);
63569833Seric 		}
63669833Seric 	}
63769833Seric 	return found;
63869833Seric }
63969833Seric /*
64060089Seric **  NDBM modules
64160089Seric */
64260089Seric 
64360089Seric #ifdef NDBM
64460089Seric 
64560089Seric /*
64660089Seric **  DBM_MAP_OPEN -- DBM-style map open
64760089Seric */
64860089Seric 
64960089Seric bool
65060089Seric ndbm_map_open(map, mode)
65160089Seric 	MAP *map;
65260089Seric 	int mode;
65360089Seric {
65464284Seric 	register DBM *dbm;
65564284Seric 	struct stat st;
65660089Seric 
65760537Seric 	if (tTd(38, 2))
65868350Seric 		printf("ndbm_map_open(%s, %s, %d)\n",
65968350Seric 			map->map_mname, map->map_file, mode);
66060089Seric 
66160207Seric 	if (mode == O_RDWR)
66260207Seric 		mode |= O_CREAT|O_TRUNC;
66360207Seric 
66460089Seric 	/* open the database */
66560089Seric 	dbm = dbm_open(map->map_file, mode, DBMMODE);
66656822Seric 	if (dbm == NULL)
66756822Seric 	{
66864718Seric 		if (aliaswait(map, ".pag", FALSE))
66964718Seric 			return TRUE;
67060207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
67156836Seric 			syserr("Cannot open DBM database %s", map->map_file);
67256822Seric 		return FALSE;
67356822Seric 	}
67460089Seric 	map->map_db1 = (void *) dbm;
67564964Seric 	if (mode == O_RDONLY)
67664964Seric 	{
67764964Seric 		if (bitset(MF_ALIAS, map->map_mflags) &&
67864964Seric 		    !aliaswait(map, ".pag", TRUE))
67964718Seric 			return FALSE;
68064964Seric 	}
68164964Seric 	else
68264964Seric 	{
68364964Seric 		int fd;
68464964Seric 
68564964Seric 		/* exclusive lock for duration of rebuild */
68664964Seric 		fd = dbm_dirfno((DBM *) map->map_db1);
68764964Seric 		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) &&
68864964Seric 		    lockfile(fd, map->map_file, ".dir", LOCK_EX))
68964964Seric 			map->map_mflags |= MF_LOCKED;
69064964Seric 	}
69164718Seric 	if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0)
69264284Seric 		map->map_mtime = st.st_mtime;
69356822Seric 	return TRUE;
69456822Seric }
69560089Seric 
69660089Seric 
69760089Seric /*
69856822Seric **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
69956822Seric */
70056822Seric 
70156822Seric char *
70260089Seric ndbm_map_lookup(map, name, av, statp)
70356822Seric 	MAP *map;
70460089Seric 	char *name;
70556822Seric 	char **av;
70659084Seric 	int *statp;
70756822Seric {
70856822Seric 	datum key, val;
70964373Seric 	int fd;
71060089Seric 	char keybuf[MAXNAME + 1];
71156822Seric 
71260537Seric 	if (tTd(38, 20))
71368350Seric 		printf("ndbm_map_lookup(%s, %s)\n",
71468350Seric 			map->map_mname, name);
71560089Seric 
71660089Seric 	key.dptr = name;
71760089Seric 	key.dsize = strlen(name);
71860207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
71957014Seric 	{
72060089Seric 		if (key.dsize > sizeof keybuf - 1)
72160089Seric 			key.dsize = sizeof keybuf - 1;
72260089Seric 		bcopy(key.dptr, keybuf, key.dsize + 1);
72360089Seric 		makelower(keybuf);
72460089Seric 		key.dptr = keybuf;
72557014Seric 	}
72664373Seric 	fd = dbm_dirfno((DBM *) map->map_db1);
72764388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
72864373Seric 		(void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
72963753Seric 	val.dptr = NULL;
73063753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
73163753Seric 	{
73263753Seric 		val = dbm_fetch((DBM *) map->map_db1, key);
73363753Seric 		if (val.dptr != NULL)
73463753Seric 			map->map_mflags &= ~MF_TRY1NULL;
73563753Seric 	}
73663753Seric 	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
73763753Seric 	{
73856822Seric 		key.dsize++;
73963753Seric 		val = dbm_fetch((DBM *) map->map_db1, key);
74063753Seric 		if (val.dptr != NULL)
74163753Seric 			map->map_mflags &= ~MF_TRY0NULL;
74263753Seric 	}
74364388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
74464373Seric 		(void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
74556822Seric 	if (val.dptr == NULL)
74656822Seric 		return NULL;
74760207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
74863753Seric 		return map_rewrite(map, name, strlen(name), NULL);
74963753Seric 	else
75063753Seric 		return map_rewrite(map, val.dptr, val.dsize, av);
75156822Seric }
75256822Seric 
75356822Seric 
75456822Seric /*
75560089Seric **  DBM_MAP_STORE -- store a datum in the database
75656822Seric */
75756822Seric 
75860089Seric void
75960089Seric ndbm_map_store(map, lhs, rhs)
76060089Seric 	register MAP *map;
76160089Seric 	char *lhs;
76260089Seric 	char *rhs;
76360089Seric {
76460089Seric 	datum key;
76560089Seric 	datum data;
76660089Seric 	int stat;
76760089Seric 
76860537Seric 	if (tTd(38, 12))
76968350Seric 		printf("ndbm_map_store(%s, %s, %s)\n",
77068350Seric 			map->map_mname, lhs, rhs);
77160089Seric 
77260089Seric 	key.dsize = strlen(lhs);
77360089Seric 	key.dptr = lhs;
77460089Seric 
77560089Seric 	data.dsize = strlen(rhs);
77660089Seric 	data.dptr = rhs;
77760089Seric 
77860207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
77960089Seric 	{
78060089Seric 		key.dsize++;
78160089Seric 		data.dsize++;
78260089Seric 	}
78360089Seric 
78460089Seric 	stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
78560089Seric 	if (stat > 0)
78660089Seric 	{
78768497Seric 		if (!bitset(MF_APPEND, map->map_mflags))
78868497Seric 			usrerr("050 Warning: duplicate alias name %s", lhs);
78968497Seric 		else
79068497Seric 		{
79168497Seric 			static char *buf = NULL;
79268497Seric 			static int bufsiz = 0;
79368879Seric 			auto int xstat;
79468497Seric 			datum old;
79568497Seric 
79668879Seric 			old.dptr = ndbm_map_lookup(map, key.dptr, NULL, &xstat);
79768497Seric 			if (old.dptr != NULL && *old.dptr != '\0')
79868497Seric 			{
79968497Seric 				old.dsize = strlen(old.dptr);
80068497Seric 				if (data.dsize + old.dsize + 2 > bufsiz)
80168497Seric 				{
80268497Seric 					if (buf != NULL)
80368497Seric 						(void) free(buf);
80468497Seric 					bufsiz = data.dsize + old.dsize + 2;
80568497Seric 					buf = xalloc(bufsiz);
80668497Seric 				}
80768497Seric 				sprintf(buf, "%s,%s", data.dptr, old.dptr);
80868497Seric 				data.dsize = data.dsize + old.dsize + 1;
80968497Seric 				data.dptr = buf;
81068497Seric 				if (tTd(38, 9))
81168497Seric 					printf("ndbm_map_store append=%s\n", data.dptr);
81268497Seric 			}
81368497Seric 		}
81460089Seric 		stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
81560089Seric 	}
81660089Seric 	if (stat != 0)
81760089Seric 		syserr("readaliases: dbm put (%s)", lhs);
81860089Seric }
81960089Seric 
82060089Seric 
82160089Seric /*
82260207Seric **  NDBM_MAP_CLOSE -- close the database
82360089Seric */
82460089Seric 
82560089Seric void
82660089Seric ndbm_map_close(map)
82760089Seric 	register MAP  *map;
82860089Seric {
82966773Seric 	if (tTd(38, 9))
83068350Seric 		printf("ndbm_map_close(%s, %s, %x)\n",
83168350Seric 			map->map_mname, map->map_file, map->map_mflags);
83266773Seric 
83360207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
83460089Seric 	{
83564250Seric #ifdef NIS
83664075Seric 		bool inclnull;
83760089Seric 		char buf[200];
83860089Seric 
83964075Seric 		inclnull = bitset(MF_INCLNULL, map->map_mflags);
84064075Seric 		map->map_mflags &= ~MF_INCLNULL;
84164075Seric 
84269651Seric 		if (strstr(map->map_file, "/yp/") != NULL)
84369651Seric 		{
84469651Seric 			(void) sprintf(buf, "%010ld", curtime());
84569651Seric 			ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
84660089Seric 
84769651Seric 			(void) gethostname(buf, sizeof buf);
84869651Seric 			ndbm_map_store(map, "YP_MASTER_NAME", buf);
84969651Seric 		}
85064075Seric 
85164075Seric 		if (inclnull)
85264075Seric 			map->map_mflags |= MF_INCLNULL;
85360089Seric #endif
85460089Seric 
85560089Seric 		/* write out the distinguished alias */
85660089Seric 		ndbm_map_store(map, "@", "@");
85760089Seric 	}
85860089Seric 	dbm_close((DBM *) map->map_db1);
85960089Seric }
86060089Seric 
86160089Seric #endif
86260089Seric /*
86360582Seric **  NEWDB (Hash and BTree) Modules
86460089Seric */
86560089Seric 
86660089Seric #ifdef NEWDB
86760089Seric 
86860089Seric /*
86960582Seric **  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
87060582Seric **
87160582Seric **	These do rather bizarre locking.  If you can lock on open,
87260582Seric **	do that to avoid the condition of opening a database that
87360582Seric **	is being rebuilt.  If you don't, we'll try to fake it, but
87460582Seric **	there will be a race condition.  If opening for read-only,
87560582Seric **	we immediately release the lock to avoid freezing things up.
87660582Seric **	We really ought to hold the lock, but guarantee that we won't
87760582Seric **	be pokey about it.  That's hard to do.
87860089Seric */
87960089Seric 
88056822Seric bool
88160089Seric bt_map_open(map, mode)
88256822Seric 	MAP *map;
88360089Seric 	int mode;
88456822Seric {
88556822Seric 	DB *db;
88660228Seric 	int i;
88760582Seric 	int omode;
88864373Seric 	int fd;
88964284Seric 	struct stat st;
89068528Seric 	char buf[MAXNAME + 1];
89156822Seric 
89260537Seric 	if (tTd(38, 2))
89368350Seric 		printf("bt_map_open(%s, %s, %d)\n",
89468350Seric 			map->map_mname, map->map_file, mode);
89560089Seric 
89660582Seric 	omode = mode;
89760582Seric 	if (omode == O_RDWR)
89860582Seric 	{
89960582Seric 		omode |= O_CREAT|O_TRUNC;
90065830Seric #if defined(O_EXLOCK) && HASFLOCK
90160582Seric 		omode |= O_EXLOCK;
90266843Seric # if !OLD_NEWDB
90360582Seric 	}
90460582Seric 	else
90560582Seric 	{
90660582Seric 		omode |= O_SHLOCK;
90760582Seric # endif
90860582Seric #endif
90960582Seric 	}
91060207Seric 
91160228Seric 	(void) strcpy(buf, map->map_file);
91260228Seric 	i = strlen(buf);
91360228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
91460228Seric 		(void) strcat(buf, ".db");
91560582Seric 	db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
91656822Seric 	if (db == NULL)
91756822Seric 	{
91864718Seric #ifdef MAYBENEXTRELEASE
91964718Seric 		if (aliaswait(map, ".db", FALSE))
92064718Seric 			return TRUE;
92164718Seric #endif
92260207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
92356836Seric 			syserr("Cannot open BTREE database %s", map->map_file);
92456822Seric 		return FALSE;
92556822Seric 	}
92668350Seric #if !OLD_NEWDB
92764373Seric 	fd = db->fd(db);
92868778Seric # if defined(O_EXLOCK) && HASFLOCK
92968778Seric 	if (fd >= 0)
93068778Seric 	{
93168778Seric 		if (mode == O_RDONLY)
93268778Seric 			(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
93368778Seric 		else
93468778Seric 			map->map_mflags |= MF_LOCKED;
93568778Seric 	}
93668778Seric # else
93764373Seric 	if (mode == O_RDWR && fd >= 0)
93864388Seric 	{
93964388Seric 		if (lockfile(fd, map->map_file, ".db", LOCK_EX))
94064388Seric 			map->map_mflags |= MF_LOCKED;
94164388Seric 	}
94260582Seric # endif
94360582Seric #endif
94460585Seric 
94560585Seric 	/* try to make sure that at least the database header is on disk */
94660585Seric 	if (mode == O_RDWR)
94766843Seric #if OLD_NEWDB
94864373Seric 		(void) db->sync(db);
94964373Seric #else
95060585Seric 		(void) db->sync(db, 0);
95160585Seric 
95264373Seric 	if (fd >= 0 && fstat(fd, &st) >= 0)
95364284Seric 		map->map_mtime = st.st_mtime;
95464284Seric #endif
95564284Seric 
95660089Seric 	map->map_db2 = (void *) db;
95760207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
95864718Seric 		if (!aliaswait(map, ".db", TRUE))
95964718Seric 			return FALSE;
96056822Seric 	return TRUE;
96156822Seric }
96256822Seric 
96356822Seric 
96456822Seric /*
96556822Seric **  HASH_MAP_INIT -- HASH-style map initialization
96656822Seric */
96756822Seric 
96856822Seric bool
96960089Seric hash_map_open(map, mode)
97056822Seric 	MAP *map;
97160089Seric 	int mode;
97256822Seric {
97356822Seric 	DB *db;
97460228Seric 	int i;
97560582Seric 	int omode;
97664373Seric 	int fd;
97764284Seric 	struct stat st;
97868528Seric 	char buf[MAXNAME + 1];
97956822Seric 
98060537Seric 	if (tTd(38, 2))
98168350Seric 		printf("hash_map_open(%s, %s, %d)\n",
98268350Seric 			map->map_mname, map->map_file, mode);
98360089Seric 
98460582Seric 	omode = mode;
98560582Seric 	if (omode == O_RDWR)
98660582Seric 	{
98760582Seric 		omode |= O_CREAT|O_TRUNC;
98865830Seric #if defined(O_EXLOCK) && HASFLOCK
98960582Seric 		omode |= O_EXLOCK;
99066843Seric # if !OLD_NEWDB
99160582Seric 	}
99260582Seric 	else
99360582Seric 	{
99460582Seric 		omode |= O_SHLOCK;
99560582Seric # endif
99660582Seric #endif
99760582Seric 	}
99860207Seric 
99960228Seric 	(void) strcpy(buf, map->map_file);
100060228Seric 	i = strlen(buf);
100160228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
100260228Seric 		(void) strcat(buf, ".db");
100360582Seric 	db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
100456822Seric 	if (db == NULL)
100556822Seric 	{
100664718Seric #ifdef MAYBENEXTRELEASE
100764718Seric 		if (aliaswait(map, ".db", FALSE))
100864718Seric 			return TRUE;
100964718Seric #endif
101060207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
101156836Seric 			syserr("Cannot open HASH database %s", map->map_file);
101256822Seric 		return FALSE;
101356822Seric 	}
101468350Seric #if !OLD_NEWDB
101564373Seric 	fd = db->fd(db);
101668778Seric # if defined(O_EXLOCK) && HASFLOCK
101768778Seric 	if (fd >= 0)
101868778Seric 	{
101968778Seric 		if (mode == O_RDONLY)
102068778Seric 			(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
102168778Seric 		else
102268778Seric 			map->map_mflags |= MF_LOCKED;
102368778Seric 	}
102468778Seric # else
102564373Seric 	if (mode == O_RDWR && fd >= 0)
102664388Seric 	{
102764388Seric 		if (lockfile(fd, map->map_file, ".db", LOCK_EX))
102864388Seric 			map->map_mflags |= MF_LOCKED;
102964388Seric 	}
103060582Seric # endif
103160582Seric #endif
103260585Seric 
103360585Seric 	/* try to make sure that at least the database header is on disk */
103460585Seric 	if (mode == O_RDWR)
103566843Seric #if OLD_NEWDB
103664373Seric 		(void) db->sync(db);
103764373Seric #else
103860585Seric 		(void) db->sync(db, 0);
103960585Seric 
104064373Seric 	if (fd >= 0 && fstat(fd, &st) >= 0)
104164284Seric 		map->map_mtime = st.st_mtime;
104264284Seric #endif
104364284Seric 
104460089Seric 	map->map_db2 = (void *) db;
104560207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
104664718Seric 		if (!aliaswait(map, ".db", TRUE))
104764718Seric 			return FALSE;
104856822Seric 	return TRUE;
104956822Seric }
105056822Seric 
105156822Seric 
105256822Seric /*
105356822Seric **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
105456822Seric */
105556822Seric 
105656822Seric char *
105760089Seric db_map_lookup(map, name, av, statp)
105856822Seric 	MAP *map;
105960089Seric 	char *name;
106056822Seric 	char **av;
106159084Seric 	int *statp;
106256822Seric {
106356822Seric 	DBT key, val;
106460422Seric 	register DB *db = (DB *) map->map_db2;
106560422Seric 	int st;
106660422Seric 	int saveerrno;
106764373Seric 	int fd;
106860089Seric 	char keybuf[MAXNAME + 1];
106956822Seric 
107060537Seric 	if (tTd(38, 20))
107168350Seric 		printf("db_map_lookup(%s, %s)\n",
107268350Seric 			map->map_mname, name);
107360089Seric 
107460089Seric 	key.size = strlen(name);
107560089Seric 	if (key.size > sizeof keybuf - 1)
107660089Seric 		key.size = sizeof keybuf - 1;
107760089Seric 	key.data = keybuf;
107860089Seric 	bcopy(name, keybuf, key.size + 1);
107960207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
108060089Seric 		makelower(keybuf);
108166843Seric #if !OLD_NEWDB
108264388Seric 	fd = db->fd(db);
108364388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
108464388Seric 		(void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH);
108560422Seric #endif
108663753Seric 	st = 1;
108763753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
108863753Seric 	{
108963753Seric 		st = db->get(db, &key, &val, 0);
109063753Seric 		if (st == 0)
109163753Seric 			map->map_mflags &= ~MF_TRY1NULL;
109263753Seric 	}
109363753Seric 	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
109463753Seric 	{
109563753Seric 		key.size++;
109663753Seric 		st = db->get(db, &key, &val, 0);
109763753Seric 		if (st == 0)
109863753Seric 			map->map_mflags &= ~MF_TRY0NULL;
109963753Seric 	}
110060422Seric 	saveerrno = errno;
110166843Seric #if !OLD_NEWDB
110264388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
110364373Seric 		(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
110460422Seric #endif
110560422Seric 	if (st != 0)
110660422Seric 	{
110760422Seric 		errno = saveerrno;
110860422Seric 		if (st < 0)
110960422Seric 			syserr("db_map_lookup: get (%s)", name);
111056822Seric 		return NULL;
111160422Seric 	}
111260207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
111363753Seric 		return map_rewrite(map, name, strlen(name), NULL);
111463753Seric 	else
111563753Seric 		return map_rewrite(map, val.data, val.size, av);
111656822Seric }
111756822Seric 
111860089Seric 
111960089Seric /*
112060089Seric **  DB_MAP_STORE -- store a datum in the NEWDB database
112156822Seric */
112256822Seric 
112360089Seric void
112460089Seric db_map_store(map, lhs, rhs)
112560089Seric 	register MAP *map;
112660089Seric 	char *lhs;
112760089Seric 	char *rhs;
112856822Seric {
112960089Seric 	int stat;
113060089Seric 	DBT key;
113160089Seric 	DBT data;
113260089Seric 	register DB *db = map->map_db2;
113356822Seric 
113460537Seric 	if (tTd(38, 20))
113568350Seric 		printf("db_map_store(%s, %s, %s)\n",
113668350Seric 			map->map_mname, lhs, rhs);
113760089Seric 
113860089Seric 	key.size = strlen(lhs);
113960089Seric 	key.data = lhs;
114060089Seric 
114160089Seric 	data.size = strlen(rhs);
114260089Seric 	data.data = rhs;
114360089Seric 
114460207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
114556822Seric 	{
114660089Seric 		key.size++;
114760089Seric 		data.size++;
114860089Seric 	}
114956836Seric 
115060089Seric 	stat = db->put(db, &key, &data, R_NOOVERWRITE);
115160089Seric 	if (stat > 0)
115260089Seric 	{
115368497Seric 		if (!bitset(MF_APPEND, map->map_mflags))
115468497Seric 			usrerr("050 Warning: duplicate alias name %s", lhs);
115568497Seric 		else
115668497Seric 		{
115768497Seric 			static char *buf = NULL;
115868497Seric 			static int bufsiz = 0;
115968497Seric 			DBT old;
116068497Seric 
116168497Seric 			old.data = db_map_lookup(map, key.data, NULL, &stat);
116268497Seric 			if (old.data != NULL)
116368497Seric 			{
116468497Seric 				old.size = strlen(old.data);
116568497Seric 				if (data.size + old.size + 2 > bufsiz)
116668497Seric 				{
116768497Seric 					if (buf != NULL)
116868497Seric 						(void) free(buf);
116968497Seric 					bufsiz = data.size + old.size + 2;
117068497Seric 					buf = xalloc(bufsiz);
117168497Seric 				}
117268497Seric 				sprintf(buf, "%s,%s", data.data, old.data);
117368497Seric 				data.size = data.size + old.size + 1;
117468497Seric 				data.data = buf;
117568497Seric 				if (tTd(38, 9))
117668497Seric 					printf("db_map_store append=%s\n", data.data);
117768497Seric 			}
117868497Seric 		}
117960089Seric 		stat = db->put(db, &key, &data, 0);
118060089Seric 	}
118160089Seric 	if (stat != 0)
118260089Seric 		syserr("readaliases: db put (%s)", lhs);
118360089Seric }
118456836Seric 
118556847Seric 
118660089Seric /*
118760089Seric **  DB_MAP_CLOSE -- add distinguished entries and close the database
118860089Seric */
118960089Seric 
119060089Seric void
119160089Seric db_map_close(map)
119260089Seric 	MAP *map;
119360089Seric {
119460089Seric 	register DB *db = map->map_db2;
119560089Seric 
119660537Seric 	if (tTd(38, 9))
119768350Seric 		printf("db_map_close(%s, %s, %x)\n",
119868350Seric 			map->map_mname, map->map_file, map->map_mflags);
119960089Seric 
120060207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
120158804Seric 	{
120260089Seric 		/* write out the distinguished alias */
120360089Seric 		db_map_store(map, "@", "@");
120458804Seric 	}
120558963Seric 
120660089Seric 	if (db->close(db) != 0)
120760089Seric 		syserr("readaliases: db close failure");
120856822Seric }
120957208Seric 
121060089Seric #endif
121160089Seric /*
121260089Seric **  NIS Modules
121360089Seric */
121460089Seric 
121560089Seric # ifdef NIS
121660089Seric 
121764369Seric # ifndef YPERR_BUSY
121864369Seric #  define YPERR_BUSY	16
121964369Seric # endif
122064369Seric 
122157208Seric /*
122260089Seric **  NIS_MAP_OPEN -- open DBM map
122357208Seric */
122457208Seric 
122557208Seric bool
122660089Seric nis_map_open(map, mode)
122757208Seric 	MAP *map;
122860089Seric 	int mode;
122957208Seric {
123057216Seric 	int yperr;
123160215Seric 	register char *p;
123260215Seric 	auto char *vp;
123360215Seric 	auto int vsize;
123457216Seric 
123560537Seric 	if (tTd(38, 2))
123668350Seric 		printf("nis_map_open(%s, %s)\n",
123768350Seric 			map->map_mname, map->map_file);
123860089Seric 
123960207Seric 	if (mode != O_RDONLY)
124060207Seric 	{
124164650Seric 		/* issue a pseudo-error message */
124264650Seric #ifdef ENOSYS
124364650Seric 		errno = ENOSYS;
124464650Seric #else
124564650Seric # ifdef EFTYPE
124664650Seric 		errno = EFTYPE;
124764650Seric # else
124864650Seric 		errno = ENXIO;
124964650Seric # endif
125064650Seric #endif
125160207Seric 		return FALSE;
125260207Seric 	}
125360207Seric 
125460089Seric 	p = strchr(map->map_file, '@');
125560089Seric 	if (p != NULL)
125660089Seric 	{
125760089Seric 		*p++ = '\0';
125860089Seric 		if (*p != '\0')
125960089Seric 			map->map_domain = p;
126060089Seric 	}
126160215Seric 
126260089Seric 	if (*map->map_file == '\0')
126360089Seric 		map->map_file = "mail.aliases";
126460089Seric 
126566157Seric 	if (map->map_domain == NULL)
126666157Seric 	{
126766157Seric 		yperr = yp_get_default_domain(&map->map_domain);
126866157Seric 		if (yperr != 0)
126966157Seric 		{
127066744Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
127168350Seric 				syserr("421 NIS map %s specified, but NIS not running\n",
127266744Seric 					map->map_file);
127366157Seric 			return FALSE;
127466157Seric 		}
127566157Seric 	}
127666157Seric 
127760215Seric 	/* check to see if this map actually exists */
127860089Seric 	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
127960089Seric 			&vp, &vsize);
128060537Seric 	if (tTd(38, 10))
128160089Seric 		printf("nis_map_open: yp_match(%s, %s) => %s\n",
128260089Seric 			map->map_domain, map->map_file, yperr_string(yperr));
128360089Seric 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
128468350Seric 	{
128568350Seric 		if (!bitset(MF_ALIAS, map->map_mflags) ||
128668350Seric 		    aliaswait(map, NULL, TRUE))
128768350Seric 			return TRUE;
128868350Seric 	}
128960215Seric 
129060215Seric 	if (!bitset(MF_OPTIONAL, map->map_mflags))
129168735Seric 	{
129268735Seric 		syserr("421 Cannot bind to map %s in domain %s: %s",
129368735Seric 			map->map_file, map->map_domain, yperr_string(yperr));
129468735Seric 	}
129560215Seric 
129660089Seric 	return FALSE;
129760089Seric }
129860089Seric 
129960089Seric 
130060089Seric /*
130157208Seric **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
130257208Seric */
130357208Seric 
130457208Seric char *
130560089Seric nis_map_lookup(map, name, av, statp)
130657208Seric 	MAP *map;
130760089Seric 	char *name;
130857208Seric 	char **av;
130959084Seric 	int *statp;
131057208Seric {
131157208Seric 	char *vp;
131257642Seric 	auto int vsize;
131359274Seric 	int buflen;
131460215Seric 	int yperr;
131560089Seric 	char keybuf[MAXNAME + 1];
131657208Seric 
131760537Seric 	if (tTd(38, 20))
131868350Seric 		printf("nis_map_lookup(%s, %s)\n",
131968350Seric 			map->map_mname, name);
132060089Seric 
132160089Seric 	buflen = strlen(name);
132260089Seric 	if (buflen > sizeof keybuf - 1)
132360089Seric 		buflen = sizeof keybuf - 1;
132460089Seric 	bcopy(name, keybuf, buflen + 1);
132560207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
132660089Seric 		makelower(keybuf);
132763753Seric 	yperr = YPERR_KEY;
132863753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
132963753Seric 	{
133063753Seric 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
133163753Seric 			     &vp, &vsize);
133263753Seric 		if (yperr == 0)
133363753Seric 			map->map_mflags &= ~MF_TRY1NULL;
133463753Seric 	}
133563753Seric 	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
133663753Seric 	{
133759274Seric 		buflen++;
133863753Seric 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
133963753Seric 			     &vp, &vsize);
134063753Seric 		if (yperr == 0)
134163753Seric 			map->map_mflags &= ~MF_TRY0NULL;
134263753Seric 	}
134360089Seric 	if (yperr != 0)
134460089Seric 	{
134560089Seric 		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
134660215Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
134757208Seric 		return NULL;
134860089Seric 	}
134960207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
135063753Seric 		return map_rewrite(map, name, strlen(name), NULL);
135163753Seric 	else
135263753Seric 		return map_rewrite(map, vp, vsize, av);
135357208Seric }
135457208Seric 
135569401Seric 
135669401Seric /*
135769401Seric **  NIS_GETCANONNAME -- look up canonical name in NIS
135869401Seric */
135969401Seric 
136069401Seric bool
136169401Seric nis_getcanonname(name, hbsize, statp)
136269401Seric 	char *name;
136369401Seric 	int hbsize;
136469401Seric 	int *statp;
136569401Seric {
136669401Seric 	char *vp;
136769401Seric 	auto int vsize;
136869401Seric 	int keylen;
136969401Seric 	int yperr;
137069401Seric 	static bool try0null = TRUE;
137169401Seric 	static bool try1null = TRUE;
137269401Seric 	static char *yp_domain = NULL;
137369748Seric 	char *domain;
137469401Seric 	char host_record[MAXLINE];
137569833Seric 	char cbuf[MAXNAME];
137669780Seric 	char nbuf[MAXNAME + 1];
137769401Seric 	extern char *get_column();
137869401Seric 
137969401Seric 	if (tTd(38, 20))
138069401Seric 		printf("nis_getcanonname(%s)\n", name);
138169401Seric 
138269780Seric 	if (strlen(name) >= sizeof nbuf)
138369780Seric 	{
138469780Seric 		*statp = EX_UNAVAILABLE;
138569780Seric 		return FALSE;
138669780Seric 	}
138769780Seric 	(void) strcpy(nbuf, name);
138869780Seric 	shorten_hostname(nbuf);
138969401Seric 
139069401Seric 	/* we only accept single token search key */
139169780Seric 	if (strchr(nbuf, '.'))
139269401Seric 	{
139369401Seric 		*statp = EX_NOHOST;
139469401Seric 		return FALSE;
139569401Seric 	}
139669401Seric 
139769780Seric 	keylen = strlen(nbuf);
139869401Seric 
139969401Seric 	if (yp_domain == NULL)
140069401Seric 		yp_get_default_domain(&yp_domain);
140169780Seric 	makelower(nbuf);
140269401Seric 	yperr = YPERR_KEY;
140369401Seric 	if (try0null)
140469401Seric 	{
140569780Seric 		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
140669401Seric 			     &vp, &vsize);
140769401Seric 		if (yperr == 0)
140869401Seric 			try1null = FALSE;
140969401Seric 	}
141069401Seric 	if (yperr == YPERR_KEY && try1null)
141169401Seric 	{
141269401Seric 		keylen++;
141369780Seric 		yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
141469401Seric 			     &vp, &vsize);
141569401Seric 		if (yperr == 0)
141669401Seric 			try0null = FALSE;
141769401Seric 	}
141869401Seric 	if (yperr != 0)
141969401Seric 	{
142069401Seric 		if (yperr == YPERR_KEY)
142169401Seric 			*statp = EX_NOHOST;
142269401Seric 		else if (yperr == YPERR_BUSY)
142369401Seric 			*statp = EX_TEMPFAIL;
142469401Seric 		else
142569401Seric 			*statp = EX_UNAVAILABLE;
142669401Seric 		return FALSE;
142769401Seric 	}
142869401Seric 	strncpy(host_record, vp, vsize);
142969401Seric 	host_record[vsize] = '\0';
143069663Seric 	if (tTd(38, 44))
143169663Seric 		printf("got record `%s'\n", host_record);
143269833Seric 	if (!extract_canonname(nbuf, host_record, cbuf))
143369401Seric 	{
143469401Seric 		/* this should not happen, but.... */
143569401Seric 		*statp = EX_NOHOST;
143669401Seric 		return FALSE;
143769401Seric 	}
143869833Seric 	if (hbsize < strlen(cbuf))
143969401Seric 	{
144069833Seric 		*statp = EX_UNAVAILABLE;
144169833Seric 		return FALSE;
144269703Seric 	}
144369833Seric 	strcpy(name, cbuf);
144469833Seric 	*statp = EX_OK;
144569833Seric 	return TRUE;
144669401Seric }
144769401Seric 
144868350Seric #endif
144968350Seric /*
145068350Seric **  NISPLUS Modules
145168350Seric **
145268350Seric **	This code donated by Sun Microsystems.
145368350Seric */
145467848Seric 
145568350Seric #ifdef NISPLUS
145668350Seric 
145768350Seric #undef NIS /* symbol conflict in nis.h */
145868350Seric #include <rpcsvc/nis.h>
145968350Seric #include <rpcsvc/nislib.h>
146068350Seric 
146168350Seric #define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
146268350Seric #define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
146368350Seric #define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
146468350Seric #define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
146568350Seric 
146667848Seric /*
146768350Seric **  NISPLUS_MAP_OPEN -- open nisplus table
146867848Seric */
146967848Seric 
147068350Seric bool
147168350Seric nisplus_map_open(map, mode)
147267848Seric 	MAP *map;
147368350Seric 	int mode;
147467848Seric {
147568350Seric 	register char *p;
147668350Seric 	char qbuf[MAXLINE + NIS_MAXNAMELEN];
147768350Seric 	nis_result *res = NULL;
147868350Seric 	u_int objs_len;
147968350Seric 	nis_object *obj_ptr;
148068350Seric 	int retry_cnt, max_col, i;
148168350Seric 
148268350Seric 	if (tTd(38, 2))
148368350Seric 		printf("nisplus_map_open(%s, %s, %d)\n",
148468350Seric 			map->map_mname, map->map_file, mode);
148568350Seric 
148668350Seric 	if (mode != O_RDONLY)
148768350Seric 	{
148868350Seric 		errno = ENODEV;
148968350Seric 		return FALSE;
149068350Seric 	}
149168350Seric 
149268350Seric 	if (*map->map_file == '\0')
149368350Seric 		map->map_file = "mail_aliases.org_dir";
149468350Seric 
149568350Seric 	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
149668350Seric 	{
149768350Seric 		/* set default NISPLUS Domain to $m */
149868350Seric 		extern char *nisplus_default_domain();
149968350Seric 
150068350Seric 		map->map_domain = newstr(nisplus_default_domain());
150168350Seric 		if (tTd(38, 2))
150268350Seric 			printf("nisplus_map_open(%s): using domain %s\n",
150368350Seric 				 map->map_file, map->map_domain);
150468350Seric 	}
150568350Seric 	if (!PARTIAL_NAME(map->map_file))
150668350Seric 		map->map_domain = newstr("");
150768350Seric 
150868350Seric 	/* check to see if this map actually exists */
150968350Seric 	if (PARTIAL_NAME(map->map_file))
151068350Seric 		sprintf(qbuf, "%s.%s", map->map_file, map->map_domain);
151168350Seric 	else
151268350Seric 		strcpy(qbuf, map->map_file);
151368350Seric 
151468350Seric 	retry_cnt = 0;
151568350Seric 	while (res == NULL || res->status != NIS_SUCCESS)
151668350Seric 	{
151768350Seric 		res = nis_lookup(qbuf, FOLLOW_LINKS);
151868350Seric 		switch (res->status)
151968350Seric 		{
152068350Seric 		  case NIS_SUCCESS:
152168350Seric 		  case NIS_TRYAGAIN:
152268350Seric 		  case NIS_RPCERROR:
152368350Seric 		  case NIS_NAMEUNREACHABLE:
152468350Seric 			break;
152568350Seric 
152668350Seric 		  default:		/* all other nisplus errors */
152768350Seric #if 0
152868350Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
152968350Seric 				syserr("421 Cannot find table %s.%s: %s",
153068350Seric 					map->map_file, map->map_domain,
153168350Seric 					nis_sperrno(res->status));
153268350Seric #endif
153368350Seric 			errno = EBADR;
153468350Seric 			return FALSE;
153568350Seric 		}
153668350Seric 		sleep(2);		/* try not to overwhelm hosed server */
153768350Seric 		if (retry_cnt++ > 4)
153868350Seric 		{
153968350Seric 			errno = EBADR;
154068350Seric 			return FALSE;
154168350Seric 		}
154268350Seric 	}
154368350Seric 
154468350Seric 	if (NIS_RES_NUMOBJ(res) != 1 ||
154568350Seric 	    (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
154668350Seric 	{
154768350Seric 		if (tTd(38, 10))
154868350Seric 			printf("nisplus_map_open: %s is not a table\n", qbuf);
154968350Seric #if 0
155068350Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
155168350Seric 			syserr("421 %s.%s: %s is not a table",
155268350Seric 				map->map_file, map->map_domain,
155368350Seric 				nis_sperrno(res->status));
155468350Seric #endif
155568350Seric 		errno = EBADR;
155668350Seric 		return FALSE;
155768350Seric 	}
155868350Seric 	/* default key column is column 0 */
155968350Seric 	if (map->map_keycolnm == NULL)
156068350Seric 		map->map_keycolnm = newstr(COL_NAME(res,0));
156168350Seric 
156268350Seric 	max_col = COL_MAX(res);
156368350Seric 
156468350Seric 	/* verify the key column exist */
156568350Seric 	for (i=0; i< max_col; i++)
156668350Seric 	{
156768350Seric 		if (!strcmp(map->map_keycolnm, COL_NAME(res,i)))
156868350Seric 			break;
156968350Seric 	}
157068350Seric 	if (i == max_col)
157168350Seric 	{
157268350Seric 		if (tTd(38, 2))
157368350Seric 			printf("nisplus_map_open(%s): can not find key column %s\n",
157468350Seric 				map->map_file, map->map_keycolnm);
157568350Seric 		errno = EBADR;
157668350Seric 		return FALSE;
157768350Seric 	}
157868350Seric 
157968350Seric 	/* default value column is the last column */
158068350Seric 	if (map->map_valcolnm == NULL)
158168350Seric 	{
158268350Seric 		map->map_valcolno = max_col - 1;
158368350Seric 		return TRUE;
158468350Seric 	}
158568350Seric 
158668350Seric 	for (i=0; i< max_col; i++)
158768350Seric 	{
158868350Seric 		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
158968350Seric 		{
159068350Seric 			map->map_valcolno = i;
159168350Seric 			return TRUE;
159268350Seric 		}
159368350Seric 	}
159468350Seric 
159568350Seric 	if (tTd(38, 2))
159668350Seric 		printf("nisplus_map_open(%s): can not find column %s\n",
159768350Seric 			 map->map_file, map->map_keycolnm);
159868350Seric 	errno = EBADR;
159968350Seric 	return FALSE;
160067848Seric }
160167848Seric 
160267848Seric 
160367848Seric /*
160468350Seric **  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
160567848Seric */
160667848Seric 
160768350Seric char *
160868350Seric nisplus_map_lookup(map, name, av, statp)
160967848Seric 	MAP *map;
161068350Seric 	char *name;
161168350Seric 	char **av;
161268350Seric 	int *statp;
161367848Seric {
161468350Seric 	char *vp;
161568350Seric 	auto int vsize;
161668350Seric 	int buflen;
161768350Seric 	char search_key[MAXNAME + 1];
161868350Seric 	char qbuf[MAXLINE + NIS_MAXNAMELEN];
161968350Seric 	nis_result *result;
162068350Seric 
162168350Seric 	if (tTd(38, 20))
162268350Seric 		printf("nisplus_map_lookup(%s, %s)\n",
162368350Seric 			map->map_mname, name);
162468350Seric 
162568350Seric 	if (!bitset(MF_OPEN, map->map_mflags))
162668350Seric 	{
162768350Seric 		if (nisplus_map_open(map, O_RDONLY))
162868350Seric 			map->map_mflags |= MF_OPEN;
162968350Seric 		else
163068350Seric 		{
163168350Seric 			*statp = EX_UNAVAILABLE;
163268350Seric 			return NULL;
163368350Seric 		}
163468350Seric 	}
163568350Seric 
163668350Seric 	buflen = strlen(name);
163768350Seric 	if (buflen > sizeof search_key - 1)
163868350Seric 		buflen = sizeof search_key - 1;
163968350Seric 	bcopy(name, search_key, buflen + 1);
164068350Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
164168350Seric 		makelower(search_key);
164268350Seric 
164368350Seric 	/* construct the query */
164468350Seric 	if (PARTIAL_NAME(map->map_file))
164568350Seric 		sprintf(qbuf, "[%s=%s],%s.%s", map->map_keycolnm,
164668350Seric 			search_key, map->map_file, map->map_domain);
164768350Seric 	else
164868350Seric 		sprintf(qbuf, "[%s=%s],%s", map->map_keycolnm,
164968350Seric 			search_key, map->map_file);
165068350Seric 
165168350Seric 	if (tTd(38, 20))
165268350Seric 		printf("qbuf=%s\n", qbuf);
165368350Seric 	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
165468350Seric 	if (result->status == NIS_SUCCESS)
165568350Seric 	{
165668350Seric 		int count;
165768350Seric 		char *str;
165868350Seric 
165968350Seric 		if ((count = NIS_RES_NUMOBJ(result)) != 1)
166068350Seric 		{
166168350Seric 			if (LogLevel > 10)
166268350Seric 				syslog(LOG_WARNING,
166368350Seric 				  "%s:Lookup error, expected 1 entry, got (%d)",
166468350Seric 				    map->map_file, count);
166568350Seric 
166668350Seric 			/* ignore second entry */
166768350Seric 			if (tTd(38, 20))
166868350Seric 				printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
166968350Seric 					name, count);
167068350Seric 		}
167168350Seric 
167268350Seric 		vp = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
167368350Seric 		/* set the length of the result */
167468350Seric 		if (vp == NULL)
167568350Seric 			vp = "";
167668350Seric 		vsize = strlen(vp);
167768350Seric 		if (tTd(38, 20))
167868350Seric 			printf("nisplus_map_lookup(%s), found %s\n",
167968350Seric 				name, vp);
168068350Seric 		if (bitset(MF_MATCHONLY, map->map_mflags))
168168350Seric 			str = map_rewrite(map, name, strlen(name), NULL);
168268350Seric 		else
168368350Seric 			str = map_rewrite(map, vp, vsize, av);
168468350Seric 		nis_freeresult(result);
168568350Seric #ifdef MAP_EXIT_STAT
168668350Seric 		*statp = EX_OK;
168768350Seric #endif
168868350Seric 		return str;
168968350Seric 	}
169068350Seric 	else
169168350Seric 	{
169268350Seric #ifdef MAP_EXIT_STAT
169368350Seric 		if (result->status == NIS_NOTFOUND)
169468350Seric 			*statp = EX_NOTFOUND;
169568350Seric 		else if (result->status == NIS_TRYAGAIN)
169668350Seric 			*statp = EX_TEMPFAIL;
169768350Seric 		else
169868350Seric 		{
169968350Seric 			*statp = EX_UNAVAILABLE;
170068350Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
170168350Seric 		}
170268350Seric #else
170368350Seric 		if ((result->status != NIS_NOTFOUND) &&
170468350Seric 		    (result->status != NIS_TRYAGAIN))
170568350Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
170668350Seric #endif
170768350Seric 	}
170868350Seric 	if (tTd(38, 20))
170968350Seric 		printf("nisplus_map_lookup(%s), failed\n", name);
171068350Seric 	nis_freeresult(result);
171168350Seric 	return NULL;
171267848Seric }
171367848Seric 
171468350Seric 
171569401Seric 
171669401Seric /*
171769401Seric **  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
171869401Seric */
171969401Seric 
172069401Seric bool
172169401Seric nisplus_getcanonname(name, hbsize, statp)
172269401Seric 	char *name;
172369401Seric 	int hbsize;
172469401Seric 	int *statp;
172569401Seric {
172669401Seric 	char *vp;
172769401Seric 	auto int vsize;
172869401Seric 	int buflen;
172969401Seric 	nis_result *result;
173069401Seric 	char *p;
173169401Seric 	int len;
173269780Seric 	char nbuf[MAXNAME + 1];
173369780Seric 	char qbuf[MAXLINE + NIS_MAXNAMELEN];
173469401Seric 
173569780Seric 	if (strlen(name) >= sizeof nbuf)
173669780Seric 	{
173769780Seric 		*statp = EX_UNAVAILABLE;
173869780Seric 		return FALSE;
173969780Seric 	}
174069780Seric 	(void) strcpy(nbuf, name);
174169780Seric 	shorten_hostname(nbuf);
174269401Seric 
174369780Seric 	p = strchr(nbuf, '.');
174469401Seric 	if (p == NULL)
174569401Seric 	{
174669401Seric 		/* single token */
174769780Seric 		sprintf(qbuf, "[name=%s],hosts.org_dir", nbuf);
174869401Seric 	}
174969401Seric 	else if (p[1] != '\0')
175069401Seric 	{
175169780Seric 		/* multi token -- take only first token in nbuf */
175269401Seric 		*p = '\0';
175369780Seric 		sprintf(qbuf, "[name=%s],hosts.org_dir.%s", nbuf, &p[1]);
175469401Seric 	}
175569401Seric 	else
175669401Seric 	{
175769401Seric 		*statp = EX_NOHOST;
175869401Seric 		return FALSE;
175969401Seric 	}
176069401Seric 
176169401Seric 	if (tTd(38, 20))
176269478Seric 		printf("\nnisplus_getcanoname(%s), qbuf=%s\n",
176369780Seric 			 name, qbuf);
176469401Seric 
176569780Seric 	result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
176669401Seric 		NULL, NULL);
176769401Seric 
176869401Seric 	if (result->status == NIS_SUCCESS)
176969401Seric 	{
177069401Seric 		int count;
177169401Seric 		char *str;
177269401Seric 		char *domain;
177369401Seric 
177469401Seric 		if ((count = NIS_RES_NUMOBJ(result)) != 1)
177569401Seric 		{
177669401Seric #ifdef LOG
177769401Seric 			if (LogLevel > 10)
177869401Seric 				syslog(LOG_WARNING,
177969401Seric 				       "nisplus_getcanonname: Lookup error, expected 1 entry, got (%d)",
178069401Seric 				       count);
178169401Seric #endif
178269401Seric 
178369401Seric 			/* ignore second entry */
178469401Seric 			if (tTd(38, 20))
178569401Seric 				printf("nisplus_getcanoname(%s), got %d entries, addtional entries ignores\n", name);
178669401Seric 		}
178769401Seric 
178869401Seric 		if (tTd(38, 20))
178969401Seric 			printf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
179069401Seric 			       name, (NIS_RES_OBJECT(result))->zo_domain);
179169401Seric 
179269401Seric 
179369401Seric 		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
179469401Seric 		vsize = strlen(vp);
179569401Seric 		if (tTd(38, 20))
179669401Seric 			printf("nisplus_getcanonname(%s), found %s\n",
179769401Seric 				name, vp);
179869703Seric 		if (strchr(vp, '.') != NULL)
179969703Seric 		{
180069636Seric 			domain = "";
180169703Seric 		}
180269703Seric 		else
180369703Seric 		{
180469703Seric 			domain = macvalue('m', CurEnv);
180569703Seric 			if (domain == NULL)
180669703Seric 				domain = "";
180769703Seric 		}
180869636Seric 		if (hbsize > vsize + (int) strlen(domain) + 1)
180969401Seric 		{
181069636Seric 			if (domain[0] == '\0')
181169636Seric 				strcpy(name, vp);
181269636Seric 			else
181369636Seric 				sprintf(name, "%s.%s", vp, domain);
181469401Seric 			*statp = EX_OK;
181569401Seric 		}
181669401Seric 		else
181769401Seric 			*statp = EX_NOHOST;
181869401Seric 		nis_freeresult(result);
181969401Seric 		return TRUE;
182069401Seric 	}
182169401Seric 	else
182269401Seric 	{
182369401Seric 		if (result->status == NIS_NOTFOUND)
182469401Seric 			*statp = EX_NOHOST;
182569401Seric 		else if (result->status == NIS_TRYAGAIN)
182669401Seric 			*statp = EX_TEMPFAIL;
182769401Seric 		else
182869401Seric 			*statp = EX_UNAVAILABLE;
182969401Seric 	}
183069401Seric 	if (tTd(38, 20))
183169401Seric 		printf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
183269401Seric 			name, result->status, *statp);
183369401Seric 	nis_freeresult(result);
183469401Seric 	return FALSE;
183569401Seric }
183669401Seric 
183769401Seric 
183868350Seric char *
183968350Seric nisplus_default_domain()
184068350Seric {
184168528Seric 	static char default_domain[MAXNAME + 1] = "";
184268350Seric 	char *p;
184368350Seric 
184468350Seric 	if (default_domain[0] != '\0')
184568350Seric 		return(default_domain);
184668350Seric 
184768458Seric 	p = nis_local_directory();
184868350Seric 	strcpy(default_domain, p);
184968458Seric 	return default_domain;
185068350Seric }
185168350Seric 
185268350Seric #endif /* NISPLUS */
185367848Seric /*
185468350Seric **  HESIOD Modules
185568350Seric */
185668350Seric 
185768350Seric #ifdef HESIOD
185868350Seric 
185968350Seric #include <hesiod.h>
186068350Seric 
186168350Seric char *
186268350Seric hes_map_lookup(map, name, av, statp)
186368350Seric         MAP *map;
186468350Seric         char *name;
186568350Seric         char **av;
186668350Seric         int *statp;
186768350Seric {
186868350Seric 	char **hp;
186968350Seric 
187068350Seric 	if (tTd(38, 20))
187168350Seric 		printf("hes_map_lookup(%s, %s)\n", map->map_file, name);
187268350Seric 
187369688Seric 	if (name[0] == '\\')
187469688Seric 	{
187569688Seric 		char *np;
187669688Seric 		int nl;
187769688Seric 		char nbuf[MAXNAME];
187869688Seric 
187969688Seric 		nl = strlen(name);
188069688Seric 		if (nl < sizeof nbuf - 1)
188169688Seric 			np = nbuf;
188269688Seric 		else
188369688Seric 			np = xalloc(strlen(name) + 2);
188469688Seric 		np[0] = '\\';
188569688Seric 		strcpy(&np[1], name);
188669688Seric 		hp = hes_resolve(np, map->map_file);
188769688Seric 		if (np != nbuf)
188869688Seric 			free(np);
188969688Seric 	}
189069688Seric 	else
189169688Seric 	{
189269688Seric 		hp = hes_resolve(name, map->map_file);
189369688Seric 	}
189469623Seric 	if (hp == NULL || hp[0] == NULL)
189568350Seric 		return NULL;
189668350Seric 
189769623Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
189869623Seric 		return map_rewrite(map, name, strlen(name), NULL);
189969623Seric 	else
190069623Seric 		return map_rewrite(map, hp[0], strlen(hp[0]), av);
190168350Seric }
190268350Seric 
190368350Seric #endif
190468350Seric /*
190568350Seric **  NeXT NETINFO Modules
190668350Seric */
190768350Seric 
190868350Seric #ifdef NETINFO
190968350Seric 
191068350Seric #define NETINFO_DEFAULT_DIR		"/aliases"
191168350Seric #define NETINFO_DEFAULT_PROPERTY	"members"
191268350Seric 
191368350Seric 
191468350Seric /*
191568350Seric **  NI_MAP_OPEN -- open NetInfo Aliases
191668350Seric */
191768350Seric 
191868350Seric bool
191968350Seric ni_map_open(map, mode)
192068350Seric 	MAP *map;
192168350Seric 	int mode;
192268350Seric {
192368350Seric 	char *p;
192468350Seric 
192568350Seric 	if (tTd(38, 20))
192668350Seric 		printf("ni_map_open: %s\n", map->map_file);
192768350Seric 
192868350Seric 	if (*map->map_file == '\0')
192968350Seric 		map->map_file = NETINFO_DEFAULT_DIR;
193068350Seric 
193168350Seric 	if (map->map_valcolnm == NULL)
193268350Seric 		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
193368350Seric 
193468350Seric 	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
193568350Seric 		map->map_coldelim = ',';
193668350Seric 
193768350Seric 	return TRUE;
193868350Seric }
193968350Seric 
194068350Seric 
194168350Seric /*
194268350Seric **  NI_MAP_LOOKUP -- look up a datum in NetInfo
194368350Seric */
194468350Seric 
194568350Seric char *
194668350Seric ni_map_lookup(map, name, av, statp)
194768350Seric 	MAP *map;
194868350Seric 	char *name;
194968350Seric 	char **av;
195068350Seric 	int *statp;
195168350Seric {
195268350Seric 	char *res;
195368350Seric 	char *propval;
195468350Seric 	extern char *ni_propval();
195568350Seric 
195668350Seric 	if (tTd(38, 20))
195768350Seric 		printf("ni_map_lookup(%s, %s)\n",
195868350Seric 			map->map_mname, name);
195968350Seric 
196068350Seric 	propval = ni_propval(map->map_file, map->map_keycolnm, name,
196168350Seric 			     map->map_valcolnm, map->map_coldelim);
196268350Seric 
196368350Seric 	if (propval == NULL)
196468350Seric 		return NULL;
196568350Seric 
196668350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
196768350Seric 		res = map_rewrite(map, name, strlen(name), NULL);
196868350Seric 	else
196968350Seric 		res = map_rewrite(map, propval, strlen(propval), av);
197068350Seric 	free(propval);
197168350Seric 	return res;
197268350Seric }
197368350Seric 
197468350Seric #endif
197568350Seric /*
197668350Seric **  TEXT (unindexed text file) Modules
197768350Seric **
197868350Seric **	This code donated by Sun Microsystems.
197968350Seric */
198068350Seric 
198168350Seric 
198268350Seric /*
198368350Seric **  TEXT_MAP_OPEN -- open text table
198468350Seric */
198568350Seric 
198668350Seric bool
198768350Seric text_map_open(map, mode)
198868350Seric 	MAP *map;
198968350Seric 	int mode;
199068350Seric {
199168350Seric 	struct stat sbuf;
199268350Seric 
199368350Seric 	if (tTd(38, 2))
199468350Seric 		printf("text_map_open(%s, %s, %d)\n",
199568350Seric 			map->map_mname, map->map_file, mode);
199668350Seric 
199768350Seric 	if (mode != O_RDONLY)
199868350Seric 	{
199968350Seric 		errno = ENODEV;
200068350Seric 		return FALSE;
200168350Seric 	}
200268350Seric 
200368350Seric 	if (*map->map_file == '\0')
200468350Seric 	{
200568350Seric 		if (tTd(38, 2))
200668350Seric 			printf("text_map_open: file name required\n");
200768350Seric 		return FALSE;
200868350Seric 	}
200968350Seric 
201068350Seric 	if (map->map_file[0] != '/')
201168350Seric 	{
201268350Seric 		if (tTd(38, 2))
201368350Seric 			printf("text_map_open(%s): file name must be fully qualified\n",
201468350Seric 				map->map_file);
201568350Seric 		return FALSE;
201668350Seric 	}
201768350Seric 	/* check to see if this map actually accessable */
201868350Seric 	if (access(map->map_file, R_OK) <0)
201968350Seric 		return FALSE;
202068350Seric 
202168350Seric 	/* check to see if this map actually exist */
202268350Seric 	if (stat(map->map_file, &sbuf) <0)
202368350Seric 	{
202468350Seric 		if (tTd(38, 2))
202568350Seric 			printf("text_map_open(%s): can not stat %s\n",
202668350Seric 				map->map_file, map->map_file);
202768350Seric 		return FALSE;
202868350Seric 	}
202968350Seric 
203068350Seric 	if (!S_ISREG(sbuf.st_mode))
203168350Seric 	{
203268350Seric 		if (tTd(38, 2))
203368350Seric 			printf("text_map_open(%s): %s is not a file\n",
203468350Seric 				map->map_file, map->map_file);
203568350Seric 		return FALSE;
203668350Seric 	}
203768350Seric 
203868350Seric 	if (map->map_keycolnm == NULL)
203968350Seric 		map->map_keycolno = 0;
204068350Seric 	else
204168350Seric 	{
204268350Seric 		if (!isdigit(*map->map_keycolnm))
204368350Seric 		{
204468350Seric 			if (tTd(38, 2))
204568350Seric 				printf("text_map_open(%s): -k should specify a number, not %s\n",
204668350Seric 					map->map_file, map->map_keycolnm);
204768350Seric 			return FALSE;
204868350Seric 		}
204968350Seric 		map->map_keycolno = atoi(map->map_keycolnm);
205068350Seric 	}
205168350Seric 
205268350Seric 	if (map->map_valcolnm == NULL)
205368350Seric 		map->map_valcolno = 0;
205468350Seric 	else
205568350Seric 	{
205668350Seric 		if (!isdigit(*map->map_valcolnm))
205768350Seric 		{
205868350Seric 			if (tTd(38, 2))
205968350Seric 				printf("text_map_open(%s): -v should specify a number, not %s\n",
206068350Seric 					map->map_file, map->map_valcolnm);
206168350Seric 			return FALSE;
206268350Seric 		}
206368350Seric 		map->map_valcolno = atoi(map->map_valcolnm);
206468350Seric 	}
206568350Seric 
206668350Seric 	if (tTd(38, 2))
206768350Seric 	{
206868520Seric 		printf("text_map_open(%s): delimiter = ",
206968520Seric 			map->map_file);
207068520Seric 		if (map->map_coldelim == '\0')
207168520Seric 			printf("(white space)\n");
207268520Seric 		else
207368520Seric 			printf("%c\n", map->map_coldelim);
207468350Seric 	}
207568350Seric 
207668350Seric 	return TRUE;
207768350Seric }
207868350Seric 
207968350Seric 
208068350Seric /*
208168350Seric **  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
208268350Seric */
208368350Seric 
208468350Seric char *
208568350Seric text_map_lookup(map, name, av, statp)
208668350Seric 	MAP *map;
208768350Seric 	char *name;
208868350Seric 	char **av;
208968350Seric 	int *statp;
209068350Seric {
209168350Seric 	char *vp;
209268350Seric 	auto int vsize;
209368350Seric 	int buflen;
209468350Seric 	char search_key[MAXNAME + 1];
209568350Seric 	char linebuf[MAXLINE];
209668350Seric 	FILE *f;
209768528Seric 	char buf[MAXNAME + 1];
209868350Seric 	char delim;
209968350Seric 	int key_idx;
210068350Seric 	bool found_it;
210168350Seric 	extern char *get_column();
210268350Seric 
210368350Seric 
210468350Seric 	found_it = FALSE;
210568350Seric 	if (tTd(38, 20))
210668350Seric 		printf("text_map_lookup(%s)\n", name);
210768350Seric 
210868350Seric 	buflen = strlen(name);
210968350Seric 	if (buflen > sizeof search_key - 1)
211068350Seric 		buflen = sizeof search_key - 1;
211168350Seric 	bcopy(name, search_key, buflen + 1);
211268350Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
211368350Seric 		makelower(search_key);
211468350Seric 
211568350Seric 	f = fopen(map->map_file, "r");
211668350Seric 	if (f == NULL)
211768350Seric 	{
211868350Seric 		map->map_mflags &= ~(MF_VALID|MF_OPEN);
211968350Seric 		*statp = EX_UNAVAILABLE;
212068350Seric 		return NULL;
212168350Seric 	}
212268350Seric 	key_idx = map->map_keycolno;
212368350Seric 	delim = map->map_coldelim;
212468350Seric 	while (fgets(linebuf, MAXLINE, f))
212568350Seric 	{
212668350Seric 		char *lf;
212768350Seric 		if (linebuf[0] == '#')
212868350Seric 			continue; /* skip comment line */
212968350Seric 		if (lf = strchr(linebuf, '\n'))
213068350Seric 			*lf = '\0';
213168350Seric 		if (!strcasecmp(search_key,
213268350Seric 				get_column(linebuf, key_idx, delim, buf)))
213368350Seric 		{
213468350Seric 			found_it = TRUE;
213568350Seric 			break;
213668350Seric 		}
213768350Seric 	}
213868350Seric 	fclose(f);
213968350Seric 	if (!found_it)
214068350Seric 	{
214168350Seric #ifdef MAP_EXIT_STAT
214268350Seric 		*statp = EX_NOTFOUND;
214368350Seric #endif
214468350Seric 		return(NULL);
214568350Seric 	}
214668350Seric 	vp = get_column(linebuf, map->map_valcolno, delim, buf);
214768350Seric 	vsize = strlen(vp);
214868350Seric #ifdef MAP_EXIT_STAT
214968350Seric 	*statp = EX_OK;
215068350Seric #endif
215168350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
215268350Seric 		return map_rewrite(map, name, strlen(name), NULL);
215368350Seric 	else
215468350Seric 		return map_rewrite(map, vp, vsize, av);
215568350Seric }
215669401Seric 
215769401Seric 
215869401Seric /*
215969401Seric **  TEXT_GETCANONNAME -- look up canonical name in hosts file
216069401Seric */
216169401Seric 
216269401Seric bool
216369401Seric text_getcanonname(name, hbsize, statp)
216469401Seric 	char *name;
216569401Seric 	int hbsize;
216669401Seric 	int *statp;
216769401Seric {
216869401Seric 	int key_idx;
216969401Seric 	bool found;
217069401Seric 	FILE *f;
217169401Seric 	char linebuf[MAXLINE];
217269401Seric 	char cbuf[MAXNAME + 1];
217369780Seric 	char fbuf[MAXNAME + 1];
217469780Seric 	char nbuf[MAXNAME + 1];
217569401Seric 	extern char *get_column();
217669401Seric 
217769780Seric 	if (strlen(name) >= sizeof nbuf)
217869780Seric 	{
217969780Seric 		*statp = EX_UNAVAILABLE;
218069780Seric 		return FALSE;
218169780Seric 	}
218269780Seric 	(void) strcpy(nbuf, name);
218369780Seric 	shorten_hostname(nbuf);
218469401Seric 
218569401Seric 	/* we only accept single token search key */
218669780Seric 	if (strchr(nbuf, '.') != NULL)
218769401Seric 	{
218869401Seric 		*statp = EX_NOHOST;
218969401Seric 		return FALSE;
219069401Seric 	}
219169401Seric 
219269401Seric 	found = FALSE;
219369401Seric 
219469401Seric 	f = fopen(HostsFile, "r");
219569401Seric 	if (f == NULL)
219669401Seric 	{
219769401Seric #ifdef MAP_EXIT_STAT
219869401Seric 		*statp = EX_UNAVAILABLE;
219969401Seric #endif
220069401Seric 		return FALSE;
220169401Seric 	}
220269401Seric 	while (!found && fgets(linebuf, MAXLINE, f) != NULL)
220369401Seric 	{
220469401Seric 		char *p;
220569401Seric 
220669401Seric 		if (linebuf[0] == '#')
220769401Seric 			continue;
220869401Seric 		if ((p = strchr(linebuf, '\n')) != NULL)
220969401Seric 			*p = '\0';
221069833Seric 		found = extract_canonname(nbuf, linebuf, cbuf);
221169401Seric 	}
221269401Seric 	fclose(f);
221369401Seric 	if (!found)
221469401Seric 	{
221569401Seric 		*statp = EX_NOHOST;
221669401Seric 		return FALSE;
221769401Seric 	}
221869401Seric 
221969833Seric 	if (hbsize >= strlen(cbuf))
222069401Seric 	{
222169833Seric 		strcpy(name, cbuf);
222269401Seric 		*statp = EX_OK;
222369401Seric 		return TRUE;
222469401Seric 	}
222569401Seric 	*statp = EX_UNAVAILABLE;
222669401Seric 	return FALSE;
222769401Seric }
222868350Seric /*
222960089Seric **  STAB (Symbol Table) Modules
223060089Seric */
223160089Seric 
223260089Seric 
223360089Seric /*
223460207Seric **  STAB_MAP_LOOKUP -- look up alias in symbol table
223560089Seric */
223660089Seric 
223760089Seric char *
223861707Seric stab_map_lookup(map, name, av, pstat)
223960089Seric 	register MAP *map;
224060089Seric 	char *name;
224161707Seric 	char **av;
224261707Seric 	int *pstat;
224360089Seric {
224460089Seric 	register STAB *s;
224560089Seric 
224660537Seric 	if (tTd(38, 20))
224768350Seric 		printf("stab_lookup(%s, %s)\n",
224868350Seric 			map->map_mname, name);
224960089Seric 
225060089Seric 	s = stab(name, ST_ALIAS, ST_FIND);
225160089Seric 	if (s != NULL)
225260089Seric 		return (s->s_alias);
225360089Seric 	return (NULL);
225460089Seric }
225560089Seric 
225660089Seric 
225760089Seric /*
225860207Seric **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
225960089Seric */
226060089Seric 
226160089Seric void
226260089Seric stab_map_store(map, lhs, rhs)
226360089Seric 	register MAP *map;
226460089Seric 	char *lhs;
226560089Seric 	char *rhs;
226660089Seric {
226760089Seric 	register STAB *s;
226860089Seric 
226960089Seric 	s = stab(lhs, ST_ALIAS, ST_ENTER);
227060089Seric 	s->s_alias = newstr(rhs);
227160089Seric }
227260089Seric 
227360089Seric 
227460089Seric /*
227560207Seric **  STAB_MAP_OPEN -- initialize (reads data file)
227660207Seric **
227760207Seric **	This is a wierd case -- it is only intended as a fallback for
227860207Seric **	aliases.  For this reason, opens for write (only during a
227960207Seric **	"newaliases") always fails, and opens for read open the
228060207Seric **	actual underlying text file instead of the database.
228160089Seric */
228260089Seric 
228360089Seric bool
228460089Seric stab_map_open(map, mode)
228560089Seric 	register MAP *map;
228660089Seric 	int mode;
228760089Seric {
228863835Seric 	FILE *af;
228964284Seric 	struct stat st;
229063835Seric 
229160537Seric 	if (tTd(38, 2))
229268350Seric 		printf("stab_map_open(%s, %s)\n",
229368350Seric 			map->map_mname, map->map_file);
229460089Seric 
229560089Seric 	if (mode != O_RDONLY)
229660207Seric 	{
229760207Seric 		errno = ENODEV;
229860089Seric 		return FALSE;
229960207Seric 	}
230060089Seric 
230163835Seric 	af = fopen(map->map_file, "r");
230263835Seric 	if (af == NULL)
230363835Seric 		return FALSE;
230468350Seric 	readaliases(map, af, FALSE, FALSE);
230564284Seric 
230664284Seric 	if (fstat(fileno(af), &st) >= 0)
230764284Seric 		map->map_mtime = st.st_mtime;
230863835Seric 	fclose(af);
230963835Seric 
231060089Seric 	return TRUE;
231160089Seric }
231260089Seric /*
231360089Seric **  Implicit Modules
231456822Seric **
231560089Seric **	Tries several types.  For back compatibility of aliases.
231656822Seric */
231756822Seric 
231860089Seric 
231960089Seric /*
232060207Seric **  IMPL_MAP_LOOKUP -- lookup in best open database
232160089Seric */
232260089Seric 
232360089Seric char *
232460089Seric impl_map_lookup(map, name, av, pstat)
232560089Seric 	MAP *map;
232660089Seric 	char *name;
232756822Seric 	char **av;
232860089Seric 	int *pstat;
232956822Seric {
233060537Seric 	if (tTd(38, 20))
233168350Seric 		printf("impl_map_lookup(%s, %s)\n",
233268350Seric 			map->map_mname, name);
233356822Seric 
233460089Seric #ifdef NEWDB
233560207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
233660089Seric 		return db_map_lookup(map, name, av, pstat);
233760089Seric #endif
233860089Seric #ifdef NDBM
233960207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
234060089Seric 		return ndbm_map_lookup(map, name, av, pstat);
234160089Seric #endif
234260089Seric 	return stab_map_lookup(map, name, av, pstat);
234360089Seric }
234460089Seric 
234560089Seric /*
234660207Seric **  IMPL_MAP_STORE -- store in open databases
234760089Seric */
234860089Seric 
234960089Seric void
235060089Seric impl_map_store(map, lhs, rhs)
235160089Seric 	MAP *map;
235260089Seric 	char *lhs;
235360089Seric 	char *rhs;
235460089Seric {
235560089Seric #ifdef NEWDB
235660207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
235760089Seric 		db_map_store(map, lhs, rhs);
235860089Seric #endif
235960089Seric #ifdef NDBM
236060207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
236160089Seric 		ndbm_map_store(map, lhs, rhs);
236260089Seric #endif
236360089Seric 	stab_map_store(map, lhs, rhs);
236460089Seric }
236560089Seric 
236660089Seric /*
236760089Seric **  IMPL_MAP_OPEN -- implicit database open
236860089Seric */
236960089Seric 
237060089Seric bool
237160089Seric impl_map_open(map, mode)
237260089Seric 	MAP *map;
237360089Seric 	int mode;
237460089Seric {
237560089Seric 	struct stat stb;
237660089Seric 
237760537Seric 	if (tTd(38, 2))
237868350Seric 		printf("impl_map_open(%s, %s, %d)\n",
237968350Seric 			map->map_mname, map->map_file, mode);
238060089Seric 
238160089Seric 	if (stat(map->map_file, &stb) < 0)
238256822Seric 	{
238360089Seric 		/* no alias file at all */
238464718Seric 		if (tTd(38, 3))
238564718Seric 			printf("no map file\n");
238660089Seric 		return FALSE;
238756822Seric 	}
238856822Seric 
238960089Seric #ifdef NEWDB
239060207Seric 	map->map_mflags |= MF_IMPL_HASH;
239160089Seric 	if (hash_map_open(map, mode))
239256822Seric 	{
239364250Seric #if defined(NDBM) && defined(NIS)
239469651Seric 		if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
239560207Seric #endif
239660207Seric 			return TRUE;
239760089Seric 	}
239860207Seric 	else
239960207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
240060089Seric #endif
240160089Seric #ifdef NDBM
240260207Seric 	map->map_mflags |= MF_IMPL_NDBM;
240360089Seric 	if (ndbm_map_open(map, mode))
240460089Seric 	{
240560089Seric 		return TRUE;
240660089Seric 	}
240760207Seric 	else
240860207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
240960089Seric #endif
241056822Seric 
241164650Seric #if defined(NEWDB) || defined(NDBM)
241260089Seric 	if (Verbose)
241360089Seric 		message("WARNING: cannot open alias database %s", map->map_file);
241464964Seric #else
241564964Seric 	if (mode != O_RDONLY)
241664964Seric 		usrerr("Cannot rebuild aliases: no database format defined");
241760207Seric #endif
241860089Seric 
241960207Seric 	return stab_map_open(map, mode);
242056822Seric }
242160089Seric 
242260207Seric 
242360089Seric /*
242460207Seric **  IMPL_MAP_CLOSE -- close any open database(s)
242560089Seric */
242660089Seric 
242760089Seric void
242860207Seric impl_map_close(map)
242960089Seric 	MAP *map;
243060089Seric {
243168350Seric 	if (tTd(38, 20))
243268350Seric 		printf("impl_map_close(%s, %s, %x)\n",
243368350Seric 			map->map_mname, map->map_file, map->map_mflags);
243460089Seric #ifdef NEWDB
243560207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
243660089Seric 	{
243760207Seric 		db_map_close(map);
243860207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
243960089Seric 	}
244060089Seric #endif
244160089Seric 
244260089Seric #ifdef NDBM
244360207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
244460089Seric 	{
244560207Seric 		ndbm_map_close(map);
244660207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
244760089Seric 	}
244860089Seric #endif
244960089Seric }
245060207Seric /*
245168350Seric **  User map class.
245268350Seric **
245368350Seric **	Provides access to the system password file.
245468350Seric */
245568350Seric 
245668350Seric /*
245768350Seric **  USER_MAP_OPEN -- open user map
245868350Seric **
245968350Seric **	Really just binds field names to field numbers.
246068350Seric */
246168350Seric 
246268350Seric bool
246368350Seric user_map_open(map, mode)
246468350Seric 	MAP *map;
246568350Seric 	int mode;
246668350Seric {
246768350Seric 	if (tTd(38, 2))
246868350Seric 		printf("user_map_open(%s)\n", map->map_mname);
246968350Seric 
247068350Seric 	if (mode != O_RDONLY)
247168350Seric 	{
247268350Seric 		/* issue a pseudo-error message */
247368350Seric #ifdef ENOSYS
247468350Seric 		errno = ENOSYS;
247568350Seric #else
247668350Seric # ifdef EFTYPE
247768350Seric 		errno = EFTYPE;
247868350Seric # else
247968350Seric 		errno = ENXIO;
248068350Seric # endif
248168350Seric #endif
248268350Seric 		return FALSE;
248368350Seric 	}
248468350Seric 	if (map->map_valcolnm == NULL)
248568350Seric 		/* nothing */ ;
248668350Seric 	else if (strcasecmp(map->map_valcolnm, "name") == 0)
248768350Seric 		map->map_valcolno = 1;
248868350Seric 	else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
248968350Seric 		map->map_valcolno = 2;
249068350Seric 	else if (strcasecmp(map->map_valcolnm, "uid") == 0)
249168350Seric 		map->map_valcolno = 3;
249268350Seric 	else if (strcasecmp(map->map_valcolnm, "gid") == 0)
249368350Seric 		map->map_valcolno = 4;
249468350Seric 	else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
249568350Seric 		map->map_valcolno = 5;
249668350Seric 	else if (strcasecmp(map->map_valcolnm, "dir") == 0)
249768350Seric 		map->map_valcolno = 6;
249868350Seric 	else if (strcasecmp(map->map_valcolnm, "shell") == 0)
249968350Seric 		map->map_valcolno = 7;
250068350Seric 	else
250168350Seric 	{
250268350Seric 		syserr("User map %s: unknown column name %s",
250368350Seric 			map->map_mname, map->map_valcolnm);
250468350Seric 		return FALSE;
250568350Seric 	}
250668350Seric 	return TRUE;
250768350Seric }
250868350Seric 
250968350Seric 
251068350Seric /*
251168350Seric **  USER_MAP_LOOKUP -- look up a user in the passwd file.
251268350Seric */
251368350Seric 
251468350Seric char *
251568350Seric user_map_lookup(map, key, av, statp)
251668350Seric 	MAP *map;
251768350Seric 	char *key;
251868350Seric 	char **av;
251968350Seric 	int *statp;
252068350Seric {
252168350Seric 	struct passwd *pw;
252268350Seric 
252368350Seric 	if (tTd(38, 20))
252468350Seric 		printf("user_map_lookup(%s, %s)\n",
252568350Seric 			map->map_mname, key);
252668350Seric 
252768693Seric 	pw = sm_getpwnam(key);
252868350Seric 	if (pw == NULL)
252968350Seric 		return NULL;
253068350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
253168350Seric 		return map_rewrite(map, key, strlen(key), NULL);
253268350Seric 	else
253368350Seric 	{
253468433Seric 		char *rwval = NULL;
253568350Seric 		char buf[30];
253668350Seric 
253768350Seric 		switch (map->map_valcolno)
253868350Seric 		{
253968350Seric 		  case 0:
254068350Seric 		  case 1:
254168350Seric 			rwval = pw->pw_name;
254268350Seric 			break;
254368350Seric 
254468350Seric 		  case 2:
254568350Seric 			rwval = pw->pw_passwd;
254668350Seric 			break;
254768350Seric 
254868350Seric 		  case 3:
254968350Seric 			sprintf(buf, "%d", pw->pw_uid);
255068350Seric 			rwval = buf;
255168350Seric 			break;
255268350Seric 
255368350Seric 		  case 4:
255468350Seric 			sprintf(buf, "%d", pw->pw_gid);
255568350Seric 			rwval = buf;
255668350Seric 			break;
255768350Seric 
255868350Seric 		  case 5:
255968350Seric 			rwval = pw->pw_gecos;
256068350Seric 			break;
256168350Seric 
256268350Seric 		  case 6:
256368350Seric 			rwval = pw->pw_dir;
256468350Seric 			break;
256568350Seric 
256668350Seric 		  case 7:
256768350Seric 			rwval = pw->pw_shell;
256868350Seric 			break;
256968350Seric 		}
257068350Seric 		return map_rewrite(map, rwval, strlen(rwval), av);
257168350Seric 	}
257268350Seric }
257368350Seric /*
257468350Seric **  BESTMX -- find the best MX for a name
257568350Seric **
257668350Seric **	This is really a hack, but I don't see any obvious way
257768350Seric **	to generalize it at the moment.
257868350Seric */
257968350Seric 
258068350Seric #if NAMED_BIND
258168350Seric 
258268350Seric char *
258368350Seric bestmx_map_lookup(map, name, av, statp)
258468350Seric 	MAP *map;
258568350Seric 	char *name;
258668350Seric 	char **av;
258768350Seric 	int *statp;
258868350Seric {
258968350Seric         int nmx;
259068350Seric         auto int rcode;
259168350Seric         char *mxhosts[MAXMXHOSTS + 1];
259268350Seric 
259368350Seric 	nmx = getmxrr(name, mxhosts, FALSE, &rcode);
259468350Seric 	if (nmx <= 0)
259568350Seric 		return NULL;
259668350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
259768350Seric 		return map_rewrite(map, name, strlen(name), NULL);
259868350Seric 	else
259968350Seric 		return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
260068350Seric }
260168350Seric 
260268350Seric #endif
260368350Seric /*
260469453Seric **  Program map type.
260569453Seric **
260669453Seric **	This provides access to arbitrary programs.  It should be used
260769453Seric **	only very sparingly, since there is no way to bound the cost
260869453Seric **	of invoking an arbitrary program.
260969453Seric */
261069453Seric 
261169453Seric char *
261269453Seric prog_map_lookup(map, name, av, statp)
261369453Seric 	MAP *map;
261469453Seric 	char *name;
261569453Seric 	char **av;
261669453Seric 	int *statp;
261769453Seric {
261869453Seric 	int i;
261969453Seric 	register char *p;
262069453Seric 	int fd;
262169453Seric 	auto pid_t pid;
262269827Seric 	char *rval;
262369827Seric 	int stat;
262469453Seric 	char *argv[MAXPV + 1];
262569453Seric 	char buf[MAXLINE];
262669453Seric 
262769453Seric 	if (tTd(38, 20))
262869453Seric 		printf("prog_map_lookup(%s, %s) %s\n",
262969453Seric 			map->map_mname, name, map->map_file);
263069453Seric 
263169453Seric 	i = 0;
263269453Seric 	argv[i++] = map->map_file;
263369453Seric 	strcpy(buf, map->map_rebuild);
263469453Seric 	for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
263569453Seric 	{
263669453Seric 		if (i >= MAXPV - 1)
263769453Seric 			break;
263869453Seric 		argv[i++] = p;
263969453Seric 	}
264069453Seric 	argv[i++] = name;
264169453Seric 	argv[i] = NULL;
264269453Seric 	pid = prog_open(argv, &fd, CurEnv);
264369453Seric 	if (pid < 0)
264469453Seric 	{
264569827Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
264669827Seric 			syserr("prog_map_lookup(%s) failed (%s) -- closing",
264769827Seric 				map->map_mname, errstring(errno));
264869827Seric 		else if (tTd(38, 9))
264969453Seric 			printf("prog_map_lookup(%s) failed (%s) -- closing",
265069453Seric 				map->map_mname, errstring(errno));
265169453Seric 		map->map_mflags &= ~(MF_VALID|MF_OPEN);
265269827Seric 		*statp = EX_OSFILE;
265369453Seric 		return NULL;
265469453Seric 	}
265569453Seric 	i = read(fd, buf, sizeof buf - 1);
265669827Seric 	if (i < 0)
265769827Seric 	{
265869827Seric 		syserr("prog_map_lookup(%s): read error %s\n",
265969562Seric 			map->map_mname, errstring(errno));
266069827Seric 		rval = NULL;
266169827Seric 	}
266269827Seric 	else if (i == 0 && tTd(38, 2))
266369827Seric 	{
266469827Seric 		printf("prog_map_lookup(%s): empty answer\n",
266569827Seric 			map->map_mname);
266669827Seric 		rval = NULL;
266769827Seric 	}
266869453Seric 	if (i > 0)
266969453Seric 	{
267069453Seric 		buf[i] = '\0';
267169453Seric 		p = strchr(buf, '\n');
267269453Seric 		if (p != NULL)
267369453Seric 			*p = '\0';
267469453Seric 
267569453Seric 		/* collect the return value */
267669453Seric 		if (bitset(MF_MATCHONLY, map->map_mflags))
267769453Seric 			rval = map_rewrite(map, name, strlen(name), NULL);
267869453Seric 		else
267969453Seric 			rval = map_rewrite(map, buf, strlen(buf), NULL);
268069453Seric 
268169453Seric 		/* now flush any additional output */
268269453Seric 		while ((i = read(fd, buf, sizeof buf)) > 0)
268369453Seric 			continue;
268469827Seric 	}
268569453Seric 
268669827Seric 	/* wait for the process to terminate */
268769827Seric 	close(fd);
268869827Seric 	stat = waitfor(pid);
268969453Seric 
269069827Seric 	if (stat == -1)
269169827Seric 	{
269269827Seric 		syserr("prog_map_lookup(%s): wait error %s\n",
269369827Seric 			map->map_mname, errstring(errno));
269469827Seric 		*statp = EX_SOFTWARE;
269569827Seric 		rval = NULL;
269669453Seric 	}
2697*69872Seric 	else if (WIFEXITED(stat))
269869827Seric 	{
2699*69872Seric 		*statp = WEXITSTATUS(stat);
270069827Seric 	}
270169827Seric 	else
270269827Seric 	{
270369827Seric 		syserr("prog_map_lookup(%s): child died on signal %d",
2704*69872Seric 			map->map_mname, stat);
270569827Seric 		*statp = EX_UNAVAILABLE;
270669827Seric 		rval = NULL;
270769827Seric 	}
270869827Seric 	return rval;
270969453Seric }
271069453Seric /*
271168350Seric **  Sequenced map type.
271268350Seric **
271368350Seric **	Tries each map in order until something matches, much like
271468350Seric **	implicit.  Stores go to the first map in the list that can
271568350Seric **	support storing.
271668350Seric **
271768350Seric **	This is slightly unusual in that there are two interfaces.
271868350Seric **	The "sequence" interface lets you stack maps arbitrarily.
271968350Seric **	The "switch" interface builds a sequence map by looking
272068350Seric **	at a system-dependent configuration file such as
272168350Seric **	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
272268350Seric **
272368350Seric **	We don't need an explicit open, since all maps are
272468350Seric **	opened during startup, including underlying maps.
272568350Seric */
272668350Seric 
272768350Seric /*
272868350Seric **  SEQ_MAP_PARSE -- Sequenced map parsing
272968350Seric */
273068350Seric 
273168350Seric bool
273268350Seric seq_map_parse(map, ap)
273368350Seric 	MAP *map;
273468350Seric 	char *ap;
273568350Seric {
273668350Seric 	int maxmap;
273768350Seric 
273868350Seric 	if (tTd(38, 2))
273968350Seric 		printf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
274068350Seric 	maxmap = 0;
274168350Seric 	while (*ap != '\0')
274268350Seric 	{
274368350Seric 		register char *p;
274468350Seric 		STAB *s;
274568350Seric 
274668350Seric 		/* find beginning of map name */
274768350Seric 		while (isascii(*ap) && isspace(*ap))
274868350Seric 			ap++;
274968350Seric 		for (p = ap; isascii(*p) && isalnum(*p); p++)
275068350Seric 			continue;
275168350Seric 		if (*p != '\0')
275268350Seric 			*p++ = '\0';
275368350Seric 		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
275468350Seric 			p++;
275568350Seric 		if (*ap == '\0')
275668350Seric 		{
275768350Seric 			ap = p;
275868350Seric 			continue;
275968350Seric 		}
276068350Seric 		s = stab(ap, ST_MAP, ST_FIND);
276168350Seric 		if (s == NULL)
276268350Seric 		{
276368350Seric 			syserr("Sequence map %s: unknown member map %s",
276468350Seric 				map->map_mname, ap);
276568350Seric 		}
276668350Seric 		else if (maxmap == MAXMAPSTACK)
276768350Seric 		{
276868350Seric 			syserr("Sequence map %s: too many member maps (%d max)",
276968350Seric 				map->map_mname, MAXMAPSTACK);
277068350Seric 			maxmap++;
277168350Seric 		}
277268350Seric 		else if (maxmap < MAXMAPSTACK)
277368350Seric 		{
277468350Seric 			map->map_stack[maxmap++] = &s->s_map;
277568350Seric 		}
277668350Seric 		ap = p;
277768350Seric 	}
277868350Seric 	return TRUE;
277968350Seric }
278068350Seric 
278168350Seric 
278268350Seric /*
278368350Seric **  SWITCH_MAP_OPEN -- open a switched map
278468350Seric **
278568350Seric **	This looks at the system-dependent configuration and builds
278668350Seric **	a sequence map that does the same thing.
278768350Seric **
278868350Seric **	Every system must define a switch_map_find routine in conf.c
278968350Seric **	that will return the list of service types associated with a
279068350Seric **	given service class.
279168350Seric */
279268350Seric 
279368350Seric bool
279468350Seric switch_map_open(map, mode)
279568350Seric 	MAP *map;
279668350Seric 	int mode;
279768350Seric {
279868350Seric 	int mapno;
279968350Seric 	int nmaps;
280068350Seric 	char *maptype[MAXMAPSTACK];
280168350Seric 
280268350Seric 	if (tTd(38, 2))
280368350Seric 		printf("switch_map_open(%s, %s, %d)\n",
280468350Seric 			map->map_mname, map->map_file, mode);
280568350Seric 
280668350Seric 	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
280768350Seric 	if (tTd(38, 19))
280868350Seric 	{
280968350Seric 		printf("\tswitch_map_find => %d\n", nmaps);
281068350Seric 		for (mapno = 0; mapno < nmaps; mapno++)
281168350Seric 			printf("\t\t%s\n", maptype[mapno]);
281268350Seric 	}
281368350Seric 	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
281468350Seric 		return FALSE;
281568350Seric 
281668350Seric 	for (mapno = 0; mapno < nmaps; mapno++)
281768350Seric 	{
281868350Seric 		register STAB *s;
281968350Seric 		char nbuf[MAXNAME + 1];
282068350Seric 
282168350Seric 		if (maptype[mapno] == NULL)
282268350Seric 			continue;
282368350Seric 		(void) sprintf(nbuf, "%s.%s", map->map_file, maptype[mapno]);
282468350Seric 		s = stab(nbuf, ST_MAP, ST_FIND);
282568350Seric 		if (s == NULL)
282668350Seric 		{
282768350Seric 			syserr("Switch map %s: unknown member map %s",
282868350Seric 				map->map_mname, nbuf);
282968350Seric 		}
283068350Seric 		else
283168350Seric 		{
283268350Seric 			map->map_stack[mapno] = &s->s_map;
283368350Seric 			if (tTd(38, 4))
283468350Seric 				printf("\tmap_stack[%d] = %s:%s\n",
283568350Seric 					mapno, s->s_map.map_class->map_cname,
283668350Seric 					nbuf);
283768350Seric 		}
283868350Seric 	}
283968350Seric 	return TRUE;
284068350Seric }
284168350Seric 
284268350Seric 
284368350Seric /*
284468350Seric **  SEQ_MAP_CLOSE -- close all underlying maps
284568350Seric */
284668350Seric 
284769748Seric void
284868350Seric seq_map_close(map)
284968350Seric 	MAP *map;
285068350Seric {
285168350Seric 	int mapno;
285268350Seric 
285368350Seric 	if (tTd(38, 20))
285468350Seric 		printf("seq_map_close(%s)\n", map->map_mname);
285568350Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
285668350Seric 	{
285768350Seric 		MAP *mm = map->map_stack[mapno];
285868350Seric 
285968350Seric 		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
286068350Seric 			continue;
286168350Seric 		mm->map_class->map_close(mm);
286268798Seric 		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
286368350Seric 	}
286468350Seric }
286568350Seric 
286668350Seric 
286768350Seric /*
286868350Seric **  SEQ_MAP_LOOKUP -- sequenced map lookup
286968350Seric */
287068350Seric 
287168350Seric char *
287268350Seric seq_map_lookup(map, key, args, pstat)
287368350Seric 	MAP *map;
287468350Seric 	char *key;
287568350Seric 	char **args;
287668350Seric 	int *pstat;
287768350Seric {
287868350Seric 	int mapno;
287968350Seric 	int mapbit = 0x01;
288068350Seric 
288168350Seric 	if (tTd(38, 20))
288268350Seric 		printf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
288368350Seric 
288468350Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
288568350Seric 	{
288668350Seric 		MAP *mm = map->map_stack[mapno];
288768350Seric 		int stat = 0;
288868350Seric 		char *rv;
288968350Seric 
289068350Seric 		if (mm == NULL)
289168350Seric 			continue;
289268350Seric 		if (!bitset(MF_OPEN, mm->map_mflags))
289368350Seric 		{
289468350Seric 			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
289568350Seric 			{
289668350Seric 				*pstat = EX_UNAVAILABLE;
289768350Seric 				return NULL;
289868350Seric 			}
289968350Seric 			continue;
290068350Seric 		}
290168350Seric 		rv = mm->map_class->map_lookup(mm, key, args, &stat);
290268350Seric 		if (rv != NULL)
290368350Seric 			return rv;
290468350Seric 		if (stat == 0 && bitset(mapbit, map->map_return[MA_NOTFOUND]))
290568350Seric 			return NULL;
290668350Seric 		if (stat != 0 && bitset(mapbit, map->map_return[MA_TRYAGAIN]))
290768350Seric 		{
290868350Seric 			*pstat = stat;
290968350Seric 			return NULL;
291068350Seric 		}
291168350Seric 	}
291268350Seric 	return NULL;
291368350Seric }
291468350Seric 
291568350Seric 
291668350Seric /*
291768350Seric **  SEQ_MAP_STORE -- sequenced map store
291868350Seric */
291968350Seric 
292068350Seric void
292168350Seric seq_map_store(map, key, val)
292268350Seric 	MAP *map;
292368350Seric 	char *key;
292468350Seric 	char *val;
292568350Seric {
292668350Seric 	int mapno;
292768350Seric 
292868350Seric 	if (tTd(38, 12))
292968350Seric 		printf("seq_map_store(%s, %s, %s)\n",
293068350Seric 			map->map_mname, key, val);
293168350Seric 
293268350Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
293368350Seric 	{
293468350Seric 		MAP *mm = map->map_stack[mapno];
293568350Seric 
293668350Seric 		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
293768350Seric 			continue;
293868350Seric 
293968350Seric 		mm->map_class->map_store(mm, key, val);
294068350Seric 		return;
294168350Seric 	}
294268350Seric 	syserr("seq_map_store(%s, %s, %s): no writable map",
294368350Seric 		map->map_mname, key, val);
294468350Seric }
294568350Seric /*
294660207Seric **  NULL stubs
294760089Seric */
294860089Seric 
294960207Seric bool
295060207Seric null_map_open(map, mode)
295160089Seric 	MAP *map;
295260207Seric 	int mode;
295360089Seric {
295460207Seric 	return TRUE;
295560089Seric }
295660089Seric 
295760207Seric void
295860207Seric null_map_close(map)
295960207Seric 	MAP *map;
296060089Seric {
296160207Seric 	return;
296260207Seric }
296360089Seric 
296460207Seric void
296560207Seric null_map_store(map, key, val)
296660207Seric 	MAP *map;
296760207Seric 	char *key;
296860207Seric 	char *val;
296960089Seric {
297060207Seric 	return;
297160089Seric }
297268350Seric 
297368350Seric 
297468350Seric /*
297568350Seric **  BOGUS stubs
297668350Seric */
297768350Seric 
297868350Seric char *
297968350Seric bogus_map_lookup(map, key, args, pstat)
298068350Seric 	MAP *map;
298168350Seric 	char *key;
298268350Seric 	char **args;
298368350Seric 	int *pstat;
298468350Seric {
298568350Seric 	*pstat = EX_TEMPFAIL;
298668350Seric 	return NULL;
298768350Seric }
298868350Seric 
298968350Seric MAPCLASS	BogusMapClass =
299068350Seric {
299168350Seric 	"bogus-map",		NULL,		0,
299268350Seric 	NULL,		bogus_map_lookup,	null_map_store,
299368350Seric 	null_map_open,	null_map_close,
299468350Seric };
2995