xref: /csrg-svn/usr.sbin/sendmail/src/map.c (revision 69453)
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*69453Seric static char sccsid[] = "@(#)map.c	8.59 (Berkeley) 05/14/95";
1156822Seric #endif /* not lint */
1256822Seric 
1356822Seric #include "sendmail.h"
1456822Seric 
1560089Seric #ifdef NDBM
1668509Seric # include <ndbm.h>
1756822Seric #endif
1860089Seric #ifdef NEWDB
1968509Seric # include <db.h>
2056822Seric #endif
2160089Seric #ifdef NIS
2268524Seric   struct dom_binding { int dummy; };	/* needed on IRIX */
2368509Seric # include <rpcsvc/ypclnt.h>
2457208Seric #endif
2556822Seric 
2656822Seric /*
2760089Seric **  MAP.C -- implementations for various map classes.
2856822Seric **
2960089Seric **	Each map class implements a series of functions:
3060089Seric **
3160089Seric **	bool map_parse(MAP *map, char *args)
3260089Seric **		Parse the arguments from the config file.  Return TRUE
3360089Seric **		if they were ok, FALSE otherwise.  Fill in map with the
3460089Seric **		values.
3560089Seric **
3660222Seric **	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
3760222Seric **		Look up the key in the given map.  If found, do any
3860222Seric **		rewriting the map wants (including "args" if desired)
3960089Seric **		and return the value.  Set *pstat to the appropriate status
4060222Seric **		on error and return NULL.  Args will be NULL if called
4160222Seric **		from the alias routines, although this should probably
4260222Seric **		not be relied upon.  It is suggested you call map_rewrite
4360222Seric **		to return the results -- it takes care of null termination
4460222Seric **		and uses a dynamically expanded buffer as needed.
4560089Seric **
4660089Seric **	void map_store(MAP *map, char *key, char *value)
4760089Seric **		Store the key:value pair in the map.
4860089Seric **
4960089Seric **	bool map_open(MAP *map, int mode)
5060222Seric **		Open the map for the indicated mode.  Mode should
5160222Seric **		be either O_RDONLY or O_RDWR.  Return TRUE if it
5260222Seric **		was opened successfully, FALSE otherwise.  If the open
5360222Seric **		failed an the MF_OPTIONAL flag is not set, it should
5460222Seric **		also print an error.  If the MF_ALIAS bit is set
5560222Seric **		and this map class understands the @:@ convention, it
5660222Seric **		should call aliaswait() before returning.
5760089Seric **
5860089Seric **	void map_close(MAP *map)
5960089Seric **		Close the map.
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));
6960089Seric /*
7060089Seric **  MAP_PARSEARGS -- parse config line arguments for database lookup
7160089Seric **
7260089Seric **	This is a generic version of the map_parse method.
7360089Seric **
7456822Seric **	Parameters:
7560089Seric **		map -- the map being initialized.
7660089Seric **		ap -- a pointer to the args on the config line.
7756822Seric **
7856822Seric **	Returns:
7960089Seric **		TRUE -- if everything parsed OK.
8056822Seric **		FALSE -- otherwise.
8156822Seric **
8256822Seric **	Side Effects:
8360089Seric **		null terminates the filename; stores it in map
8456822Seric */
8556822Seric 
8656822Seric bool
8760089Seric map_parseargs(map, ap)
8856822Seric 	MAP *map;
8960089Seric 	char *ap;
9056822Seric {
9160089Seric 	register char *p = ap;
9256822Seric 
9363753Seric 	map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
9460089Seric 	for (;;)
9560089Seric 	{
9660089Seric 		while (isascii(*p) && isspace(*p))
9760089Seric 			p++;
9860089Seric 		if (*p != '-')
9960089Seric 			break;
10060089Seric 		switch (*++p)
10160089Seric 		{
10260089Seric 		  case 'N':
10360207Seric 			map->map_mflags |= MF_INCLNULL;
10463753Seric 			map->map_mflags &= ~MF_TRY0NULL;
10560089Seric 			break;
10660089Seric 
10763753Seric 		  case 'O':
10863753Seric 			map->map_mflags &= ~MF_TRY1NULL;
10963753Seric 			break;
11063753Seric 
11160089Seric 		  case 'o':
11260207Seric 			map->map_mflags |= MF_OPTIONAL;
11360089Seric 			break;
11460089Seric 
11560089Seric 		  case 'f':
11660207Seric 			map->map_mflags |= MF_NOFOLDCASE;
11760089Seric 			break;
11860089Seric 
11960089Seric 		  case 'm':
12060207Seric 			map->map_mflags |= MF_MATCHONLY;
12160089Seric 			break;
12260089Seric 
12368497Seric 		  case 'A':
12468497Seric 			map->map_mflags |= MF_APPEND;
12568497Seric 			break;
12668497Seric 
12760089Seric 		  case 'a':
12860089Seric 			map->map_app = ++p;
12960089Seric 			break;
13068350Seric 
13168350Seric 		  case 'k':
13268350Seric 			while (isascii(*++p) && isspace(*p))
13368350Seric 				continue;
13468350Seric 			map->map_keycolnm = p;
13568350Seric 			break;
13668350Seric 
13768350Seric 		  case 'v':
13868350Seric 			while (isascii(*++p) && isspace(*p))
13968350Seric 				continue;
14068350Seric 			map->map_valcolnm = p;
14168350Seric 			break;
14268350Seric 
14368350Seric 		  case 'z':
14468350Seric 			if (*++p != '\\')
14568350Seric 				map->map_coldelim = *p;
14668350Seric 			else
14768350Seric 			{
14868350Seric 				switch (*++p)
14968350Seric 				{
15068350Seric 				  case 'n':
15168350Seric 					map->map_coldelim = '\n';
15268350Seric 					break;
15368350Seric 
15468350Seric 				  case 't':
15568350Seric 					map->map_coldelim = '\t';
15668350Seric 					break;
15768350Seric 
15868350Seric 				  default:
15968350Seric 					map->map_coldelim = '\\';
16068350Seric 				}
16168350Seric 			}
16268350Seric 			break;
16368497Seric #ifdef RESERVED_FOR_SUN
16468497Seric 		  case 'd':
16568497Seric 			map->map_mflags |= MF_DOMAIN_WIDE;
16668497Seric 			break;
16768497Seric 
16868497Seric 		  case 's':
16968497Seric 			/* info type */
17068497Seric 			break;
17168497Seric #endif
17260089Seric 		}
17360089Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
17460089Seric 			p++;
17560089Seric 		if (*p != '\0')
17660089Seric 			*p++ = '\0';
17760089Seric 	}
17860089Seric 	if (map->map_app != NULL)
17960089Seric 		map->map_app = newstr(map->map_app);
18068350Seric 	if (map->map_keycolnm != NULL)
18168350Seric 		map->map_keycolnm = newstr(map->map_keycolnm);
18268350Seric 	if (map->map_valcolnm != NULL)
18368350Seric 		map->map_valcolnm = newstr(map->map_valcolnm);
18460089Seric 
18560089Seric 	if (*p != '\0')
18660089Seric 	{
18760089Seric 		map->map_file = p;
18860089Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
18960089Seric 			p++;
19060089Seric 		if (*p != '\0')
19160089Seric 			*p++ = '\0';
19260089Seric 		map->map_file = newstr(map->map_file);
19360089Seric 	}
19460089Seric 
19560089Seric 	while (*p != '\0' && isascii(*p) && isspace(*p))
19660089Seric 		p++;
19760089Seric 	if (*p != '\0')
19860089Seric 		map->map_rebuild = newstr(p);
19960089Seric 
20068350Seric 	if (map->map_file == NULL &&
20168350Seric 	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
20257208Seric 	{
20360089Seric 		syserr("No file name for %s map %s",
20460089Seric 			map->map_class->map_cname, map->map_mname);
20556822Seric 		return FALSE;
20657208Seric 	}
20760089Seric 	return TRUE;
20860089Seric }
20960089Seric /*
21060089Seric **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
21160089Seric **
21260089Seric **	It also adds the map_app string.  It can be used as a utility
21360089Seric **	in the map_lookup method.
21460089Seric **
21560089Seric **	Parameters:
21660089Seric **		map -- the map that causes this.
21760089Seric **		s -- the string to rewrite, NOT necessarily null terminated.
21860089Seric **		slen -- the length of s.
21960089Seric **		av -- arguments to interpolate into buf.
22060089Seric **
22160089Seric **	Returns:
22267895Seric **		Pointer to rewritten result.  This is static data that
22367895Seric **		should be copied if it is to be saved!
22460089Seric **
22560089Seric **	Side Effects:
22660089Seric **		none.
22760089Seric */
22860089Seric 
22960089Seric char *
23060089Seric map_rewrite(map, s, slen, av)
23160089Seric 	register MAP *map;
23260089Seric 	register char *s;
23360089Seric 	int slen;
23460089Seric 	char **av;
23560089Seric {
23660089Seric 	register char *bp;
23760089Seric 	register char c;
23860089Seric 	char **avp;
23960089Seric 	register char *ap;
24060089Seric 	int i;
24160089Seric 	int len;
24267895Seric 	static int buflen = -1;
24367895Seric 	static char *buf = NULL;
24460089Seric 
24560537Seric 	if (tTd(39, 1))
24660089Seric 	{
24760256Seric 		printf("map_rewrite(%.*s), av =", slen, s);
24860256Seric 		if (av == NULL)
24960256Seric 			printf(" (nullv)");
25060256Seric 		else
25160256Seric 		{
25260256Seric 			for (avp = av; *avp != NULL; avp++)
25360256Seric 				printf("\n\t%s", *avp);
25460256Seric 		}
25560256Seric 		printf("\n");
25660089Seric 	}
25760089Seric 
25860089Seric 	/* count expected size of output (can safely overestimate) */
25960089Seric 	i = len = slen;
26060089Seric 	if (av != NULL)
26160089Seric 	{
26260089Seric 		bp = s;
26360089Seric 		for (i = slen; --i >= 0 && (c = *bp++) != 0; )
26460089Seric 		{
26560089Seric 			if (c != '%')
26660089Seric 				continue;
26760089Seric 			if (--i < 0)
26860089Seric 				break;
26960089Seric 			c = *bp++;
27060089Seric 			if (!(isascii(c) && isdigit(c)))
27160089Seric 				continue;
27263937Seric 			for (avp = av; --c >= '0' && *avp != NULL; avp++)
27360089Seric 				continue;
27460089Seric 			if (*avp == NULL)
27560089Seric 				continue;
27660089Seric 			len += strlen(*avp);
27760089Seric 		}
27860089Seric 	}
27960089Seric 	if (map->map_app != NULL)
28060089Seric 		len += strlen(map->map_app);
28167895Seric 	if (buflen < ++len)
28260089Seric 	{
28360089Seric 		/* need to malloc additional space */
28467895Seric 		buflen = len;
28567895Seric 		if (buf != NULL)
28667895Seric 			free(buf);
28767895Seric 		buf = xalloc(buflen);
28860089Seric 	}
28960089Seric 
29067895Seric 	bp = buf;
29160089Seric 	if (av == NULL)
29260089Seric 	{
29360089Seric 		bcopy(s, bp, slen);
29460089Seric 		bp += slen;
29560089Seric 	}
29660089Seric 	else
29760089Seric 	{
29860089Seric 		while (--slen >= 0 && (c = *s++) != '\0')
29960089Seric 		{
30060089Seric 			if (c != '%')
30160089Seric 			{
30260089Seric   pushc:
30360089Seric 				*bp++ = c;
30460089Seric 				continue;
30560089Seric 			}
30660089Seric 			if (--slen < 0 || (c = *s++) == '\0')
30760089Seric 				c = '%';
30860089Seric 			if (c == '%')
30960089Seric 				goto pushc;
31060089Seric 			if (!(isascii(c) && isdigit(c)))
31160089Seric 			{
31260089Seric 				*bp++ = '%';
31360089Seric 				goto pushc;
31460089Seric 			}
31563937Seric 			for (avp = av; --c >= '0' && *avp != NULL; avp++)
31660089Seric 				continue;
31760089Seric 			if (*avp == NULL)
31860089Seric 				continue;
31960089Seric 
32060089Seric 			/* transliterate argument into output string */
32160089Seric 			for (ap = *avp; (c = *ap++) != '\0'; )
32260089Seric 				*bp++ = c;
32360089Seric 		}
32460089Seric 	}
32560089Seric 	if (map->map_app != NULL)
32660089Seric 		strcpy(bp, map->map_app);
32760089Seric 	else
32860089Seric 		*bp = '\0';
32960537Seric 	if (tTd(39, 1))
33067895Seric 		printf("map_rewrite => %s\n", buf);
33167895Seric 	return buf;
33260089Seric }
33360089Seric /*
33460537Seric **  INITMAPS -- initialize for aliasing
33560537Seric **
33660537Seric **	Parameters:
33760537Seric **		rebuild -- if TRUE, this rebuilds the cached versions.
33860537Seric **		e -- current envelope.
33960537Seric **
34060537Seric **	Returns:
34160537Seric **		none.
34260537Seric **
34360537Seric **	Side Effects:
34460537Seric **		initializes aliases:
34560537Seric **		if NDBM:  opens the database.
34660537Seric **		if ~NDBM: reads the aliases into the symbol table.
34760537Seric */
34860537Seric 
34960537Seric initmaps(rebuild, e)
35060537Seric 	bool rebuild;
35160537Seric 	register ENVELOPE *e;
35260537Seric {
35360537Seric 	extern void map_init();
35460537Seric 
35564671Seric #ifdef XDEBUG
35664671Seric 	checkfd012("entering initmaps");
35764671Seric #endif
35860537Seric 	CurEnv = e;
35965085Seric 	if (rebuild)
36065085Seric 	{
36165085Seric 		stabapply(map_init, 1);
36265085Seric 		stabapply(map_init, 2);
36365085Seric 	}
36465085Seric 	else
36565085Seric 	{
36665085Seric 		stabapply(map_init, 0);
36765085Seric 	}
36864671Seric #ifdef XDEBUG
36964671Seric 	checkfd012("exiting initmaps");
37064671Seric #endif
37160537Seric }
37260537Seric 
37360537Seric void
37460537Seric map_init(s, rebuild)
37560537Seric 	register STAB *s;
37660537Seric 	int rebuild;
37760537Seric {
37860537Seric 	register MAP *map;
37960537Seric 
38060537Seric 	/* has to be a map */
38160537Seric 	if (s->s_type != ST_MAP)
38260537Seric 		return;
38360537Seric 
38460537Seric 	map = &s->s_map;
38560537Seric 	if (!bitset(MF_VALID, map->map_mflags))
38660537Seric 		return;
38760537Seric 
38860537Seric 	if (tTd(38, 2))
38968350Seric 		printf("map_init(%s:%s, %s, %d)\n",
39064690Seric 			map->map_class->map_cname == NULL ? "NULL" :
39164690Seric 				map->map_class->map_cname,
39268350Seric 			map->map_mname == NULL ? "NULL" : map->map_mname,
39365085Seric 			map->map_file == NULL ? "NULL" : map->map_file,
39465085Seric 			rebuild);
39560537Seric 
39665085Seric 	if (rebuild == (bitset(MF_ALIAS, map->map_mflags) &&
39765085Seric 		    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2))
39865085Seric 	{
39965085Seric 		if (tTd(38, 3))
40065085Seric 			printf("\twrong pass\n");
40165085Seric 		return;
40265085Seric 	}
40365085Seric 
40460537Seric 	/* if already open, close it (for nested open) */
40560537Seric 	if (bitset(MF_OPEN, map->map_mflags))
40660537Seric 	{
40760537Seric 		map->map_class->map_close(map);
40860537Seric 		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
40960537Seric 	}
41060537Seric 
41165085Seric 	if (rebuild == 2)
41260537Seric 	{
41365085Seric 		rebuildaliases(map, FALSE);
41460537Seric 	}
41560537Seric 	else
41660537Seric 	{
41760537Seric 		if (map->map_class->map_open(map, O_RDONLY))
41860537Seric 		{
41960537Seric 			if (tTd(38, 4))
42068350Seric 				printf("\t%s:%s %s: valid\n",
42164690Seric 					map->map_class->map_cname == NULL ? "NULL" :
42264690Seric 						map->map_class->map_cname,
42368350Seric 					map->map_mname == NULL ? "NULL" :
42468350Seric 						map->map_mname,
42564690Seric 					map->map_file == NULL ? "NULL" :
42664690Seric 						map->map_file);
42760537Seric 			map->map_mflags |= MF_OPEN;
42860537Seric 		}
42968350Seric 		else
43068350Seric 		{
43168350Seric 			if (tTd(38, 4))
43268350Seric 				printf("\t%s:%s %s: invalid: %s\n",
43368350Seric 					map->map_class->map_cname == NULL ? "NULL" :
43468350Seric 						map->map_class->map_cname,
43568350Seric 					map->map_mname == NULL ? "NULL" :
43668350Seric 						map->map_mname,
43768350Seric 					map->map_file == NULL ? "NULL" :
43868350Seric 						map->map_file,
43968350Seric 					errstring(errno));
44068350Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
44168350Seric 			{
44268350Seric 				extern MAPCLASS BogusMapClass;
44368350Seric 
44468350Seric 				map->map_class = &BogusMapClass;
44568350Seric 				map->map_mflags |= MF_OPEN;
44668350Seric 			}
44768350Seric 		}
44860537Seric 	}
44960537Seric }
45060537Seric /*
45160089Seric **  NDBM modules
45260089Seric */
45360089Seric 
45460089Seric #ifdef NDBM
45560089Seric 
45660089Seric /*
45760089Seric **  DBM_MAP_OPEN -- DBM-style map open
45860089Seric */
45960089Seric 
46060089Seric bool
46160089Seric ndbm_map_open(map, mode)
46260089Seric 	MAP *map;
46360089Seric 	int mode;
46460089Seric {
46564284Seric 	register DBM *dbm;
46664284Seric 	struct stat st;
46760089Seric 
46860537Seric 	if (tTd(38, 2))
46968350Seric 		printf("ndbm_map_open(%s, %s, %d)\n",
47068350Seric 			map->map_mname, map->map_file, mode);
47160089Seric 
47260207Seric 	if (mode == O_RDWR)
47360207Seric 		mode |= O_CREAT|O_TRUNC;
47460207Seric 
47560089Seric 	/* open the database */
47660089Seric 	dbm = dbm_open(map->map_file, mode, DBMMODE);
47756822Seric 	if (dbm == NULL)
47856822Seric 	{
47964718Seric 		if (aliaswait(map, ".pag", FALSE))
48064718Seric 			return TRUE;
48160207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
48256836Seric 			syserr("Cannot open DBM database %s", map->map_file);
48356822Seric 		return FALSE;
48456822Seric 	}
48560089Seric 	map->map_db1 = (void *) dbm;
48664964Seric 	if (mode == O_RDONLY)
48764964Seric 	{
48864964Seric 		if (bitset(MF_ALIAS, map->map_mflags) &&
48964964Seric 		    !aliaswait(map, ".pag", TRUE))
49064718Seric 			return FALSE;
49164964Seric 	}
49264964Seric 	else
49364964Seric 	{
49464964Seric 		int fd;
49564964Seric 
49664964Seric 		/* exclusive lock for duration of rebuild */
49764964Seric 		fd = dbm_dirfno((DBM *) map->map_db1);
49864964Seric 		if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) &&
49964964Seric 		    lockfile(fd, map->map_file, ".dir", LOCK_EX))
50064964Seric 			map->map_mflags |= MF_LOCKED;
50164964Seric 	}
50264718Seric 	if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0)
50364284Seric 		map->map_mtime = st.st_mtime;
50456822Seric 	return TRUE;
50556822Seric }
50660089Seric 
50760089Seric 
50860089Seric /*
50956822Seric **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
51056822Seric */
51156822Seric 
51256822Seric char *
51360089Seric ndbm_map_lookup(map, name, av, statp)
51456822Seric 	MAP *map;
51560089Seric 	char *name;
51656822Seric 	char **av;
51759084Seric 	int *statp;
51856822Seric {
51956822Seric 	datum key, val;
52064373Seric 	int fd;
52160089Seric 	char keybuf[MAXNAME + 1];
52256822Seric 
52360537Seric 	if (tTd(38, 20))
52468350Seric 		printf("ndbm_map_lookup(%s, %s)\n",
52568350Seric 			map->map_mname, name);
52660089Seric 
52760089Seric 	key.dptr = name;
52860089Seric 	key.dsize = strlen(name);
52960207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
53057014Seric 	{
53160089Seric 		if (key.dsize > sizeof keybuf - 1)
53260089Seric 			key.dsize = sizeof keybuf - 1;
53360089Seric 		bcopy(key.dptr, keybuf, key.dsize + 1);
53460089Seric 		makelower(keybuf);
53560089Seric 		key.dptr = keybuf;
53657014Seric 	}
53764373Seric 	fd = dbm_dirfno((DBM *) map->map_db1);
53864388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
53964373Seric 		(void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
54063753Seric 	val.dptr = NULL;
54163753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
54263753Seric 	{
54363753Seric 		val = dbm_fetch((DBM *) map->map_db1, key);
54463753Seric 		if (val.dptr != NULL)
54563753Seric 			map->map_mflags &= ~MF_TRY1NULL;
54663753Seric 	}
54763753Seric 	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
54863753Seric 	{
54956822Seric 		key.dsize++;
55063753Seric 		val = dbm_fetch((DBM *) map->map_db1, key);
55163753Seric 		if (val.dptr != NULL)
55263753Seric 			map->map_mflags &= ~MF_TRY0NULL;
55363753Seric 	}
55464388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
55564373Seric 		(void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
55656822Seric 	if (val.dptr == NULL)
55756822Seric 		return NULL;
55860207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
55963753Seric 		return map_rewrite(map, name, strlen(name), NULL);
56063753Seric 	else
56163753Seric 		return map_rewrite(map, val.dptr, val.dsize, av);
56256822Seric }
56356822Seric 
56456822Seric 
56556822Seric /*
56660089Seric **  DBM_MAP_STORE -- store a datum in the database
56756822Seric */
56856822Seric 
56960089Seric void
57060089Seric ndbm_map_store(map, lhs, rhs)
57160089Seric 	register MAP *map;
57260089Seric 	char *lhs;
57360089Seric 	char *rhs;
57460089Seric {
57560089Seric 	datum key;
57660089Seric 	datum data;
57760089Seric 	int stat;
57860089Seric 
57960537Seric 	if (tTd(38, 12))
58068350Seric 		printf("ndbm_map_store(%s, %s, %s)\n",
58168350Seric 			map->map_mname, lhs, rhs);
58260089Seric 
58360089Seric 	key.dsize = strlen(lhs);
58460089Seric 	key.dptr = lhs;
58560089Seric 
58660089Seric 	data.dsize = strlen(rhs);
58760089Seric 	data.dptr = rhs;
58860089Seric 
58960207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
59060089Seric 	{
59160089Seric 		key.dsize++;
59260089Seric 		data.dsize++;
59360089Seric 	}
59460089Seric 
59560089Seric 	stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
59660089Seric 	if (stat > 0)
59760089Seric 	{
59868497Seric 		if (!bitset(MF_APPEND, map->map_mflags))
59968497Seric 			usrerr("050 Warning: duplicate alias name %s", lhs);
60068497Seric 		else
60168497Seric 		{
60268497Seric 			static char *buf = NULL;
60368497Seric 			static int bufsiz = 0;
60468879Seric 			auto int xstat;
60568497Seric 			datum old;
60668497Seric 
60768879Seric 			old.dptr = ndbm_map_lookup(map, key.dptr, NULL, &xstat);
60868497Seric 			if (old.dptr != NULL && *old.dptr != '\0')
60968497Seric 			{
61068497Seric 				old.dsize = strlen(old.dptr);
61168497Seric 				if (data.dsize + old.dsize + 2 > bufsiz)
61268497Seric 				{
61368497Seric 					if (buf != NULL)
61468497Seric 						(void) free(buf);
61568497Seric 					bufsiz = data.dsize + old.dsize + 2;
61668497Seric 					buf = xalloc(bufsiz);
61768497Seric 				}
61868497Seric 				sprintf(buf, "%s,%s", data.dptr, old.dptr);
61968497Seric 				data.dsize = data.dsize + old.dsize + 1;
62068497Seric 				data.dptr = buf;
62168497Seric 				if (tTd(38, 9))
62268497Seric 					printf("ndbm_map_store append=%s\n", data.dptr);
62368497Seric 			}
62468497Seric 		}
62560089Seric 		stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
62660089Seric 	}
62760089Seric 	if (stat != 0)
62860089Seric 		syserr("readaliases: dbm put (%s)", lhs);
62960089Seric }
63060089Seric 
63160089Seric 
63260089Seric /*
63360207Seric **  NDBM_MAP_CLOSE -- close the database
63460089Seric */
63560089Seric 
63660089Seric void
63760089Seric ndbm_map_close(map)
63860089Seric 	register MAP  *map;
63960089Seric {
64066773Seric 	if (tTd(38, 9))
64168350Seric 		printf("ndbm_map_close(%s, %s, %x)\n",
64268350Seric 			map->map_mname, map->map_file, map->map_mflags);
64366773Seric 
64460207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
64560089Seric 	{
64664250Seric #ifdef NIS
64764075Seric 		bool inclnull;
64860089Seric 		char buf[200];
64960089Seric 
65064075Seric 		inclnull = bitset(MF_INCLNULL, map->map_mflags);
65164075Seric 		map->map_mflags &= ~MF_INCLNULL;
65264075Seric 
65360089Seric 		(void) sprintf(buf, "%010ld", curtime());
65460089Seric 		ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
65560089Seric 
65664941Seric 		(void) gethostname(buf, sizeof buf);
65760089Seric 		ndbm_map_store(map, "YP_MASTER_NAME", buf);
65864075Seric 
65964075Seric 		if (inclnull)
66064075Seric 			map->map_mflags |= MF_INCLNULL;
66160089Seric #endif
66260089Seric 
66360089Seric 		/* write out the distinguished alias */
66460089Seric 		ndbm_map_store(map, "@", "@");
66560089Seric 	}
66660089Seric 	dbm_close((DBM *) map->map_db1);
66760089Seric }
66860089Seric 
66960089Seric #endif
67060089Seric /*
67160582Seric **  NEWDB (Hash and BTree) Modules
67260089Seric */
67360089Seric 
67460089Seric #ifdef NEWDB
67560089Seric 
67660089Seric /*
67760582Seric **  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
67860582Seric **
67960582Seric **	These do rather bizarre locking.  If you can lock on open,
68060582Seric **	do that to avoid the condition of opening a database that
68160582Seric **	is being rebuilt.  If you don't, we'll try to fake it, but
68260582Seric **	there will be a race condition.  If opening for read-only,
68360582Seric **	we immediately release the lock to avoid freezing things up.
68460582Seric **	We really ought to hold the lock, but guarantee that we won't
68560582Seric **	be pokey about it.  That's hard to do.
68660089Seric */
68760089Seric 
68856822Seric bool
68960089Seric bt_map_open(map, mode)
69056822Seric 	MAP *map;
69160089Seric 	int mode;
69256822Seric {
69356822Seric 	DB *db;
69460228Seric 	int i;
69560582Seric 	int omode;
69664373Seric 	int fd;
69764284Seric 	struct stat st;
69868528Seric 	char buf[MAXNAME + 1];
69956822Seric 
70060537Seric 	if (tTd(38, 2))
70168350Seric 		printf("bt_map_open(%s, %s, %d)\n",
70268350Seric 			map->map_mname, map->map_file, mode);
70360089Seric 
70460582Seric 	omode = mode;
70560582Seric 	if (omode == O_RDWR)
70660582Seric 	{
70760582Seric 		omode |= O_CREAT|O_TRUNC;
70865830Seric #if defined(O_EXLOCK) && HASFLOCK
70960582Seric 		omode |= O_EXLOCK;
71066843Seric # if !OLD_NEWDB
71160582Seric 	}
71260582Seric 	else
71360582Seric 	{
71460582Seric 		omode |= O_SHLOCK;
71560582Seric # endif
71660582Seric #endif
71760582Seric 	}
71860207Seric 
71960228Seric 	(void) strcpy(buf, map->map_file);
72060228Seric 	i = strlen(buf);
72160228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
72260228Seric 		(void) strcat(buf, ".db");
72360582Seric 	db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
72456822Seric 	if (db == NULL)
72556822Seric 	{
72664718Seric #ifdef MAYBENEXTRELEASE
72764718Seric 		if (aliaswait(map, ".db", FALSE))
72864718Seric 			return TRUE;
72964718Seric #endif
73060207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
73156836Seric 			syserr("Cannot open BTREE database %s", map->map_file);
73256822Seric 		return FALSE;
73356822Seric 	}
73468350Seric #if !OLD_NEWDB
73564373Seric 	fd = db->fd(db);
73668778Seric # if defined(O_EXLOCK) && HASFLOCK
73768778Seric 	if (fd >= 0)
73868778Seric 	{
73968778Seric 		if (mode == O_RDONLY)
74068778Seric 			(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
74168778Seric 		else
74268778Seric 			map->map_mflags |= MF_LOCKED;
74368778Seric 	}
74468778Seric # else
74564373Seric 	if (mode == O_RDWR && fd >= 0)
74664388Seric 	{
74764388Seric 		if (lockfile(fd, map->map_file, ".db", LOCK_EX))
74864388Seric 			map->map_mflags |= MF_LOCKED;
74964388Seric 	}
75060582Seric # endif
75160582Seric #endif
75260585Seric 
75360585Seric 	/* try to make sure that at least the database header is on disk */
75460585Seric 	if (mode == O_RDWR)
75566843Seric #if OLD_NEWDB
75664373Seric 		(void) db->sync(db);
75764373Seric #else
75860585Seric 		(void) db->sync(db, 0);
75960585Seric 
76064373Seric 	if (fd >= 0 && fstat(fd, &st) >= 0)
76164284Seric 		map->map_mtime = st.st_mtime;
76264284Seric #endif
76364284Seric 
76460089Seric 	map->map_db2 = (void *) db;
76560207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
76664718Seric 		if (!aliaswait(map, ".db", TRUE))
76764718Seric 			return FALSE;
76856822Seric 	return TRUE;
76956822Seric }
77056822Seric 
77156822Seric 
77256822Seric /*
77356822Seric **  HASH_MAP_INIT -- HASH-style map initialization
77456822Seric */
77556822Seric 
77656822Seric bool
77760089Seric hash_map_open(map, mode)
77856822Seric 	MAP *map;
77960089Seric 	int mode;
78056822Seric {
78156822Seric 	DB *db;
78260228Seric 	int i;
78360582Seric 	int omode;
78464373Seric 	int fd;
78564284Seric 	struct stat st;
78668528Seric 	char buf[MAXNAME + 1];
78756822Seric 
78860537Seric 	if (tTd(38, 2))
78968350Seric 		printf("hash_map_open(%s, %s, %d)\n",
79068350Seric 			map->map_mname, map->map_file, mode);
79160089Seric 
79260582Seric 	omode = mode;
79360582Seric 	if (omode == O_RDWR)
79460582Seric 	{
79560582Seric 		omode |= O_CREAT|O_TRUNC;
79665830Seric #if defined(O_EXLOCK) && HASFLOCK
79760582Seric 		omode |= O_EXLOCK;
79866843Seric # if !OLD_NEWDB
79960582Seric 	}
80060582Seric 	else
80160582Seric 	{
80260582Seric 		omode |= O_SHLOCK;
80360582Seric # endif
80460582Seric #endif
80560582Seric 	}
80660207Seric 
80760228Seric 	(void) strcpy(buf, map->map_file);
80860228Seric 	i = strlen(buf);
80960228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
81060228Seric 		(void) strcat(buf, ".db");
81160582Seric 	db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
81256822Seric 	if (db == NULL)
81356822Seric 	{
81464718Seric #ifdef MAYBENEXTRELEASE
81564718Seric 		if (aliaswait(map, ".db", FALSE))
81664718Seric 			return TRUE;
81764718Seric #endif
81860207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
81956836Seric 			syserr("Cannot open HASH database %s", map->map_file);
82056822Seric 		return FALSE;
82156822Seric 	}
82268350Seric #if !OLD_NEWDB
82364373Seric 	fd = db->fd(db);
82468778Seric # if defined(O_EXLOCK) && HASFLOCK
82568778Seric 	if (fd >= 0)
82668778Seric 	{
82768778Seric 		if (mode == O_RDONLY)
82868778Seric 			(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
82968778Seric 		else
83068778Seric 			map->map_mflags |= MF_LOCKED;
83168778Seric 	}
83268778Seric # else
83364373Seric 	if (mode == O_RDWR && fd >= 0)
83464388Seric 	{
83564388Seric 		if (lockfile(fd, map->map_file, ".db", LOCK_EX))
83664388Seric 			map->map_mflags |= MF_LOCKED;
83764388Seric 	}
83860582Seric # endif
83960582Seric #endif
84060585Seric 
84160585Seric 	/* try to make sure that at least the database header is on disk */
84260585Seric 	if (mode == O_RDWR)
84366843Seric #if OLD_NEWDB
84464373Seric 		(void) db->sync(db);
84564373Seric #else
84660585Seric 		(void) db->sync(db, 0);
84760585Seric 
84864373Seric 	if (fd >= 0 && fstat(fd, &st) >= 0)
84964284Seric 		map->map_mtime = st.st_mtime;
85064284Seric #endif
85164284Seric 
85260089Seric 	map->map_db2 = (void *) db;
85360207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
85464718Seric 		if (!aliaswait(map, ".db", TRUE))
85564718Seric 			return FALSE;
85656822Seric 	return TRUE;
85756822Seric }
85856822Seric 
85956822Seric 
86056822Seric /*
86156822Seric **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
86256822Seric */
86356822Seric 
86456822Seric char *
86560089Seric db_map_lookup(map, name, av, statp)
86656822Seric 	MAP *map;
86760089Seric 	char *name;
86856822Seric 	char **av;
86959084Seric 	int *statp;
87056822Seric {
87156822Seric 	DBT key, val;
87260422Seric 	register DB *db = (DB *) map->map_db2;
87360422Seric 	int st;
87460422Seric 	int saveerrno;
87564373Seric 	int fd;
87660089Seric 	char keybuf[MAXNAME + 1];
87756822Seric 
87860537Seric 	if (tTd(38, 20))
87968350Seric 		printf("db_map_lookup(%s, %s)\n",
88068350Seric 			map->map_mname, name);
88160089Seric 
88260089Seric 	key.size = strlen(name);
88360089Seric 	if (key.size > sizeof keybuf - 1)
88460089Seric 		key.size = sizeof keybuf - 1;
88560089Seric 	key.data = keybuf;
88660089Seric 	bcopy(name, keybuf, key.size + 1);
88760207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
88860089Seric 		makelower(keybuf);
88966843Seric #if !OLD_NEWDB
89064388Seric 	fd = db->fd(db);
89164388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
89264388Seric 		(void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH);
89360422Seric #endif
89463753Seric 	st = 1;
89563753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
89663753Seric 	{
89763753Seric 		st = db->get(db, &key, &val, 0);
89863753Seric 		if (st == 0)
89963753Seric 			map->map_mflags &= ~MF_TRY1NULL;
90063753Seric 	}
90163753Seric 	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
90263753Seric 	{
90363753Seric 		key.size++;
90463753Seric 		st = db->get(db, &key, &val, 0);
90563753Seric 		if (st == 0)
90663753Seric 			map->map_mflags &= ~MF_TRY0NULL;
90763753Seric 	}
90860422Seric 	saveerrno = errno;
90966843Seric #if !OLD_NEWDB
91064388Seric 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
91164373Seric 		(void) lockfile(fd, map->map_file, ".db", LOCK_UN);
91260422Seric #endif
91360422Seric 	if (st != 0)
91460422Seric 	{
91560422Seric 		errno = saveerrno;
91660422Seric 		if (st < 0)
91760422Seric 			syserr("db_map_lookup: get (%s)", name);
91856822Seric 		return NULL;
91960422Seric 	}
92060207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
92163753Seric 		return map_rewrite(map, name, strlen(name), NULL);
92263753Seric 	else
92363753Seric 		return map_rewrite(map, val.data, val.size, av);
92456822Seric }
92556822Seric 
92660089Seric 
92760089Seric /*
92860089Seric **  DB_MAP_STORE -- store a datum in the NEWDB database
92956822Seric */
93056822Seric 
93160089Seric void
93260089Seric db_map_store(map, lhs, rhs)
93360089Seric 	register MAP *map;
93460089Seric 	char *lhs;
93560089Seric 	char *rhs;
93656822Seric {
93760089Seric 	int stat;
93860089Seric 	DBT key;
93960089Seric 	DBT data;
94060089Seric 	register DB *db = map->map_db2;
94156822Seric 
94260537Seric 	if (tTd(38, 20))
94368350Seric 		printf("db_map_store(%s, %s, %s)\n",
94468350Seric 			map->map_mname, lhs, rhs);
94560089Seric 
94660089Seric 	key.size = strlen(lhs);
94760089Seric 	key.data = lhs;
94860089Seric 
94960089Seric 	data.size = strlen(rhs);
95060089Seric 	data.data = rhs;
95160089Seric 
95260207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
95356822Seric 	{
95460089Seric 		key.size++;
95560089Seric 		data.size++;
95660089Seric 	}
95756836Seric 
95860089Seric 	stat = db->put(db, &key, &data, R_NOOVERWRITE);
95960089Seric 	if (stat > 0)
96060089Seric 	{
96168497Seric 		if (!bitset(MF_APPEND, map->map_mflags))
96268497Seric 			usrerr("050 Warning: duplicate alias name %s", lhs);
96368497Seric 		else
96468497Seric 		{
96568497Seric 			static char *buf = NULL;
96668497Seric 			static int bufsiz = 0;
96768497Seric 			DBT old;
96868497Seric 
96968497Seric 			old.data = db_map_lookup(map, key.data, NULL, &stat);
97068497Seric 			if (old.data != NULL)
97168497Seric 			{
97268497Seric 				old.size = strlen(old.data);
97368497Seric 				if (data.size + old.size + 2 > bufsiz)
97468497Seric 				{
97568497Seric 					if (buf != NULL)
97668497Seric 						(void) free(buf);
97768497Seric 					bufsiz = data.size + old.size + 2;
97868497Seric 					buf = xalloc(bufsiz);
97968497Seric 				}
98068497Seric 				sprintf(buf, "%s,%s", data.data, old.data);
98168497Seric 				data.size = data.size + old.size + 1;
98268497Seric 				data.data = buf;
98368497Seric 				if (tTd(38, 9))
98468497Seric 					printf("db_map_store append=%s\n", data.data);
98568497Seric 			}
98668497Seric 		}
98760089Seric 		stat = db->put(db, &key, &data, 0);
98860089Seric 	}
98960089Seric 	if (stat != 0)
99060089Seric 		syserr("readaliases: db put (%s)", lhs);
99160089Seric }
99256836Seric 
99356847Seric 
99460089Seric /*
99560089Seric **  DB_MAP_CLOSE -- add distinguished entries and close the database
99660089Seric */
99760089Seric 
99860089Seric void
99960089Seric db_map_close(map)
100060089Seric 	MAP *map;
100160089Seric {
100260089Seric 	register DB *db = map->map_db2;
100360089Seric 
100460537Seric 	if (tTd(38, 9))
100568350Seric 		printf("db_map_close(%s, %s, %x)\n",
100668350Seric 			map->map_mname, map->map_file, map->map_mflags);
100760089Seric 
100860207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
100958804Seric 	{
101060089Seric 		/* write out the distinguished alias */
101160089Seric 		db_map_store(map, "@", "@");
101258804Seric 	}
101358963Seric 
101460089Seric 	if (db->close(db) != 0)
101560089Seric 		syserr("readaliases: db close failure");
101656822Seric }
101757208Seric 
101860089Seric #endif
101960089Seric /*
102060089Seric **  NIS Modules
102160089Seric */
102260089Seric 
102360089Seric # ifdef NIS
102460089Seric 
102564369Seric # ifndef YPERR_BUSY
102664369Seric #  define YPERR_BUSY	16
102764369Seric # endif
102864369Seric 
102957208Seric /*
103060089Seric **  NIS_MAP_OPEN -- open DBM map
103157208Seric */
103257208Seric 
103357208Seric bool
103460089Seric nis_map_open(map, mode)
103557208Seric 	MAP *map;
103660089Seric 	int mode;
103757208Seric {
103857216Seric 	int yperr;
103960215Seric 	register char *p;
104060215Seric 	auto char *vp;
104160215Seric 	auto int vsize;
104257216Seric 	char *master;
104357216Seric 
104460537Seric 	if (tTd(38, 2))
104568350Seric 		printf("nis_map_open(%s, %s)\n",
104668350Seric 			map->map_mname, map->map_file);
104760089Seric 
104860207Seric 	if (mode != O_RDONLY)
104960207Seric 	{
105064650Seric 		/* issue a pseudo-error message */
105164650Seric #ifdef ENOSYS
105264650Seric 		errno = ENOSYS;
105364650Seric #else
105464650Seric # ifdef EFTYPE
105564650Seric 		errno = EFTYPE;
105664650Seric # else
105764650Seric 		errno = ENXIO;
105864650Seric # endif
105964650Seric #endif
106060207Seric 		return FALSE;
106160207Seric 	}
106260207Seric 
106360089Seric 	p = strchr(map->map_file, '@');
106460089Seric 	if (p != NULL)
106560089Seric 	{
106660089Seric 		*p++ = '\0';
106760089Seric 		if (*p != '\0')
106860089Seric 			map->map_domain = p;
106960089Seric 	}
107060215Seric 
107160089Seric 	if (*map->map_file == '\0')
107260089Seric 		map->map_file = "mail.aliases";
107360089Seric 
107466157Seric 	if (map->map_domain == NULL)
107566157Seric 	{
107666157Seric 		yperr = yp_get_default_domain(&map->map_domain);
107766157Seric 		if (yperr != 0)
107866157Seric 		{
107966744Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
108068350Seric 				syserr("421 NIS map %s specified, but NIS not running\n",
108166744Seric 					map->map_file);
108266157Seric 			return FALSE;
108366157Seric 		}
108466157Seric 	}
108566157Seric 
108660215Seric 	/* check to see if this map actually exists */
108760089Seric 	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
108860089Seric 			&vp, &vsize);
108960537Seric 	if (tTd(38, 10))
109060089Seric 		printf("nis_map_open: yp_match(%s, %s) => %s\n",
109160089Seric 			map->map_domain, map->map_file, yperr_string(yperr));
109260089Seric 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
109368350Seric 	{
109468350Seric 		if (!bitset(MF_ALIAS, map->map_mflags) ||
109568350Seric 		    aliaswait(map, NULL, TRUE))
109668350Seric 			return TRUE;
109768350Seric 	}
109860215Seric 
109960215Seric 	if (!bitset(MF_OPTIONAL, map->map_mflags))
110068735Seric 	{
110168735Seric 		syserr("421 Cannot bind to map %s in domain %s: %s",
110268735Seric 			map->map_file, map->map_domain, yperr_string(yperr));
110368735Seric 	}
110460215Seric 
110560089Seric 	return FALSE;
110660089Seric }
110760089Seric 
110860089Seric 
110960089Seric /*
111057208Seric **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
111157208Seric */
111257208Seric 
111357208Seric char *
111460089Seric nis_map_lookup(map, name, av, statp)
111557208Seric 	MAP *map;
111660089Seric 	char *name;
111757208Seric 	char **av;
111859084Seric 	int *statp;
111957208Seric {
112057208Seric 	char *vp;
112157642Seric 	auto int vsize;
112259274Seric 	int buflen;
112360215Seric 	int yperr;
112460089Seric 	char keybuf[MAXNAME + 1];
112557208Seric 
112660537Seric 	if (tTd(38, 20))
112768350Seric 		printf("nis_map_lookup(%s, %s)\n",
112868350Seric 			map->map_mname, name);
112960089Seric 
113060089Seric 	buflen = strlen(name);
113160089Seric 	if (buflen > sizeof keybuf - 1)
113260089Seric 		buflen = sizeof keybuf - 1;
113360089Seric 	bcopy(name, keybuf, buflen + 1);
113460207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
113560089Seric 		makelower(keybuf);
113663753Seric 	yperr = YPERR_KEY;
113763753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
113863753Seric 	{
113963753Seric 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
114063753Seric 			     &vp, &vsize);
114163753Seric 		if (yperr == 0)
114263753Seric 			map->map_mflags &= ~MF_TRY1NULL;
114363753Seric 	}
114463753Seric 	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
114563753Seric 	{
114659274Seric 		buflen++;
114763753Seric 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
114863753Seric 			     &vp, &vsize);
114963753Seric 		if (yperr == 0)
115063753Seric 			map->map_mflags &= ~MF_TRY0NULL;
115163753Seric 	}
115260089Seric 	if (yperr != 0)
115360089Seric 	{
115460089Seric 		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
115560215Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
115657208Seric 		return NULL;
115760089Seric 	}
115860207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
115963753Seric 		return map_rewrite(map, name, strlen(name), NULL);
116063753Seric 	else
116163753Seric 		return map_rewrite(map, vp, vsize, av);
116257208Seric }
116357208Seric 
116469401Seric 
116569401Seric /*
116669401Seric **  NIS_GETCANONNAME -- look up canonical name in NIS
116769401Seric */
116869401Seric 
116969401Seric bool
117069401Seric nis_getcanonname(name, hbsize, statp)
117169401Seric 	char *name;
117269401Seric 	int hbsize;
117369401Seric 	int *statp;
117469401Seric {
117569401Seric 	char *vp;
117669401Seric 	auto int vsize;
117769401Seric 	int keylen;
117869401Seric 	int yperr;
117969401Seric 	static bool try0null = TRUE;
118069401Seric 	static bool try1null = TRUE;
118169401Seric 	static char *yp_domain = NULL;
118269401Seric 	char *domain, *p;
118369401Seric 	char host_record[MAXLINE];
118469401Seric 	char buf[MAXNAME];
118569401Seric 	char *cname;
118669401Seric 	extern char *get_column();
118769401Seric 
118869401Seric 	if (tTd(38, 20))
118969401Seric 		printf("nis_getcanonname(%s)\n", name);
119069401Seric 
119169401Seric 	shorten_hostname(name);
119269401Seric 
119369401Seric 	/* we only accept single token search key */
119469401Seric 	if (strchr(name, '.'))
119569401Seric 	{
119669401Seric 		*statp = EX_NOHOST;
119769401Seric 		return FALSE;
119869401Seric 	}
119969401Seric 
120069401Seric 	keylen = strlen(name);
120169401Seric 
120269401Seric 	if (yp_domain == NULL)
120369401Seric 		yp_get_default_domain(&yp_domain);
120469401Seric 	makelower(name);
120569401Seric 	yperr = YPERR_KEY;
120669401Seric 	if (try0null)
120769401Seric 	{
120869401Seric 		yperr = yp_match(yp_domain, "hosts.byname", name, keylen,
120969401Seric 			     &vp, &vsize);
121069401Seric 		if (yperr == 0)
121169401Seric 			try1null = FALSE;
121269401Seric 	}
121369401Seric 	if (yperr == YPERR_KEY && try1null)
121469401Seric 	{
121569401Seric 		keylen++;
121669401Seric 		yperr = yp_match(yp_domain, "hosts.byname", name, keylen,
121769401Seric 			     &vp, &vsize);
121869401Seric 		if (yperr == 0)
121969401Seric 			try0null = FALSE;
122069401Seric 	}
122169401Seric 	if (yperr != 0)
122269401Seric 	{
122369401Seric 		if (yperr == YPERR_KEY)
122469401Seric 			*statp = EX_NOHOST;
122569401Seric 		else if (yperr == YPERR_BUSY)
122669401Seric 			*statp = EX_TEMPFAIL;
122769401Seric 		else
122869401Seric 			*statp = EX_UNAVAILABLE;
122969401Seric 		return FALSE;
123069401Seric 	}
123169401Seric 	strncpy(host_record, vp, vsize);
123269401Seric 	host_record[vsize] = '\0';
123369401Seric 	cname = get_column(host_record, 1, '\t', buf);
123469401Seric 	if (cname == NULL)
123569401Seric 	{
123669401Seric 		/* this should not happen, but.... */
123769401Seric 		*statp = EX_NOHOST;
123869401Seric 		return FALSE;
123969401Seric 	}
124069401Seric 
124169401Seric 	if (hbsize >= strlen(cname))
124269401Seric 	{
124369401Seric 		strcpy(name, cname);
124469401Seric 		*statp = EX_OK;
124569401Seric 		return TRUE;
124669401Seric 	}
124769401Seric 	*statp = EX_UNAVAILABLE;
124869401Seric 	return FALSE;
124969401Seric }
125069401Seric 
125168350Seric #endif
125268350Seric /*
125368350Seric **  NISPLUS Modules
125468350Seric **
125568350Seric **	This code donated by Sun Microsystems.
125668350Seric */
125767848Seric 
125868350Seric #ifdef NISPLUS
125968350Seric 
126068350Seric #undef NIS /* symbol conflict in nis.h */
126168350Seric #include <rpcsvc/nis.h>
126268350Seric #include <rpcsvc/nislib.h>
126368350Seric 
126468350Seric #define EN_col(col)	zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
126568350Seric #define COL_NAME(res,i)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
126668350Seric #define COL_MAX(res)	((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
126768350Seric #define PARTIAL_NAME(x)	((x)[strlen(x) - 1] != '.')
126868350Seric 
126967848Seric /*
127068350Seric **  NISPLUS_MAP_OPEN -- open nisplus table
127167848Seric */
127267848Seric 
127368350Seric bool
127468350Seric nisplus_map_open(map, mode)
127567848Seric 	MAP *map;
127668350Seric 	int mode;
127767848Seric {
127868350Seric 	register char *p;
127968350Seric 	char qbuf[MAXLINE + NIS_MAXNAMELEN];
128068350Seric 	nis_result *res = NULL;
128168350Seric 	u_int objs_len;
128268350Seric 	nis_object *obj_ptr;
128368350Seric 	int retry_cnt, max_col, i;
128468350Seric 
128568350Seric 	if (tTd(38, 2))
128668350Seric 		printf("nisplus_map_open(%s, %s, %d)\n",
128768350Seric 			map->map_mname, map->map_file, mode);
128868350Seric 
128968350Seric 	if (mode != O_RDONLY)
129068350Seric 	{
129168350Seric 		errno = ENODEV;
129268350Seric 		return FALSE;
129368350Seric 	}
129468350Seric 
129568350Seric 	if (*map->map_file == '\0')
129668350Seric 		map->map_file = "mail_aliases.org_dir";
129768350Seric 
129868350Seric 	if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
129968350Seric 	{
130068350Seric 		/* set default NISPLUS Domain to $m */
130168350Seric 		extern char *nisplus_default_domain();
130268350Seric 
130368350Seric 		map->map_domain = newstr(nisplus_default_domain());
130468350Seric 		if (tTd(38, 2))
130568350Seric 			printf("nisplus_map_open(%s): using domain %s\n",
130668350Seric 				 map->map_file, map->map_domain);
130768350Seric 	}
130868350Seric 	if (!PARTIAL_NAME(map->map_file))
130968350Seric 		map->map_domain = newstr("");
131068350Seric 
131168350Seric 	/* check to see if this map actually exists */
131268350Seric 	if (PARTIAL_NAME(map->map_file))
131368350Seric 		sprintf(qbuf, "%s.%s", map->map_file, map->map_domain);
131468350Seric 	else
131568350Seric 		strcpy(qbuf, map->map_file);
131668350Seric 
131768350Seric 	retry_cnt = 0;
131868350Seric 	while (res == NULL || res->status != NIS_SUCCESS)
131968350Seric 	{
132068350Seric 		res = nis_lookup(qbuf, FOLLOW_LINKS);
132168350Seric 		switch (res->status)
132268350Seric 		{
132368350Seric 		  case NIS_SUCCESS:
132468350Seric 		  case NIS_TRYAGAIN:
132568350Seric 		  case NIS_RPCERROR:
132668350Seric 		  case NIS_NAMEUNREACHABLE:
132768350Seric 			break;
132868350Seric 
132968350Seric 		  default:		/* all other nisplus errors */
133068350Seric #if 0
133168350Seric 			if (!bitset(MF_OPTIONAL, map->map_mflags))
133268350Seric 				syserr("421 Cannot find table %s.%s: %s",
133368350Seric 					map->map_file, map->map_domain,
133468350Seric 					nis_sperrno(res->status));
133568350Seric #endif
133668350Seric 			errno = EBADR;
133768350Seric 			return FALSE;
133868350Seric 		}
133968350Seric 		sleep(2);		/* try not to overwhelm hosed server */
134068350Seric 		if (retry_cnt++ > 4)
134168350Seric 		{
134268350Seric 			errno = EBADR;
134368350Seric 			return FALSE;
134468350Seric 		}
134568350Seric 	}
134668350Seric 
134768350Seric 	if (NIS_RES_NUMOBJ(res) != 1 ||
134868350Seric 	    (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
134968350Seric 	{
135068350Seric 		if (tTd(38, 10))
135168350Seric 			printf("nisplus_map_open: %s is not a table\n", qbuf);
135268350Seric #if 0
135368350Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
135468350Seric 			syserr("421 %s.%s: %s is not a table",
135568350Seric 				map->map_file, map->map_domain,
135668350Seric 				nis_sperrno(res->status));
135768350Seric #endif
135868350Seric 		errno = EBADR;
135968350Seric 		return FALSE;
136068350Seric 	}
136168350Seric 	/* default key column is column 0 */
136268350Seric 	if (map->map_keycolnm == NULL)
136368350Seric 		map->map_keycolnm = newstr(COL_NAME(res,0));
136468350Seric 
136568350Seric 	max_col = COL_MAX(res);
136668350Seric 
136768350Seric 	/* verify the key column exist */
136868350Seric 	for (i=0; i< max_col; i++)
136968350Seric 	{
137068350Seric 		if (!strcmp(map->map_keycolnm, COL_NAME(res,i)))
137168350Seric 			break;
137268350Seric 	}
137368350Seric 	if (i == max_col)
137468350Seric 	{
137568350Seric 		if (tTd(38, 2))
137668350Seric 			printf("nisplus_map_open(%s): can not find key column %s\n",
137768350Seric 				map->map_file, map->map_keycolnm);
137868350Seric 		errno = EBADR;
137968350Seric 		return FALSE;
138068350Seric 	}
138168350Seric 
138268350Seric 	/* default value column is the last column */
138368350Seric 	if (map->map_valcolnm == NULL)
138468350Seric 	{
138568350Seric 		map->map_valcolno = max_col - 1;
138668350Seric 		return TRUE;
138768350Seric 	}
138868350Seric 
138968350Seric 	for (i=0; i< max_col; i++)
139068350Seric 	{
139168350Seric 		if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
139268350Seric 		{
139368350Seric 			map->map_valcolno = i;
139468350Seric 			return TRUE;
139568350Seric 		}
139668350Seric 	}
139768350Seric 
139868350Seric 	if (tTd(38, 2))
139968350Seric 		printf("nisplus_map_open(%s): can not find column %s\n",
140068350Seric 			 map->map_file, map->map_keycolnm);
140168350Seric 	errno = EBADR;
140268350Seric 	return FALSE;
140367848Seric }
140467848Seric 
140567848Seric 
140667848Seric /*
140768350Seric **  NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
140867848Seric */
140967848Seric 
141068350Seric char *
141168350Seric nisplus_map_lookup(map, name, av, statp)
141267848Seric 	MAP *map;
141368350Seric 	char *name;
141468350Seric 	char **av;
141568350Seric 	int *statp;
141667848Seric {
141768350Seric 	char *vp;
141868350Seric 	auto int vsize;
141968350Seric 	int buflen;
142068350Seric 	char search_key[MAXNAME + 1];
142168350Seric 	char qbuf[MAXLINE + NIS_MAXNAMELEN];
142268350Seric 	nis_result *result;
142368350Seric 
142468350Seric 	if (tTd(38, 20))
142568350Seric 		printf("nisplus_map_lookup(%s, %s)\n",
142668350Seric 			map->map_mname, name);
142768350Seric 
142868350Seric 	if (!bitset(MF_OPEN, map->map_mflags))
142968350Seric 	{
143068350Seric 		if (nisplus_map_open(map, O_RDONLY))
143168350Seric 			map->map_mflags |= MF_OPEN;
143268350Seric 		else
143368350Seric 		{
143468350Seric 			*statp = EX_UNAVAILABLE;
143568350Seric 			return NULL;
143668350Seric 		}
143768350Seric 	}
143868350Seric 
143968350Seric 	buflen = strlen(name);
144068350Seric 	if (buflen > sizeof search_key - 1)
144168350Seric 		buflen = sizeof search_key - 1;
144268350Seric 	bcopy(name, search_key, buflen + 1);
144368350Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
144468350Seric 		makelower(search_key);
144568350Seric 
144668350Seric 	/* construct the query */
144768350Seric 	if (PARTIAL_NAME(map->map_file))
144868350Seric 		sprintf(qbuf, "[%s=%s],%s.%s", map->map_keycolnm,
144968350Seric 			search_key, map->map_file, map->map_domain);
145068350Seric 	else
145168350Seric 		sprintf(qbuf, "[%s=%s],%s", map->map_keycolnm,
145268350Seric 			search_key, map->map_file);
145368350Seric 
145468350Seric 	if (tTd(38, 20))
145568350Seric 		printf("qbuf=%s\n", qbuf);
145668350Seric 	result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
145768350Seric 	if (result->status == NIS_SUCCESS)
145868350Seric 	{
145968350Seric 		int count;
146068350Seric 		char *str;
146168350Seric 
146268350Seric 		if ((count = NIS_RES_NUMOBJ(result)) != 1)
146368350Seric 		{
146468350Seric 			if (LogLevel > 10)
146568350Seric 				syslog(LOG_WARNING,
146668350Seric 				  "%s:Lookup error, expected 1 entry, got (%d)",
146768350Seric 				    map->map_file, count);
146868350Seric 
146968350Seric 			/* ignore second entry */
147068350Seric 			if (tTd(38, 20))
147168350Seric 				printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
147268350Seric 					name, count);
147368350Seric 		}
147468350Seric 
147568350Seric 		vp = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
147668350Seric 		/* set the length of the result */
147768350Seric 		if (vp == NULL)
147868350Seric 			vp = "";
147968350Seric 		vsize = strlen(vp);
148068350Seric 		if (tTd(38, 20))
148168350Seric 			printf("nisplus_map_lookup(%s), found %s\n",
148268350Seric 				name, vp);
148368350Seric 		if (bitset(MF_MATCHONLY, map->map_mflags))
148468350Seric 			str = map_rewrite(map, name, strlen(name), NULL);
148568350Seric 		else
148668350Seric 			str = map_rewrite(map, vp, vsize, av);
148768350Seric 		nis_freeresult(result);
148868350Seric #ifdef MAP_EXIT_STAT
148968350Seric 		*statp = EX_OK;
149068350Seric #endif
149168350Seric 		return str;
149268350Seric 	}
149368350Seric 	else
149468350Seric 	{
149568350Seric #ifdef MAP_EXIT_STAT
149668350Seric 		if (result->status == NIS_NOTFOUND)
149768350Seric 			*statp = EX_NOTFOUND;
149868350Seric 		else if (result->status == NIS_TRYAGAIN)
149968350Seric 			*statp = EX_TEMPFAIL;
150068350Seric 		else
150168350Seric 		{
150268350Seric 			*statp = EX_UNAVAILABLE;
150368350Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
150468350Seric 		}
150568350Seric #else
150668350Seric 		if ((result->status != NIS_NOTFOUND) &&
150768350Seric 		    (result->status != NIS_TRYAGAIN))
150868350Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
150968350Seric #endif
151068350Seric 	}
151168350Seric 	if (tTd(38, 20))
151268350Seric 		printf("nisplus_map_lookup(%s), failed\n", name);
151368350Seric 	nis_freeresult(result);
151468350Seric 	return NULL;
151567848Seric }
151667848Seric 
151768350Seric 
151869401Seric 
151969401Seric /*
152069401Seric **  NISPLUS_GETCANONNAME -- look up canonical name in NIS+
152169401Seric */
152269401Seric 
152369401Seric bool
152469401Seric nisplus_getcanonname(name, hbsize, statp)
152569401Seric 	char *name;
152669401Seric 	int hbsize;
152769401Seric 	int *statp;
152869401Seric {
152969401Seric 	char *vp;
153069401Seric 	auto int vsize;
153169401Seric 	int buflen;
153269401Seric 	char buf1[MAXLINE + NIS_MAXNAMELEN];
153369401Seric 	static char *nis_path = NULL;
153469401Seric 	static char nis_path_buf[MAXLINE];
153569401Seric 	nis_result *result;
153669401Seric 	char *p;
153769401Seric 	int len;
153869401Seric 
153969401Seric 	if (nis_path == NULL)
154069401Seric 	{
154169401Seric 		char *ptr;
154269401Seric 		char pathbuf[MAXLINE];
154369401Seric 
154469401Seric 		strcpy(buf1, macvalue('m', CurEnv));
154569401Seric 		strcat(buf1, ".");
154669401Seric 		/* try the host tabe in $m */
154769401Seric 		if (hosts_table_ok(buf1))
154869401Seric 			strcpy(pathbuf, buf1);
154969401Seric 		else
155069401Seric 			strcpy(pathbuf, "$");
155169401Seric 
155269401Seric 		nis_path = nis_path_buf;
155369401Seric 		sprintf(nis_path, "NIS_PATH=%s", pathbuf);
155469401Seric 	}
155569401Seric 
155669401Seric 	if (nis_path[0] != '\0')
155769401Seric 		putenv(nis_path);
155869401Seric 	else
155969401Seric 		syslog(LOG_WARNING, "no NIS+ path defined");
156069401Seric 
156169401Seric 	shorten_hostname(name);
156269401Seric 
156369401Seric 	p = strchr(name, '.');
156469401Seric 	if (p == NULL)
156569401Seric 	{
156669401Seric 		/* single token */
156769401Seric 		sprintf(buf1, "[name=%s],hosts.org_dir", name);
156869401Seric 	}
156969401Seric 	else if (p[1] != '\0')
157069401Seric 	{
157169401Seric 		/* multi token -- take only first token in name buf */
157269401Seric 		*p = '\0';
157369401Seric 		sprintf(buf1, "[name=%s],hosts.org_dir.%s", name, &p[1]);
157469401Seric 	}
157569401Seric 	else
157669401Seric 	{
157769401Seric 		*statp = EX_NOHOST;
157869401Seric 		return FALSE;
157969401Seric 	}
158069401Seric 
158169401Seric 	if (tTd(38, 20))
158269401Seric 		printf("\nnisplus_getcanoname(%s), qbuf=%s\n%s\n",
158369401Seric 			 name, buf1, nis_path);
158469401Seric 
158569401Seric 	result = nis_list(buf1, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
158669401Seric 		NULL, NULL);
158769401Seric 
158869401Seric 	/* unset NIS_PATH, just in case */
158969401Seric 	unsetenv("NIS_PATH");
159069401Seric 
159169401Seric 	if (result->status == NIS_SUCCESS)
159269401Seric 	{
159369401Seric 		int count;
159469401Seric 		char *str;
159569401Seric 		char *domain;
159669401Seric 
159769401Seric 		if ((count = NIS_RES_NUMOBJ(result)) != 1)
159869401Seric 		{
159969401Seric #ifdef LOG
160069401Seric 			if (LogLevel > 10)
160169401Seric 				syslog(LOG_WARNING,
160269401Seric 				       "nisplus_getcanonname: Lookup error, expected 1 entry, got (%d)",
160369401Seric 				       count);
160469401Seric #endif
160569401Seric 
160669401Seric 			/* ignore second entry */
160769401Seric 			if (tTd(38, 20))
160869401Seric 				printf("nisplus_getcanoname(%s), got %d entries, addtional entries ignores\n", name);
160969401Seric 		}
161069401Seric 
161169401Seric 		if (tTd(38, 20))
161269401Seric 			printf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
161369401Seric 			       name, (NIS_RES_OBJECT(result))->zo_domain);
161469401Seric 
161569401Seric 
161669401Seric 		vp = ((NIS_RES_OBJECT(result))->EN_col(0));
161769401Seric 		vsize = strlen(vp);
161869401Seric 		if (tTd(38, 20))
161969401Seric 			printf("nisplus_getcanonname(%s), found %s\n",
162069401Seric 				name, vp);
162169401Seric 		domain = macvalue('m', CurEnv);
162269401Seric 		if (hbsize > (vsize + ((int) strlen(domain))))
162369401Seric 		{
162469401Seric 			sprintf(name, "%s.%s", vp, domain);
162569401Seric 			*statp = EX_OK;
162669401Seric 		}
162769401Seric 		else
162869401Seric 			*statp = EX_NOHOST;
162969401Seric 		nis_freeresult(result);
163069401Seric 		return TRUE;
163169401Seric 	}
163269401Seric 	else
163369401Seric 	{
163469401Seric 		if (result->status == NIS_NOTFOUND)
163569401Seric 			*statp = EX_NOHOST;
163669401Seric 		else if (result->status == NIS_TRYAGAIN)
163769401Seric 			*statp = EX_TEMPFAIL;
163869401Seric 		else
163969401Seric 		{
164069401Seric 			*statp = EX_UNAVAILABLE;
164169401Seric 		}
164269401Seric 	}
164369401Seric 	if (tTd(38, 20))
164469401Seric 		printf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
164569401Seric 			name, result->status, *statp);
164669401Seric 	nis_freeresult(result);
164769401Seric 	return FALSE;
164869401Seric }
164969401Seric 
165069401Seric 
165168350Seric char *
165268350Seric nisplus_default_domain()
165368350Seric {
165468528Seric 	static char default_domain[MAXNAME + 1] = "";
165568350Seric 	char *p;
165668350Seric 
165768350Seric 	if (default_domain[0] != '\0')
165868350Seric 		return(default_domain);
165968350Seric 
166068458Seric 	p = nis_local_directory();
166168350Seric 	strcpy(default_domain, p);
166268458Seric 	return default_domain;
166368350Seric }
166468350Seric 
166568350Seric #endif /* NISPLUS */
166667848Seric /*
166768350Seric **  HESIOD Modules
166868350Seric */
166968350Seric 
167068350Seric #ifdef HESIOD
167168350Seric 
167268350Seric #include <hesiod.h>
167368350Seric 
167468350Seric char *
167568350Seric hes_map_lookup(map, name, av, statp)
167668350Seric         MAP *map;
167768350Seric         char *name;
167868350Seric         char **av;
167968350Seric         int *statp;
168068350Seric {
168168350Seric 	char **hp;
168268350Seric 	char *retdata = NULL;
168368350Seric 	int i;
168468350Seric 
168568350Seric 	if (tTd(38, 20))
168668350Seric 		printf("hes_map_lookup(%s, %s)\n", map->map_file, name);
168768350Seric 
168868350Seric 	hp = hes_resolve(name, map->map_file);
168968350Seric 	if (hp == NULL)
169068350Seric 		return NULL;
169168350Seric 
169268350Seric 	if (hp[0] != NULL)
169368350Seric 	{
169468350Seric 		if (bitset(MF_MATCHONLY, map->map_mflags))
169568350Seric 			retdata = map_rewrite(map, name, strlen(name), NULL);
169668350Seric 		else
169768350Seric 			retdata = map_rewrite(map, hp[0], strlen(hp[0]), av);
169868350Seric 	}
169968350Seric 
170068350Seric 	for (i = 0; hp[i] != NULL; i++)
170168350Seric 		free(hp[i]);
170268350Seric 	free(hp);
170368350Seric 	return retdata;
170468350Seric }
170568350Seric 
170668350Seric #endif
170768350Seric /*
170868350Seric **  NeXT NETINFO Modules
170968350Seric */
171068350Seric 
171168350Seric #ifdef NETINFO
171268350Seric 
171368350Seric #define NETINFO_DEFAULT_DIR		"/aliases"
171468350Seric #define NETINFO_DEFAULT_PROPERTY	"members"
171568350Seric 
171668350Seric 
171768350Seric /*
171868350Seric **  NI_MAP_OPEN -- open NetInfo Aliases
171968350Seric */
172068350Seric 
172168350Seric bool
172268350Seric ni_map_open(map, mode)
172368350Seric 	MAP *map;
172468350Seric 	int mode;
172568350Seric {
172668350Seric 	char *p;
172768350Seric 
172868350Seric 	if (tTd(38, 20))
172968350Seric 		printf("ni_map_open: %s\n", map->map_file);
173068350Seric 
173168350Seric 	if (*map->map_file == '\0')
173268350Seric 		map->map_file = NETINFO_DEFAULT_DIR;
173368350Seric 
173468350Seric 	if (map->map_valcolnm == NULL)
173568350Seric 		map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
173668350Seric 
173768350Seric 	if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
173868350Seric 		map->map_coldelim = ',';
173968350Seric 
174068350Seric 	return TRUE;
174168350Seric }
174268350Seric 
174368350Seric 
174468350Seric /*
174568350Seric **  NI_MAP_LOOKUP -- look up a datum in NetInfo
174668350Seric */
174768350Seric 
174868350Seric char *
174968350Seric ni_map_lookup(map, name, av, statp)
175068350Seric 	MAP *map;
175168350Seric 	char *name;
175268350Seric 	char **av;
175368350Seric 	int *statp;
175468350Seric {
175568350Seric 	char *res;
175668350Seric 	char *propval;
175768350Seric 	extern char *ni_propval();
175868350Seric 
175968350Seric 	if (tTd(38, 20))
176068350Seric 		printf("ni_map_lookup(%s, %s)\n",
176168350Seric 			map->map_mname, name);
176268350Seric 
176368350Seric 	propval = ni_propval(map->map_file, map->map_keycolnm, name,
176468350Seric 			     map->map_valcolnm, map->map_coldelim);
176568350Seric 
176668350Seric 	if (propval == NULL)
176768350Seric 		return NULL;
176868350Seric 
176968350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
177068350Seric 		res = map_rewrite(map, name, strlen(name), NULL);
177168350Seric 	else
177268350Seric 		res = map_rewrite(map, propval, strlen(propval), av);
177368350Seric 	free(propval);
177468350Seric 	return res;
177568350Seric }
177668350Seric 
177768350Seric #endif
177868350Seric /*
177968350Seric **  TEXT (unindexed text file) Modules
178068350Seric **
178168350Seric **	This code donated by Sun Microsystems.
178268350Seric */
178368350Seric 
178468350Seric 
178568350Seric /*
178668350Seric **  TEXT_MAP_OPEN -- open text table
178768350Seric */
178868350Seric 
178968350Seric bool
179068350Seric text_map_open(map, mode)
179168350Seric 	MAP *map;
179268350Seric 	int mode;
179368350Seric {
179468350Seric 	struct stat sbuf;
179568350Seric 
179668350Seric 	if (tTd(38, 2))
179768350Seric 		printf("text_map_open(%s, %s, %d)\n",
179868350Seric 			map->map_mname, map->map_file, mode);
179968350Seric 
180068350Seric 	if (mode != O_RDONLY)
180168350Seric 	{
180268350Seric 		errno = ENODEV;
180368350Seric 		return FALSE;
180468350Seric 	}
180568350Seric 
180668350Seric 	if (*map->map_file == '\0')
180768350Seric 	{
180868350Seric 		if (tTd(38, 2))
180968350Seric 			printf("text_map_open: file name required\n");
181068350Seric 		return FALSE;
181168350Seric 	}
181268350Seric 
181368350Seric 	if (map->map_file[0] != '/')
181468350Seric 	{
181568350Seric 		if (tTd(38, 2))
181668350Seric 			printf("text_map_open(%s): file name must be fully qualified\n",
181768350Seric 				map->map_file);
181868350Seric 		return FALSE;
181968350Seric 	}
182068350Seric 	/* check to see if this map actually accessable */
182168350Seric 	if (access(map->map_file, R_OK) <0)
182268350Seric 		return FALSE;
182368350Seric 
182468350Seric 	/* check to see if this map actually exist */
182568350Seric 	if (stat(map->map_file, &sbuf) <0)
182668350Seric 	{
182768350Seric 		if (tTd(38, 2))
182868350Seric 			printf("text_map_open(%s): can not stat %s\n",
182968350Seric 				map->map_file, map->map_file);
183068350Seric 		return FALSE;
183168350Seric 	}
183268350Seric 
183368350Seric 	if (!S_ISREG(sbuf.st_mode))
183468350Seric 	{
183568350Seric 		if (tTd(38, 2))
183668350Seric 			printf("text_map_open(%s): %s is not a file\n",
183768350Seric 				map->map_file, map->map_file);
183868350Seric 		return FALSE;
183968350Seric 	}
184068350Seric 
184168350Seric 	if (map->map_keycolnm == NULL)
184268350Seric 		map->map_keycolno = 0;
184368350Seric 	else
184468350Seric 	{
184568350Seric 		if (!isdigit(*map->map_keycolnm))
184668350Seric 		{
184768350Seric 			if (tTd(38, 2))
184868350Seric 				printf("text_map_open(%s): -k should specify a number, not %s\n",
184968350Seric 					map->map_file, map->map_keycolnm);
185068350Seric 			return FALSE;
185168350Seric 		}
185268350Seric 		map->map_keycolno = atoi(map->map_keycolnm);
185368350Seric 	}
185468350Seric 
185568350Seric 	if (map->map_valcolnm == NULL)
185668350Seric 		map->map_valcolno = 0;
185768350Seric 	else
185868350Seric 	{
185968350Seric 		if (!isdigit(*map->map_valcolnm))
186068350Seric 		{
186168350Seric 			if (tTd(38, 2))
186268350Seric 				printf("text_map_open(%s): -v should specify a number, not %s\n",
186368350Seric 					map->map_file, map->map_valcolnm);
186468350Seric 			return FALSE;
186568350Seric 		}
186668350Seric 		map->map_valcolno = atoi(map->map_valcolnm);
186768350Seric 	}
186868350Seric 
186968350Seric 	if (tTd(38, 2))
187068350Seric 	{
187168520Seric 		printf("text_map_open(%s): delimiter = ",
187268520Seric 			map->map_file);
187368520Seric 		if (map->map_coldelim == '\0')
187468520Seric 			printf("(white space)\n");
187568520Seric 		else
187668520Seric 			printf("%c\n", map->map_coldelim);
187768350Seric 	}
187868350Seric 
187968350Seric 	return TRUE;
188068350Seric }
188168350Seric 
188268350Seric 
188368350Seric /*
188468350Seric **  TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
188568350Seric */
188668350Seric 
188768350Seric char *
188868350Seric text_map_lookup(map, name, av, statp)
188968350Seric 	MAP *map;
189068350Seric 	char *name;
189168350Seric 	char **av;
189268350Seric 	int *statp;
189368350Seric {
189468350Seric 	char *vp;
189568350Seric 	auto int vsize;
189668350Seric 	int buflen;
189768350Seric 	char search_key[MAXNAME + 1];
189868350Seric 	char linebuf[MAXLINE];
189968350Seric 	FILE *f;
190068528Seric 	char buf[MAXNAME + 1];
190168350Seric 	char delim;
190268350Seric 	int key_idx;
190368350Seric 	bool found_it;
190468350Seric 	extern char *get_column();
190568350Seric 
190668350Seric 
190768350Seric 	found_it = FALSE;
190868350Seric 	if (tTd(38, 20))
190968350Seric 		printf("text_map_lookup(%s)\n", name);
191068350Seric 
191168350Seric 	buflen = strlen(name);
191268350Seric 	if (buflen > sizeof search_key - 1)
191368350Seric 		buflen = sizeof search_key - 1;
191468350Seric 	bcopy(name, search_key, buflen + 1);
191568350Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
191668350Seric 		makelower(search_key);
191768350Seric 
191868350Seric 	f = fopen(map->map_file, "r");
191968350Seric 	if (f == NULL)
192068350Seric 	{
192168350Seric 		map->map_mflags &= ~(MF_VALID|MF_OPEN);
192268350Seric 		*statp = EX_UNAVAILABLE;
192368350Seric 		return NULL;
192468350Seric 	}
192568350Seric 	key_idx = map->map_keycolno;
192668350Seric 	delim = map->map_coldelim;
192768350Seric 	while (fgets(linebuf, MAXLINE, f))
192868350Seric 	{
192968350Seric 		char *lf;
193068350Seric 		if (linebuf[0] == '#')
193168350Seric 			continue; /* skip comment line */
193268350Seric 		if (lf = strchr(linebuf, '\n'))
193368350Seric 			*lf = '\0';
193468350Seric 		if (!strcasecmp(search_key,
193568350Seric 				get_column(linebuf, key_idx, delim, buf)))
193668350Seric 		{
193768350Seric 			found_it = TRUE;
193868350Seric 			break;
193968350Seric 		}
194068350Seric 	}
194168350Seric 	fclose(f);
194268350Seric 	if (!found_it)
194368350Seric 	{
194468350Seric #ifdef MAP_EXIT_STAT
194568350Seric 		*statp = EX_NOTFOUND;
194668350Seric #endif
194768350Seric 		return(NULL);
194868350Seric 	}
194968350Seric 	vp = get_column(linebuf, map->map_valcolno, delim, buf);
195068350Seric 	vsize = strlen(vp);
195168350Seric #ifdef MAP_EXIT_STAT
195268350Seric 	*statp = EX_OK;
195368350Seric #endif
195468350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
195568350Seric 		return map_rewrite(map, name, strlen(name), NULL);
195668350Seric 	else
195768350Seric 		return map_rewrite(map, vp, vsize, av);
195868350Seric }
195969401Seric 
196069401Seric 
196169401Seric /*
196269401Seric **  TEXT_GETCANONNAME -- look up canonical name in hosts file
196369401Seric */
196469401Seric 
196569401Seric bool
196669401Seric text_getcanonname(name, hbsize, statp)
196769401Seric 	char *name;
196869401Seric 	int hbsize;
196969401Seric 	int *statp;
197069401Seric {
197169401Seric 	int buflen;
197269401Seric 	char delim;
197369401Seric 	int key_idx;
197469401Seric 	char *cname;
197569401Seric 	bool found;
197669401Seric 	char *domain;
197769401Seric 	FILE *f;
197869401Seric 	char linebuf[MAXLINE];
197969401Seric 	char cbuf[MAXNAME + 1];
198069401Seric 	char buf[MAXNAME + 1];
198169401Seric 	extern char *get_column();
198269401Seric 
198369401Seric 	shorten_hostname(name);
198469401Seric 
198569401Seric 	/* we only accept single token search key */
198669401Seric 	if (strchr(name, '.') != NULL)
198769401Seric 	{
198869401Seric 		*statp = EX_NOHOST;
198969401Seric 		return FALSE;
199069401Seric 	}
199169401Seric 
199269401Seric 	found = FALSE;
199369401Seric 
199469401Seric 	f = fopen(HostsFile, "r");
199569401Seric 	if (f == NULL)
199669401Seric 	{
199769401Seric #ifdef MAP_EXIT_STAT
199869401Seric 		*statp = EX_UNAVAILABLE;
199969401Seric #endif
200069401Seric 		return FALSE;
200169401Seric 	}
200269401Seric 	delim = '\t';
200369401Seric 	while (!found && fgets(linebuf, MAXLINE, f) != NULL)
200469401Seric 	{
200569401Seric 		char *p;
200669401Seric 
200769401Seric 		if (linebuf[0] == '#')
200869401Seric 			continue;
200969401Seric 		if ((p = strchr(linebuf, '\n')) != NULL)
201069401Seric 			*p = '\0';
201169401Seric 		cname = get_column(linebuf, 1, delim, cbuf);
201269401Seric 		if (cname != NULL && strcasecmp(name,  cname) == 0)
201369401Seric 		{
201469401Seric 			found = TRUE;
201569401Seric 			break;
201669401Seric 		}
201769401Seric 
201869401Seric 		key_idx = 2;
201969401Seric 		while ((p = get_column(linebuf, key_idx, delim, buf)) != NULL)
202069401Seric 		{
202169401Seric 			if (strcasecmp(name, p) == 0)
202269401Seric 			{
202369401Seric 				found = TRUE;
202469401Seric 				break;
202569401Seric 			}
202669401Seric 			key_idx++;
202769401Seric 		}
202869401Seric 	}
202969401Seric 	fclose(f);
203069401Seric 	if (!found)
203169401Seric 	{
203269401Seric 		*statp = EX_NOHOST;
203369401Seric 		return FALSE;
203469401Seric 	}
203569401Seric 
203669401Seric 	if (hbsize >= strlen(cname))
203769401Seric 	{
203869401Seric 		strcpy(name, cname);
203969401Seric 		*statp = EX_OK;
204069401Seric 		return TRUE;
204169401Seric 	}
204269401Seric 	*statp = EX_UNAVAILABLE;
204369401Seric 	return FALSE;
204469401Seric }
204568350Seric /*
204660089Seric **  STAB (Symbol Table) Modules
204760089Seric */
204860089Seric 
204960089Seric 
205060089Seric /*
205160207Seric **  STAB_MAP_LOOKUP -- look up alias in symbol table
205260089Seric */
205360089Seric 
205460089Seric char *
205561707Seric stab_map_lookup(map, name, av, pstat)
205660089Seric 	register MAP *map;
205760089Seric 	char *name;
205861707Seric 	char **av;
205961707Seric 	int *pstat;
206060089Seric {
206160089Seric 	register STAB *s;
206260089Seric 
206360537Seric 	if (tTd(38, 20))
206468350Seric 		printf("stab_lookup(%s, %s)\n",
206568350Seric 			map->map_mname, name);
206660089Seric 
206760089Seric 	s = stab(name, ST_ALIAS, ST_FIND);
206860089Seric 	if (s != NULL)
206960089Seric 		return (s->s_alias);
207060089Seric 	return (NULL);
207160089Seric }
207260089Seric 
207360089Seric 
207460089Seric /*
207560207Seric **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
207660089Seric */
207760089Seric 
207860089Seric void
207960089Seric stab_map_store(map, lhs, rhs)
208060089Seric 	register MAP *map;
208160089Seric 	char *lhs;
208260089Seric 	char *rhs;
208360089Seric {
208460089Seric 	register STAB *s;
208560089Seric 
208660089Seric 	s = stab(lhs, ST_ALIAS, ST_ENTER);
208760089Seric 	s->s_alias = newstr(rhs);
208860089Seric }
208960089Seric 
209060089Seric 
209160089Seric /*
209260207Seric **  STAB_MAP_OPEN -- initialize (reads data file)
209360207Seric **
209460207Seric **	This is a wierd case -- it is only intended as a fallback for
209560207Seric **	aliases.  For this reason, opens for write (only during a
209660207Seric **	"newaliases") always fails, and opens for read open the
209760207Seric **	actual underlying text file instead of the database.
209860089Seric */
209960089Seric 
210060089Seric bool
210160089Seric stab_map_open(map, mode)
210260089Seric 	register MAP *map;
210360089Seric 	int mode;
210460089Seric {
210563835Seric 	FILE *af;
210664284Seric 	struct stat st;
210763835Seric 
210860537Seric 	if (tTd(38, 2))
210968350Seric 		printf("stab_map_open(%s, %s)\n",
211068350Seric 			map->map_mname, map->map_file);
211160089Seric 
211260089Seric 	if (mode != O_RDONLY)
211360207Seric 	{
211460207Seric 		errno = ENODEV;
211560089Seric 		return FALSE;
211660207Seric 	}
211760089Seric 
211863835Seric 	af = fopen(map->map_file, "r");
211963835Seric 	if (af == NULL)
212063835Seric 		return FALSE;
212168350Seric 	readaliases(map, af, FALSE, FALSE);
212264284Seric 
212364284Seric 	if (fstat(fileno(af), &st) >= 0)
212464284Seric 		map->map_mtime = st.st_mtime;
212563835Seric 	fclose(af);
212663835Seric 
212760089Seric 	return TRUE;
212860089Seric }
212960089Seric /*
213060089Seric **  Implicit Modules
213156822Seric **
213260089Seric **	Tries several types.  For back compatibility of aliases.
213356822Seric */
213456822Seric 
213560089Seric 
213660089Seric /*
213760207Seric **  IMPL_MAP_LOOKUP -- lookup in best open database
213860089Seric */
213960089Seric 
214060089Seric char *
214160089Seric impl_map_lookup(map, name, av, pstat)
214260089Seric 	MAP *map;
214360089Seric 	char *name;
214456822Seric 	char **av;
214560089Seric 	int *pstat;
214656822Seric {
214760537Seric 	if (tTd(38, 20))
214868350Seric 		printf("impl_map_lookup(%s, %s)\n",
214968350Seric 			map->map_mname, name);
215056822Seric 
215160089Seric #ifdef NEWDB
215260207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
215360089Seric 		return db_map_lookup(map, name, av, pstat);
215460089Seric #endif
215560089Seric #ifdef NDBM
215660207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
215760089Seric 		return ndbm_map_lookup(map, name, av, pstat);
215860089Seric #endif
215960089Seric 	return stab_map_lookup(map, name, av, pstat);
216060089Seric }
216160089Seric 
216260089Seric /*
216360207Seric **  IMPL_MAP_STORE -- store in open databases
216460089Seric */
216560089Seric 
216660089Seric void
216760089Seric impl_map_store(map, lhs, rhs)
216860089Seric 	MAP *map;
216960089Seric 	char *lhs;
217060089Seric 	char *rhs;
217160089Seric {
217260089Seric #ifdef NEWDB
217360207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
217460089Seric 		db_map_store(map, lhs, rhs);
217560089Seric #endif
217660089Seric #ifdef NDBM
217760207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
217860089Seric 		ndbm_map_store(map, lhs, rhs);
217960089Seric #endif
218060089Seric 	stab_map_store(map, lhs, rhs);
218160089Seric }
218260089Seric 
218360089Seric /*
218460089Seric **  IMPL_MAP_OPEN -- implicit database open
218560089Seric */
218660089Seric 
218760089Seric bool
218860089Seric impl_map_open(map, mode)
218960089Seric 	MAP *map;
219060089Seric 	int mode;
219160089Seric {
219260089Seric 	struct stat stb;
219360089Seric 
219460537Seric 	if (tTd(38, 2))
219568350Seric 		printf("impl_map_open(%s, %s, %d)\n",
219668350Seric 			map->map_mname, map->map_file, mode);
219760089Seric 
219860089Seric 	if (stat(map->map_file, &stb) < 0)
219956822Seric 	{
220060089Seric 		/* no alias file at all */
220164718Seric 		if (tTd(38, 3))
220264718Seric 			printf("no map file\n");
220360089Seric 		return FALSE;
220456822Seric 	}
220556822Seric 
220660089Seric #ifdef NEWDB
220760207Seric 	map->map_mflags |= MF_IMPL_HASH;
220860089Seric 	if (hash_map_open(map, mode))
220956822Seric 	{
221064250Seric #if defined(NDBM) && defined(NIS)
221160561Seric 		if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0)
221260207Seric #endif
221360207Seric 			return TRUE;
221460089Seric 	}
221560207Seric 	else
221660207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
221760089Seric #endif
221860089Seric #ifdef NDBM
221960207Seric 	map->map_mflags |= MF_IMPL_NDBM;
222060089Seric 	if (ndbm_map_open(map, mode))
222160089Seric 	{
222260089Seric 		return TRUE;
222360089Seric 	}
222460207Seric 	else
222560207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
222660089Seric #endif
222756822Seric 
222864650Seric #if defined(NEWDB) || defined(NDBM)
222960089Seric 	if (Verbose)
223060089Seric 		message("WARNING: cannot open alias database %s", map->map_file);
223164964Seric #else
223264964Seric 	if (mode != O_RDONLY)
223364964Seric 		usrerr("Cannot rebuild aliases: no database format defined");
223460207Seric #endif
223560089Seric 
223660207Seric 	return stab_map_open(map, mode);
223756822Seric }
223860089Seric 
223960207Seric 
224060089Seric /*
224160207Seric **  IMPL_MAP_CLOSE -- close any open database(s)
224260089Seric */
224360089Seric 
224460089Seric void
224560207Seric impl_map_close(map)
224660089Seric 	MAP *map;
224760089Seric {
224868350Seric 	if (tTd(38, 20))
224968350Seric 		printf("impl_map_close(%s, %s, %x)\n",
225068350Seric 			map->map_mname, map->map_file, map->map_mflags);
225160089Seric #ifdef NEWDB
225260207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
225360089Seric 	{
225460207Seric 		db_map_close(map);
225560207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
225660089Seric 	}
225760089Seric #endif
225860089Seric 
225960089Seric #ifdef NDBM
226060207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
226160089Seric 	{
226260207Seric 		ndbm_map_close(map);
226360207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
226460089Seric 	}
226560089Seric #endif
226660089Seric }
226760207Seric /*
226868350Seric **  User map class.
226968350Seric **
227068350Seric **	Provides access to the system password file.
227168350Seric */
227268350Seric 
227368350Seric /*
227468350Seric **  USER_MAP_OPEN -- open user map
227568350Seric **
227668350Seric **	Really just binds field names to field numbers.
227768350Seric */
227868350Seric 
227968350Seric bool
228068350Seric user_map_open(map, mode)
228168350Seric 	MAP *map;
228268350Seric 	int mode;
228368350Seric {
228468350Seric 	if (tTd(38, 2))
228568350Seric 		printf("user_map_open(%s)\n", map->map_mname);
228668350Seric 
228768350Seric 	if (mode != O_RDONLY)
228868350Seric 	{
228968350Seric 		/* issue a pseudo-error message */
229068350Seric #ifdef ENOSYS
229168350Seric 		errno = ENOSYS;
229268350Seric #else
229368350Seric # ifdef EFTYPE
229468350Seric 		errno = EFTYPE;
229568350Seric # else
229668350Seric 		errno = ENXIO;
229768350Seric # endif
229868350Seric #endif
229968350Seric 		return FALSE;
230068350Seric 	}
230168350Seric 	if (map->map_valcolnm == NULL)
230268350Seric 		/* nothing */ ;
230368350Seric 	else if (strcasecmp(map->map_valcolnm, "name") == 0)
230468350Seric 		map->map_valcolno = 1;
230568350Seric 	else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
230668350Seric 		map->map_valcolno = 2;
230768350Seric 	else if (strcasecmp(map->map_valcolnm, "uid") == 0)
230868350Seric 		map->map_valcolno = 3;
230968350Seric 	else if (strcasecmp(map->map_valcolnm, "gid") == 0)
231068350Seric 		map->map_valcolno = 4;
231168350Seric 	else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
231268350Seric 		map->map_valcolno = 5;
231368350Seric 	else if (strcasecmp(map->map_valcolnm, "dir") == 0)
231468350Seric 		map->map_valcolno = 6;
231568350Seric 	else if (strcasecmp(map->map_valcolnm, "shell") == 0)
231668350Seric 		map->map_valcolno = 7;
231768350Seric 	else
231868350Seric 	{
231968350Seric 		syserr("User map %s: unknown column name %s",
232068350Seric 			map->map_mname, map->map_valcolnm);
232168350Seric 		return FALSE;
232268350Seric 	}
232368350Seric 	return TRUE;
232468350Seric }
232568350Seric 
232668350Seric 
232768350Seric /*
232868350Seric **  USER_MAP_LOOKUP -- look up a user in the passwd file.
232968350Seric */
233068350Seric 
233168350Seric char *
233268350Seric user_map_lookup(map, key, av, statp)
233368350Seric 	MAP *map;
233468350Seric 	char *key;
233568350Seric 	char **av;
233668350Seric 	int *statp;
233768350Seric {
233868350Seric 	struct passwd *pw;
233968350Seric 
234068350Seric 	if (tTd(38, 20))
234168350Seric 		printf("user_map_lookup(%s, %s)\n",
234268350Seric 			map->map_mname, key);
234368350Seric 
234468693Seric 	pw = sm_getpwnam(key);
234568350Seric 	if (pw == NULL)
234668350Seric 		return NULL;
234768350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
234868350Seric 		return map_rewrite(map, key, strlen(key), NULL);
234968350Seric 	else
235068350Seric 	{
235168433Seric 		char *rwval = NULL;
235268350Seric 		char buf[30];
235368350Seric 
235468350Seric 		switch (map->map_valcolno)
235568350Seric 		{
235668350Seric 		  case 0:
235768350Seric 		  case 1:
235868350Seric 			rwval = pw->pw_name;
235968350Seric 			break;
236068350Seric 
236168350Seric 		  case 2:
236268350Seric 			rwval = pw->pw_passwd;
236368350Seric 			break;
236468350Seric 
236568350Seric 		  case 3:
236668350Seric 			sprintf(buf, "%d", pw->pw_uid);
236768350Seric 			rwval = buf;
236868350Seric 			break;
236968350Seric 
237068350Seric 		  case 4:
237168350Seric 			sprintf(buf, "%d", pw->pw_gid);
237268350Seric 			rwval = buf;
237368350Seric 			break;
237468350Seric 
237568350Seric 		  case 5:
237668350Seric 			rwval = pw->pw_gecos;
237768350Seric 			break;
237868350Seric 
237968350Seric 		  case 6:
238068350Seric 			rwval = pw->pw_dir;
238168350Seric 			break;
238268350Seric 
238368350Seric 		  case 7:
238468350Seric 			rwval = pw->pw_shell;
238568350Seric 			break;
238668350Seric 		}
238768350Seric 		return map_rewrite(map, rwval, strlen(rwval), av);
238868350Seric 	}
238968350Seric }
239068350Seric /*
239168350Seric **  BESTMX -- find the best MX for a name
239268350Seric **
239368350Seric **	This is really a hack, but I don't see any obvious way
239468350Seric **	to generalize it at the moment.
239568350Seric */
239668350Seric 
239768350Seric #if NAMED_BIND
239868350Seric 
239968350Seric char *
240068350Seric bestmx_map_lookup(map, name, av, statp)
240168350Seric 	MAP *map;
240268350Seric 	char *name;
240368350Seric 	char **av;
240468350Seric 	int *statp;
240568350Seric {
240668350Seric         int nmx;
240768350Seric         auto int rcode;
240868350Seric         char *mxhosts[MAXMXHOSTS + 1];
240968350Seric 
241068350Seric 	nmx = getmxrr(name, mxhosts, FALSE, &rcode);
241168350Seric 	if (nmx <= 0)
241268350Seric 		return NULL;
241368350Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
241468350Seric 		return map_rewrite(map, name, strlen(name), NULL);
241568350Seric 	else
241668350Seric 		return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
241768350Seric }
241868350Seric 
241968350Seric #endif
242068350Seric /*
2421*69453Seric **  Program map type.
2422*69453Seric **
2423*69453Seric **	This provides access to arbitrary programs.  It should be used
2424*69453Seric **	only very sparingly, since there is no way to bound the cost
2425*69453Seric **	of invoking an arbitrary program.
2426*69453Seric */
2427*69453Seric 
2428*69453Seric char *
2429*69453Seric prog_map_lookup(map, name, av, statp)
2430*69453Seric 	MAP *map;
2431*69453Seric 	char *name;
2432*69453Seric 	char **av;
2433*69453Seric 	int *statp;
2434*69453Seric {
2435*69453Seric 	int i;
2436*69453Seric 	register char *p;
2437*69453Seric 	int fd;
2438*69453Seric 	auto pid_t pid;
2439*69453Seric 	char *argv[MAXPV + 1];
2440*69453Seric 	char buf[MAXLINE];
2441*69453Seric 
2442*69453Seric 	if (tTd(38, 20))
2443*69453Seric 		printf("prog_map_lookup(%s, %s) %s\n",
2444*69453Seric 			map->map_mname, name, map->map_file);
2445*69453Seric 
2446*69453Seric 	i = 0;
2447*69453Seric 	argv[i++] = map->map_file;
2448*69453Seric 	strcpy(buf, map->map_rebuild);
2449*69453Seric 	for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
2450*69453Seric 	{
2451*69453Seric 		if (i >= MAXPV - 1)
2452*69453Seric 			break;
2453*69453Seric 		argv[i++] = p;
2454*69453Seric 	}
2455*69453Seric 	argv[i++] = name;
2456*69453Seric 	argv[i] = NULL;
2457*69453Seric 	pid = prog_open(argv, &fd, CurEnv);
2458*69453Seric 	if (pid < 0)
2459*69453Seric 	{
2460*69453Seric 		if (tTd(38, 9))
2461*69453Seric 			printf("prog_map_lookup(%s) failed (%s) -- closing",
2462*69453Seric 				map->map_mname, errstring(errno));
2463*69453Seric 		map->map_mflags &= ~(MF_VALID|MF_OPEN);
2464*69453Seric 		return NULL;
2465*69453Seric 	}
2466*69453Seric 	i = read(fd, buf, sizeof buf - 1);
2467*69453Seric 	if (i <= 0 && tTd(38, 2))
2468*69453Seric 		printf("prog_map_lookup(%s): read error %s\n",
2469*69453Seric 			map->map_mname, strerror(errno));
2470*69453Seric 	if (i > 0)
2471*69453Seric 	{
2472*69453Seric 		char *rval;
2473*69453Seric 
2474*69453Seric 		buf[i] = '\0';
2475*69453Seric 		p = strchr(buf, '\n');
2476*69453Seric 		if (p != NULL)
2477*69453Seric 			*p = '\0';
2478*69453Seric 
2479*69453Seric 		/* collect the return value */
2480*69453Seric 		if (bitset(MF_MATCHONLY, map->map_mflags))
2481*69453Seric 			rval = map_rewrite(map, name, strlen(name), NULL);
2482*69453Seric 		else
2483*69453Seric 			rval = map_rewrite(map, buf, strlen(buf), NULL);
2484*69453Seric 
2485*69453Seric 		/* now flush any additional output */
2486*69453Seric 		while ((i = read(fd, buf, sizeof buf)) > 0)
2487*69453Seric 			continue;
2488*69453Seric 		close(fd);
2489*69453Seric 
2490*69453Seric 		/* and wait for the process to terminate */
2491*69453Seric 		*statp = waitfor(pid);
2492*69453Seric 
2493*69453Seric 		return rval;
2494*69453Seric 	}
2495*69453Seric 
2496*69453Seric 	close(fd);
2497*69453Seric 	*statp = waitfor(pid);
2498*69453Seric 	return NULL;
2499*69453Seric }
2500*69453Seric /*
250168350Seric **  Sequenced map type.
250268350Seric **
250368350Seric **	Tries each map in order until something matches, much like
250468350Seric **	implicit.  Stores go to the first map in the list that can
250568350Seric **	support storing.
250668350Seric **
250768350Seric **	This is slightly unusual in that there are two interfaces.
250868350Seric **	The "sequence" interface lets you stack maps arbitrarily.
250968350Seric **	The "switch" interface builds a sequence map by looking
251068350Seric **	at a system-dependent configuration file such as
251168350Seric **	/etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
251268350Seric **
251368350Seric **	We don't need an explicit open, since all maps are
251468350Seric **	opened during startup, including underlying maps.
251568350Seric */
251668350Seric 
251768350Seric /*
251868350Seric **  SEQ_MAP_PARSE -- Sequenced map parsing
251968350Seric */
252068350Seric 
252168350Seric bool
252268350Seric seq_map_parse(map, ap)
252368350Seric 	MAP *map;
252468350Seric 	char *ap;
252568350Seric {
252668350Seric 	int maxmap;
252768350Seric 
252868350Seric 	if (tTd(38, 2))
252968350Seric 		printf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
253068350Seric 	maxmap = 0;
253168350Seric 	while (*ap != '\0')
253268350Seric 	{
253368350Seric 		register char *p;
253468350Seric 		STAB *s;
253568350Seric 
253668350Seric 		/* find beginning of map name */
253768350Seric 		while (isascii(*ap) && isspace(*ap))
253868350Seric 			ap++;
253968350Seric 		for (p = ap; isascii(*p) && isalnum(*p); p++)
254068350Seric 			continue;
254168350Seric 		if (*p != '\0')
254268350Seric 			*p++ = '\0';
254368350Seric 		while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
254468350Seric 			p++;
254568350Seric 		if (*ap == '\0')
254668350Seric 		{
254768350Seric 			ap = p;
254868350Seric 			continue;
254968350Seric 		}
255068350Seric 		s = stab(ap, ST_MAP, ST_FIND);
255168350Seric 		if (s == NULL)
255268350Seric 		{
255368350Seric 			syserr("Sequence map %s: unknown member map %s",
255468350Seric 				map->map_mname, ap);
255568350Seric 		}
255668350Seric 		else if (maxmap == MAXMAPSTACK)
255768350Seric 		{
255868350Seric 			syserr("Sequence map %s: too many member maps (%d max)",
255968350Seric 				map->map_mname, MAXMAPSTACK);
256068350Seric 			maxmap++;
256168350Seric 		}
256268350Seric 		else if (maxmap < MAXMAPSTACK)
256368350Seric 		{
256468350Seric 			map->map_stack[maxmap++] = &s->s_map;
256568350Seric 		}
256668350Seric 		ap = p;
256768350Seric 	}
256868350Seric 	return TRUE;
256968350Seric }
257068350Seric 
257168350Seric 
257268350Seric /*
257368350Seric **  SWITCH_MAP_OPEN -- open a switched map
257468350Seric **
257568350Seric **	This looks at the system-dependent configuration and builds
257668350Seric **	a sequence map that does the same thing.
257768350Seric **
257868350Seric **	Every system must define a switch_map_find routine in conf.c
257968350Seric **	that will return the list of service types associated with a
258068350Seric **	given service class.
258168350Seric */
258268350Seric 
258368350Seric bool
258468350Seric switch_map_open(map, mode)
258568350Seric 	MAP *map;
258668350Seric 	int mode;
258768350Seric {
258868350Seric 	int mapno;
258968350Seric 	int nmaps;
259068350Seric 	char *maptype[MAXMAPSTACK];
259168350Seric 
259268350Seric 	if (tTd(38, 2))
259368350Seric 		printf("switch_map_open(%s, %s, %d)\n",
259468350Seric 			map->map_mname, map->map_file, mode);
259568350Seric 
259668350Seric 	nmaps = switch_map_find(map->map_file, maptype, map->map_return);
259768350Seric 	if (tTd(38, 19))
259868350Seric 	{
259968350Seric 		printf("\tswitch_map_find => %d\n", nmaps);
260068350Seric 		for (mapno = 0; mapno < nmaps; mapno++)
260168350Seric 			printf("\t\t%s\n", maptype[mapno]);
260268350Seric 	}
260368350Seric 	if (nmaps <= 0 || nmaps > MAXMAPSTACK)
260468350Seric 		return FALSE;
260568350Seric 
260668350Seric 	for (mapno = 0; mapno < nmaps; mapno++)
260768350Seric 	{
260868350Seric 		register STAB *s;
260968350Seric 		char nbuf[MAXNAME + 1];
261068350Seric 
261168350Seric 		if (maptype[mapno] == NULL)
261268350Seric 			continue;
261368350Seric 		(void) sprintf(nbuf, "%s.%s", map->map_file, maptype[mapno]);
261468350Seric 		s = stab(nbuf, ST_MAP, ST_FIND);
261568350Seric 		if (s == NULL)
261668350Seric 		{
261768350Seric 			syserr("Switch map %s: unknown member map %s",
261868350Seric 				map->map_mname, nbuf);
261968350Seric 		}
262068350Seric 		else
262168350Seric 		{
262268350Seric 			map->map_stack[mapno] = &s->s_map;
262368350Seric 			if (tTd(38, 4))
262468350Seric 				printf("\tmap_stack[%d] = %s:%s\n",
262568350Seric 					mapno, s->s_map.map_class->map_cname,
262668350Seric 					nbuf);
262768350Seric 		}
262868350Seric 	}
262968350Seric 	return TRUE;
263068350Seric }
263168350Seric 
263268350Seric 
263368350Seric /*
263468350Seric **  SEQ_MAP_CLOSE -- close all underlying maps
263568350Seric */
263668350Seric 
263768350Seric seq_map_close(map)
263868350Seric 	MAP *map;
263968350Seric {
264068350Seric 	int mapno;
264168350Seric 
264268350Seric 	if (tTd(38, 20))
264368350Seric 		printf("seq_map_close(%s)\n", map->map_mname);
264468350Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
264568350Seric 	{
264668350Seric 		MAP *mm = map->map_stack[mapno];
264768350Seric 
264868350Seric 		if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
264968350Seric 			continue;
265068350Seric 		mm->map_class->map_close(mm);
265168798Seric 		mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
265268350Seric 	}
265368350Seric }
265468350Seric 
265568350Seric 
265668350Seric /*
265768350Seric **  SEQ_MAP_LOOKUP -- sequenced map lookup
265868350Seric */
265968350Seric 
266068350Seric char *
266168350Seric seq_map_lookup(map, key, args, pstat)
266268350Seric 	MAP *map;
266368350Seric 	char *key;
266468350Seric 	char **args;
266568350Seric 	int *pstat;
266668350Seric {
266768350Seric 	int mapno;
266868350Seric 	int mapbit = 0x01;
266968350Seric 
267068350Seric 	if (tTd(38, 20))
267168350Seric 		printf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
267268350Seric 
267368350Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
267468350Seric 	{
267568350Seric 		MAP *mm = map->map_stack[mapno];
267668350Seric 		int stat = 0;
267768350Seric 		char *rv;
267868350Seric 
267968350Seric 		if (mm == NULL)
268068350Seric 			continue;
268168350Seric 		if (!bitset(MF_OPEN, mm->map_mflags))
268268350Seric 		{
268368350Seric 			if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
268468350Seric 			{
268568350Seric 				*pstat = EX_UNAVAILABLE;
268668350Seric 				return NULL;
268768350Seric 			}
268868350Seric 			continue;
268968350Seric 		}
269068350Seric 		rv = mm->map_class->map_lookup(mm, key, args, &stat);
269168350Seric 		if (rv != NULL)
269268350Seric 			return rv;
269368350Seric 		if (stat == 0 && bitset(mapbit, map->map_return[MA_NOTFOUND]))
269468350Seric 			return NULL;
269568350Seric 		if (stat != 0 && bitset(mapbit, map->map_return[MA_TRYAGAIN]))
269668350Seric 		{
269768350Seric 			*pstat = stat;
269868350Seric 			return NULL;
269968350Seric 		}
270068350Seric 	}
270168350Seric 	return NULL;
270268350Seric }
270368350Seric 
270468350Seric 
270568350Seric /*
270668350Seric **  SEQ_MAP_STORE -- sequenced map store
270768350Seric */
270868350Seric 
270968350Seric void
271068350Seric seq_map_store(map, key, val)
271168350Seric 	MAP *map;
271268350Seric 	char *key;
271368350Seric 	char *val;
271468350Seric {
271568350Seric 	int mapno;
271668350Seric 
271768350Seric 	if (tTd(38, 12))
271868350Seric 		printf("seq_map_store(%s, %s, %s)\n",
271968350Seric 			map->map_mname, key, val);
272068350Seric 
272168350Seric 	for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
272268350Seric 	{
272368350Seric 		MAP *mm = map->map_stack[mapno];
272468350Seric 
272568350Seric 		if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
272668350Seric 			continue;
272768350Seric 
272868350Seric 		mm->map_class->map_store(mm, key, val);
272968350Seric 		return;
273068350Seric 	}
273168350Seric 	syserr("seq_map_store(%s, %s, %s): no writable map",
273268350Seric 		map->map_mname, key, val);
273368350Seric }
273468350Seric /*
273569401Seric **  GETCANONNAME -- look up name using service switch
273669401Seric **
273769401Seric **	Parameters:
273869401Seric **		host -- the host name to look up.
273969401Seric **		hbsize -- the size of the host buffer.
274069401Seric **		trymx -- if set, try MX records.
274169401Seric **
274269401Seric **	Returns:
274369401Seric **		TRUE -- if the host was found.
274469401Seric **		FALSE -- otherwise.
274569401Seric */
274669401Seric 
274769401Seric bool
274869401Seric getcanonname(host, hbsize, trymx)
274969401Seric 	char *host;
275069401Seric 	int hbsize;
275169401Seric 	bool trymx;
275269401Seric {
275369401Seric 	int nmaps;
275469401Seric 	int mapno;
275569401Seric 	bool found = FALSE;
275669401Seric 	auto int stat;
275769401Seric 	char *maptype[MAXMAPSTACK];
275869401Seric 	short mapreturn[MAXMAPACTIONS];
275969401Seric 	extern int h_errno;
276069401Seric 
276169401Seric 	nmaps = switch_map_find("hosts", maptype, mapreturn);
276269401Seric 	for (mapno = 0; mapno < nmaps; mapno++)
276369401Seric 	{
276469401Seric 		int i;
276569401Seric 
276669401Seric 		if (tTd(38, 20))
276769401Seric 			printf("getcanonname(%s), trying %s\n",
276869401Seric 				host, maptype[mapno]);
276969401Seric 		if (strcmp("files", maptype[mapno]) == 0)
277069401Seric 			found = text_getcanonname(host, hbsize, &stat);
277169401Seric #ifdef NIS
277269401Seric 		else if (strcmp("nis", maptype[mapno]) == 0)
277369401Seric 			found = nis_getcanonname(host, hbsize, &stat);
277469401Seric #endif
277569401Seric #ifdef NISPLUS
277669401Seric 		else if (strcmp("nisplus", maptype[mapno]) == 0)
277769401Seric 			found = nisplus_getcanonname(host, hbsize, &stat);
277869401Seric #endif
277969401Seric #if NAMED_BIND
278069401Seric 		else if (strcmp("dns", maptype[mapno]) == 0)
278169401Seric 			found = dns_getcanonname(host, hbsize, trymx, &stat);
278269401Seric #endif
278369401Seric 		else
278469401Seric 		{
278569401Seric 			found = FALSE;
278669401Seric 			stat = EX_UNAVAILABLE;
278769401Seric 		}
278869401Seric 		if (found)
278969401Seric 			break;
279069401Seric 
279169401Seric 		/* see if we should continue */
279269401Seric 		if (stat == EX_TEMPFAIL)
279369401Seric 			i = MA_TRYAGAIN;
279469401Seric 		else if (stat == EX_NOHOST)
279569401Seric 			i = MA_NOTFOUND;
279669401Seric 		else
279769401Seric 			i = MA_UNAVAIL;
279869401Seric 		if (bitset(1 << mapno, mapreturn[i]))
279969401Seric 			break;
280069401Seric 	}
280169401Seric 
280269401Seric 	if (found)
280369401Seric 	{
280469401Seric 		char *d;
280569401Seric 
280669401Seric 		if (tTd(38, 20))
280769401Seric 			printf("getcanonname(%s), found\n", host);
280869401Seric 
280969401Seric 		/*
281069401Seric 		**  If returned name is still single token, compensate
281169401Seric 		**  by tagging on $m.  This is because some sites set
281269401Seric 		**  up their DNS or NIS databases wrong.
281369401Seric 		*/
281469401Seric 
281569401Seric 		if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
281669401Seric 		{
281769401Seric 			d = macvalue('m', CurEnv);
281869401Seric 			if (d != NULL &&
281969401Seric 			    hbsize > (int) (strlen(host) + strlen(d) + 1))
282069401Seric 			{
282169401Seric 				if (host[strlen(host) - 1] != '.')
282269401Seric 					strcat(host, ".");
282369401Seric 				strcat(host, d);
282469401Seric 			}
282569401Seric 			else
282669401Seric 			{
282769401Seric 				return FALSE;
282869401Seric 			}
282969401Seric 		}
283069401Seric 		return TRUE;
283169401Seric 	}
283269401Seric 
283369401Seric 	if (tTd(38, 20))
283469401Seric 		printf("getcanonname(%s), failed, stat=%d\n", host, stat);
283569401Seric 
283669401Seric #if NAMED_BIND
283769401Seric 	if (stat == EX_NOHOST)
283869401Seric 		h_errno = HOST_NOT_FOUND;
283969401Seric 	else
284069401Seric 		h_errno = TRY_AGAIN;
284169401Seric #endif
284269401Seric 
284369401Seric 	return FALSE;
284469401Seric }
284569401Seric /*
284660207Seric **  NULL stubs
284760089Seric */
284860089Seric 
284960207Seric bool
285060207Seric null_map_open(map, mode)
285160089Seric 	MAP *map;
285260207Seric 	int mode;
285360089Seric {
285460207Seric 	return TRUE;
285560089Seric }
285660089Seric 
285760207Seric void
285860207Seric null_map_close(map)
285960207Seric 	MAP *map;
286060089Seric {
286160207Seric 	return;
286260207Seric }
286360089Seric 
286460207Seric void
286560207Seric null_map_store(map, key, val)
286660207Seric 	MAP *map;
286760207Seric 	char *key;
286860207Seric 	char *val;
286960089Seric {
287060207Seric 	return;
287160089Seric }
287268350Seric 
287368350Seric 
287468350Seric /*
287568350Seric **  BOGUS stubs
287668350Seric */
287768350Seric 
287868350Seric char *
287968350Seric bogus_map_lookup(map, key, args, pstat)
288068350Seric 	MAP *map;
288168350Seric 	char *key;
288268350Seric 	char **args;
288368350Seric 	int *pstat;
288468350Seric {
288568350Seric 	*pstat = EX_TEMPFAIL;
288668350Seric 	return NULL;
288768350Seric }
288868350Seric 
288968350Seric MAPCLASS	BogusMapClass =
289068350Seric {
289168350Seric 	"bogus-map",		NULL,		0,
289268350Seric 	NULL,		bogus_map_lookup,	null_map_store,
289368350Seric 	null_map_open,	null_map_close,
289468350Seric };
2895