xref: /csrg-svn/usr.sbin/sendmail/src/map.c (revision 63753)
156822Seric /*
256822Seric  * Copyright (c) 1992 Eric P. Allman.
362526Sbostic  * Copyright (c) 1992, 1993
462526Sbostic  *	The Regents of the University of California.  All rights reserved.
556822Seric  *
656822Seric  * %sccs.include.redist.c%
756822Seric  */
856822Seric 
956822Seric #ifndef lint
10*63753Seric static char sccsid[] = "@(#)map.c	8.2 (Berkeley) 07/11/93";
1156822Seric #endif /* not lint */
1256822Seric 
1356822Seric #include "sendmail.h"
1456822Seric 
1560089Seric #ifdef NDBM
1656822Seric #include <ndbm.h>
1756822Seric #endif
1860089Seric #ifdef NEWDB
1956822Seric #include <db.h>
2056822Seric #endif
2160089Seric #ifdef NIS
2257208Seric #include <rpcsvc/ypclnt.h>
2357208Seric #endif
2456822Seric 
2556822Seric /*
2660089Seric **  MAP.C -- implementations for various map classes.
2756822Seric **
2860089Seric **	Each map class implements a series of functions:
2960089Seric **
3060089Seric **	bool map_parse(MAP *map, char *args)
3160089Seric **		Parse the arguments from the config file.  Return TRUE
3260089Seric **		if they were ok, FALSE otherwise.  Fill in map with the
3360089Seric **		values.
3460089Seric **
3560222Seric **	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
3660222Seric **		Look up the key in the given map.  If found, do any
3760222Seric **		rewriting the map wants (including "args" if desired)
3860089Seric **		and return the value.  Set *pstat to the appropriate status
3960222Seric **		on error and return NULL.  Args will be NULL if called
4060222Seric **		from the alias routines, although this should probably
4160222Seric **		not be relied upon.  It is suggested you call map_rewrite
4260222Seric **		to return the results -- it takes care of null termination
4360222Seric **		and uses a dynamically expanded buffer as needed.
4460089Seric **
4560089Seric **	void map_store(MAP *map, char *key, char *value)
4660089Seric **		Store the key:value pair in the map.
4760089Seric **
4860089Seric **	bool map_open(MAP *map, int mode)
4960222Seric **		Open the map for the indicated mode.  Mode should
5060222Seric **		be either O_RDONLY or O_RDWR.  Return TRUE if it
5160222Seric **		was opened successfully, FALSE otherwise.  If the open
5260222Seric **		failed an the MF_OPTIONAL flag is not set, it should
5360222Seric **		also print an error.  If the MF_ALIAS bit is set
5460222Seric **		and this map class understands the @:@ convention, it
5560222Seric **		should call aliaswait() before returning.
5660089Seric **
5760089Seric **	void map_close(MAP *map)
5860089Seric **		Close the map.
5960089Seric */
6060089Seric 
6160089Seric #define DBMMODE		0644
6260089Seric /*
6360089Seric **  MAP_PARSEARGS -- parse config line arguments for database lookup
6460089Seric **
6560089Seric **	This is a generic version of the map_parse method.
6660089Seric **
6756822Seric **	Parameters:
6860089Seric **		map -- the map being initialized.
6960089Seric **		ap -- a pointer to the args on the config line.
7056822Seric **
7156822Seric **	Returns:
7260089Seric **		TRUE -- if everything parsed OK.
7356822Seric **		FALSE -- otherwise.
7456822Seric **
7556822Seric **	Side Effects:
7660089Seric **		null terminates the filename; stores it in map
7756822Seric */
7856822Seric 
7956822Seric bool
8060089Seric map_parseargs(map, ap)
8156822Seric 	MAP *map;
8260089Seric 	char *ap;
8356822Seric {
8460089Seric 	register char *p = ap;
8556822Seric 
86*63753Seric 	map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
8760089Seric 	for (;;)
8860089Seric 	{
8960089Seric 		while (isascii(*p) && isspace(*p))
9060089Seric 			p++;
9160089Seric 		if (*p != '-')
9260089Seric 			break;
9360089Seric 		switch (*++p)
9460089Seric 		{
9560089Seric 		  case 'N':
9660207Seric 			map->map_mflags |= MF_INCLNULL;
97*63753Seric 			map->map_mflags &= ~MF_TRY0NULL;
9860089Seric 			break;
9960089Seric 
100*63753Seric 		  case 'O':
101*63753Seric 			map->map_mflags &= ~MF_TRY1NULL;
102*63753Seric 			break;
103*63753Seric 
10460089Seric 		  case 'o':
10560207Seric 			map->map_mflags |= MF_OPTIONAL;
10660089Seric 			break;
10760089Seric 
10860089Seric 		  case 'f':
10960207Seric 			map->map_mflags |= MF_NOFOLDCASE;
11060089Seric 			break;
11160089Seric 
11260089Seric 		  case 'm':
11360207Seric 			map->map_mflags |= MF_MATCHONLY;
11460089Seric 			break;
11560089Seric 
11660089Seric 		  case 'a':
11760089Seric 			map->map_app = ++p;
11860089Seric 			break;
11960089Seric 		}
12060089Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
12160089Seric 			p++;
12260089Seric 		if (*p != '\0')
12360089Seric 			*p++ = '\0';
12460089Seric 	}
12560089Seric 	if (map->map_app != NULL)
12660089Seric 		map->map_app = newstr(map->map_app);
12760089Seric 
12860089Seric 	if (*p != '\0')
12960089Seric 	{
13060089Seric 		map->map_file = p;
13160089Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
13260089Seric 			p++;
13360089Seric 		if (*p != '\0')
13460089Seric 			*p++ = '\0';
13560089Seric 		map->map_file = newstr(map->map_file);
13660089Seric 	}
13760089Seric 
13860089Seric 	while (*p != '\0' && isascii(*p) && isspace(*p))
13960089Seric 		p++;
14060089Seric 	if (*p != '\0')
14160089Seric 		map->map_rebuild = newstr(p);
14260089Seric 
14356822Seric 	if (map->map_file == NULL)
14457208Seric 	{
14560089Seric 		syserr("No file name for %s map %s",
14660089Seric 			map->map_class->map_cname, map->map_mname);
14756822Seric 		return FALSE;
14857208Seric 	}
14960089Seric 	return TRUE;
15060089Seric }
15160089Seric /*
15260089Seric **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
15360089Seric **
15460089Seric **	It also adds the map_app string.  It can be used as a utility
15560089Seric **	in the map_lookup method.
15660089Seric **
15760089Seric **	Parameters:
15860089Seric **		map -- the map that causes this.
15960089Seric **		s -- the string to rewrite, NOT necessarily null terminated.
16060089Seric **		slen -- the length of s.
16160089Seric **		av -- arguments to interpolate into buf.
16260089Seric **
16360089Seric **	Returns:
16460089Seric **		Pointer to rewritten result.
16560089Seric **
16660089Seric **	Side Effects:
16760089Seric **		none.
16860089Seric */
16960089Seric 
17060492Seric struct rwbuf
17160492Seric {
17260492Seric 	int	rwb_len;	/* size of buffer */
17360492Seric 	char	*rwb_buf;	/* ptr to buffer */
17460492Seric };
17560492Seric 
17660492Seric struct rwbuf	RwBufs[2];	/* buffers for rewriting output */
17760492Seric 
17860089Seric char *
17960089Seric map_rewrite(map, s, slen, av)
18060089Seric 	register MAP *map;
18160089Seric 	register char *s;
18260089Seric 	int slen;
18360089Seric 	char **av;
18460089Seric {
18560089Seric 	register char *bp;
18660089Seric 	register char c;
18760089Seric 	char **avp;
18860089Seric 	register char *ap;
18960492Seric 	register struct rwbuf *rwb;
19060089Seric 	int i;
19160089Seric 	int len;
19260089Seric 
19360537Seric 	if (tTd(39, 1))
19460089Seric 	{
19560256Seric 		printf("map_rewrite(%.*s), av =", slen, s);
19660256Seric 		if (av == NULL)
19760256Seric 			printf(" (nullv)");
19860256Seric 		else
19960256Seric 		{
20060256Seric 			for (avp = av; *avp != NULL; avp++)
20160256Seric 				printf("\n\t%s", *avp);
20260256Seric 		}
20360256Seric 		printf("\n");
20460089Seric 	}
20560089Seric 
20660492Seric 	rwb = RwBufs;
20760492Seric 	if (av == NULL)
20860492Seric 		rwb++;
20960492Seric 
21060089Seric 	/* count expected size of output (can safely overestimate) */
21160089Seric 	i = len = slen;
21260089Seric 	if (av != NULL)
21360089Seric 	{
21460089Seric 		bp = s;
21560089Seric 		for (i = slen; --i >= 0 && (c = *bp++) != 0; )
21660089Seric 		{
21760089Seric 			if (c != '%')
21860089Seric 				continue;
21960089Seric 			if (--i < 0)
22060089Seric 				break;
22160089Seric 			c = *bp++;
22260089Seric 			if (!(isascii(c) && isdigit(c)))
22360089Seric 				continue;
22460089Seric 			c -= 0;
22560089Seric 			for (avp = av; --c >= 0 && *avp != NULL; avp++)
22660089Seric 				continue;
22760089Seric 			if (*avp == NULL)
22860089Seric 				continue;
22960089Seric 			len += strlen(*avp);
23060089Seric 		}
23160089Seric 	}
23260089Seric 	if (map->map_app != NULL)
23360089Seric 		len += strlen(map->map_app);
23460492Seric 	if (rwb->rwb_len < ++len)
23560089Seric 	{
23660089Seric 		/* need to malloc additional space */
23760492Seric 		rwb->rwb_len = len;
23860492Seric 		if (rwb->rwb_buf != NULL)
23960492Seric 			free(rwb->rwb_buf);
24060492Seric 		rwb->rwb_buf = xalloc(rwb->rwb_len);
24160089Seric 	}
24260089Seric 
24360492Seric 	bp = rwb->rwb_buf;
24460089Seric 	if (av == NULL)
24560089Seric 	{
24660089Seric 		bcopy(s, bp, slen);
24760089Seric 		bp += slen;
24860089Seric 	}
24960089Seric 	else
25060089Seric 	{
25160089Seric 		while (--slen >= 0 && (c = *s++) != '\0')
25260089Seric 		{
25360089Seric 			if (c != '%')
25460089Seric 			{
25560089Seric   pushc:
25660089Seric 				*bp++ = c;
25760089Seric 				continue;
25860089Seric 			}
25960089Seric 			if (--slen < 0 || (c = *s++) == '\0')
26060089Seric 				c = '%';
26160089Seric 			if (c == '%')
26260089Seric 				goto pushc;
26360089Seric 			if (!(isascii(c) && isdigit(c)))
26460089Seric 			{
26560089Seric 				*bp++ = '%';
26660089Seric 				goto pushc;
26760089Seric 			}
26860089Seric 			c -= '0';
26960089Seric 			for (avp = av; --c >= 0 && *avp != NULL; avp++)
27060089Seric 				continue;
27160089Seric 			if (*avp == NULL)
27260089Seric 				continue;
27360089Seric 
27460089Seric 			/* transliterate argument into output string */
27560089Seric 			for (ap = *avp; (c = *ap++) != '\0'; )
27660089Seric 				*bp++ = c;
27760089Seric 		}
27860089Seric 	}
27960089Seric 	if (map->map_app != NULL)
28060089Seric 		strcpy(bp, map->map_app);
28160089Seric 	else
28260089Seric 		*bp = '\0';
28360537Seric 	if (tTd(39, 1))
28460492Seric 		printf("map_rewrite => %s\n", rwb->rwb_buf);
28560492Seric 	return rwb->rwb_buf;
28660089Seric }
28760089Seric /*
28860537Seric **  INITMAPS -- initialize for aliasing
28960537Seric **
29060537Seric **	Parameters:
29160537Seric **		rebuild -- if TRUE, this rebuilds the cached versions.
29260537Seric **		e -- current envelope.
29360537Seric **
29460537Seric **	Returns:
29560537Seric **		none.
29660537Seric **
29760537Seric **	Side Effects:
29860537Seric **		initializes aliases:
29960537Seric **		if NDBM:  opens the database.
30060537Seric **		if ~NDBM: reads the aliases into the symbol table.
30160537Seric */
30260537Seric 
30360537Seric initmaps(rebuild, e)
30460537Seric 	bool rebuild;
30560537Seric 	register ENVELOPE *e;
30660537Seric {
30760537Seric 	extern void map_init();
30860537Seric 
30960537Seric 	CurEnv = e;
31060537Seric 	stabapply(map_init, rebuild);
31160537Seric }
31260537Seric 
31360537Seric void
31460537Seric map_init(s, rebuild)
31560537Seric 	register STAB *s;
31660537Seric 	int rebuild;
31760537Seric {
31860537Seric 	register MAP *map;
31960537Seric 
32060537Seric 	/* has to be a map */
32160537Seric 	if (s->s_type != ST_MAP)
32260537Seric 		return;
32360537Seric 
32460537Seric 	map = &s->s_map;
32560537Seric 	if (!bitset(MF_VALID, map->map_mflags))
32660537Seric 		return;
32760537Seric 
32860537Seric 	if (tTd(38, 2))
32960537Seric 		printf("map_init(%s:%s)\n",
33060537Seric 			map->map_class->map_cname, map->map_file);
33160537Seric 
33260537Seric 	/* if already open, close it (for nested open) */
33360537Seric 	if (bitset(MF_OPEN, map->map_mflags))
33460537Seric 	{
33560537Seric 		map->map_class->map_close(map);
33660537Seric 		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
33760537Seric 	}
33860537Seric 
33960537Seric 	if (rebuild)
34060537Seric 	{
34160926Seric 		if (bitset(MF_ALIAS, map->map_mflags) &&
34260926Seric 		    bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
34360537Seric 			rebuildaliases(map, FALSE);
34460537Seric 	}
34560537Seric 	else
34660537Seric 	{
34760537Seric 		if (map->map_class->map_open(map, O_RDONLY))
34860537Seric 		{
34960537Seric 			if (tTd(38, 4))
35060537Seric 				printf("%s:%s: valid\n",
35160537Seric 					map->map_class->map_cname,
35260537Seric 					map->map_file);
35360537Seric 			map->map_mflags |= MF_OPEN;
35460537Seric 		}
35560537Seric 		else if (tTd(38, 4))
35660537Seric 			printf("%s:%s: invalid: %s\n",
35760537Seric 				map->map_class->map_cname,
35860537Seric 				map->map_file,
35960537Seric 				errstring(errno));
36060537Seric 	}
36160537Seric }
36260537Seric /*
36360089Seric **  NDBM modules
36460089Seric */
36560089Seric 
36660089Seric #ifdef NDBM
36760089Seric 
36860089Seric /*
36960089Seric **  DBM_MAP_OPEN -- DBM-style map open
37060089Seric */
37160089Seric 
37260089Seric bool
37360089Seric ndbm_map_open(map, mode)
37460089Seric 	MAP *map;
37560089Seric 	int mode;
37660089Seric {
37760089Seric 	DBM *dbm;
37860089Seric 
37960537Seric 	if (tTd(38, 2))
38060089Seric 		printf("ndbm_map_open(%s, %d)\n", map->map_file, mode);
38160089Seric 
38260207Seric 	if (mode == O_RDWR)
38360207Seric 		mode |= O_CREAT|O_TRUNC;
38460207Seric 
38560089Seric 	/* open the database */
38660089Seric 	dbm = dbm_open(map->map_file, mode, DBMMODE);
38756822Seric 	if (dbm == NULL)
38856822Seric 	{
38960207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
39056836Seric 			syserr("Cannot open DBM database %s", map->map_file);
39156822Seric 		return FALSE;
39256822Seric 	}
39360089Seric 	map->map_db1 = (void *) dbm;
39460207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
39560604Seric 		aliaswait(map, ".pag");
39656822Seric 	return TRUE;
39756822Seric }
39860089Seric 
39960089Seric 
40060089Seric /*
40156822Seric **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
40256822Seric */
40356822Seric 
40456822Seric char *
40560089Seric ndbm_map_lookup(map, name, av, statp)
40656822Seric 	MAP *map;
40760089Seric 	char *name;
40856822Seric 	char **av;
40959084Seric 	int *statp;
41056822Seric {
41156822Seric 	datum key, val;
41260089Seric 	char keybuf[MAXNAME + 1];
41356822Seric 
41460537Seric 	if (tTd(38, 20))
41560089Seric 		printf("ndbm_map_lookup(%s)\n", name);
41660089Seric 
41760089Seric 	key.dptr = name;
41860089Seric 	key.dsize = strlen(name);
41960207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
42057014Seric 	{
42160089Seric 		if (key.dsize > sizeof keybuf - 1)
42260089Seric 			key.dsize = sizeof keybuf - 1;
42360089Seric 		bcopy(key.dptr, keybuf, key.dsize + 1);
42460089Seric 		makelower(keybuf);
42560089Seric 		key.dptr = keybuf;
42657014Seric 	}
427*63753Seric 	(void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file, LOCK_SH);
428*63753Seric 	val.dptr = NULL;
429*63753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
430*63753Seric 	{
431*63753Seric 		val = dbm_fetch((DBM *) map->map_db1, key);
432*63753Seric 		if (val.dptr != NULL)
433*63753Seric 			map->map_mflags &= ~MF_TRY1NULL;
434*63753Seric 	}
435*63753Seric 	if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
436*63753Seric 	{
43756822Seric 		key.dsize++;
438*63753Seric 		val = dbm_fetch((DBM *) map->map_db1, key);
439*63753Seric 		if (val.dptr != NULL)
440*63753Seric 			map->map_mflags &= ~MF_TRY0NULL;
441*63753Seric 	}
44260089Seric 	(void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file, LOCK_UN);
44356822Seric 	if (val.dptr == NULL)
44456822Seric 		return NULL;
44560207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
446*63753Seric 		return map_rewrite(map, name, strlen(name), NULL);
447*63753Seric 	else
448*63753Seric 		return map_rewrite(map, val.dptr, val.dsize, av);
44956822Seric }
45056822Seric 
45156822Seric 
45256822Seric /*
45360089Seric **  DBM_MAP_STORE -- store a datum in the database
45456822Seric */
45556822Seric 
45660089Seric void
45760089Seric ndbm_map_store(map, lhs, rhs)
45860089Seric 	register MAP *map;
45960089Seric 	char *lhs;
46060089Seric 	char *rhs;
46160089Seric {
46260089Seric 	datum key;
46360089Seric 	datum data;
46460089Seric 	int stat;
46560089Seric 
46660537Seric 	if (tTd(38, 12))
46760089Seric 		printf("ndbm_map_store(%s, %s)\n", lhs, rhs);
46860089Seric 
46960089Seric 	key.dsize = strlen(lhs);
47060089Seric 	key.dptr = lhs;
47160089Seric 
47260089Seric 	data.dsize = strlen(rhs);
47360089Seric 	data.dptr = rhs;
47460089Seric 
47560207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
47660089Seric 	{
47760089Seric 		key.dsize++;
47860089Seric 		data.dsize++;
47960089Seric 	}
48060089Seric 
48160089Seric 	stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
48260089Seric 	if (stat > 0)
48360089Seric 	{
48460089Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
48560089Seric 		stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
48660089Seric 	}
48760089Seric 	if (stat != 0)
48860089Seric 		syserr("readaliases: dbm put (%s)", lhs);
48960089Seric }
49060089Seric 
49160089Seric 
49260089Seric /*
49360207Seric **  NDBM_MAP_CLOSE -- close the database
49460089Seric */
49560089Seric 
49660089Seric void
49760089Seric ndbm_map_close(map)
49860089Seric 	register MAP  *map;
49960089Seric {
50060207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
50160089Seric 	{
50260089Seric #ifdef YPCOMPAT
50360089Seric 		char buf[200];
50460089Seric 
50560089Seric 		(void) sprintf(buf, "%010ld", curtime());
50660089Seric 		ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
50760089Seric 
50860089Seric 		(void) myhostname(buf, sizeof buf);
50960089Seric 		ndbm_map_store(map, "YP_MASTER_NAME", buf);
51060089Seric #endif
51160089Seric 
51260089Seric 		/* write out the distinguished alias */
51360089Seric 		ndbm_map_store(map, "@", "@");
51460089Seric 	}
51560089Seric 	dbm_close((DBM *) map->map_db1);
51660089Seric }
51760089Seric 
51860089Seric #endif
51960089Seric /*
52060582Seric **  NEWDB (Hash and BTree) Modules
52160089Seric */
52260089Seric 
52360089Seric #ifdef NEWDB
52460089Seric 
52560089Seric /*
52660582Seric **  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
52760582Seric **
52860582Seric **	These do rather bizarre locking.  If you can lock on open,
52960582Seric **	do that to avoid the condition of opening a database that
53060582Seric **	is being rebuilt.  If you don't, we'll try to fake it, but
53160582Seric **	there will be a race condition.  If opening for read-only,
53260582Seric **	we immediately release the lock to avoid freezing things up.
53360582Seric **	We really ought to hold the lock, but guarantee that we won't
53460582Seric **	be pokey about it.  That's hard to do.
53560089Seric */
53660089Seric 
53756822Seric bool
53860089Seric bt_map_open(map, mode)
53956822Seric 	MAP *map;
54060089Seric 	int mode;
54156822Seric {
54256822Seric 	DB *db;
54360228Seric 	int i;
54460582Seric 	int omode;
54560089Seric 	char buf[MAXNAME];
54656822Seric 
54760537Seric 	if (tTd(38, 2))
54860089Seric 		printf("bt_map_open(%s, %d)\n", map->map_file, mode);
54960089Seric 
55060582Seric 	omode = mode;
55160582Seric 	if (omode == O_RDWR)
55260582Seric 	{
55360582Seric 		omode |= O_CREAT|O_TRUNC;
55460582Seric #if defined(O_EXLOCK) && !defined(LOCKF)
55560582Seric 		omode |= O_EXLOCK;
55660582Seric # if !defined(OLD_NEWDB)
55760582Seric 	}
55860582Seric 	else
55960582Seric 	{
56060582Seric 		omode |= O_SHLOCK;
56160582Seric # endif
56260582Seric #endif
56360582Seric 	}
56460207Seric 
56560228Seric 	(void) strcpy(buf, map->map_file);
56660228Seric 	i = strlen(buf);
56760228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
56860228Seric 		(void) strcat(buf, ".db");
56960582Seric 	db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
57056822Seric 	if (db == NULL)
57156822Seric 	{
57260207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
57356836Seric 			syserr("Cannot open BTREE database %s", map->map_file);
57456822Seric 		return FALSE;
57556822Seric 	}
57660582Seric #if !defined(OLD_NEWDB) && !defined(LOCKF)
57760582Seric # if !defined(O_EXLOCK)
57860582Seric 	if (mode == O_RDWR)
57960582Seric 		(void) lockfile(db->fd(db), map->map_file, LOCK_EX);
58060582Seric # else
58160582Seric 	if (mode == O_RDONLY)
58260582Seric 		(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
58360582Seric # endif
58460582Seric #endif
58560585Seric 
58660585Seric 	/* try to make sure that at least the database header is on disk */
58760585Seric 	if (mode == O_RDWR)
58860585Seric 		(void) db->sync(db, 0);
58960585Seric 
59060089Seric 	map->map_db2 = (void *) db;
59160207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
59260207Seric 		aliaswait(map, ".db");
59356822Seric 	return TRUE;
59456822Seric }
59556822Seric 
59656822Seric 
59756822Seric /*
59856822Seric **  HASH_MAP_INIT -- HASH-style map initialization
59956822Seric */
60056822Seric 
60156822Seric bool
60260089Seric hash_map_open(map, mode)
60356822Seric 	MAP *map;
60460089Seric 	int mode;
60556822Seric {
60656822Seric 	DB *db;
60760228Seric 	int i;
60860582Seric 	int omode;
60960089Seric 	char buf[MAXNAME];
61056822Seric 
61160537Seric 	if (tTd(38, 2))
61260089Seric 		printf("hash_map_open(%s, %d)\n", map->map_file, mode);
61360089Seric 
61460582Seric 	omode = mode;
61560582Seric 	if (omode == O_RDWR)
61660582Seric 	{
61760582Seric 		omode |= O_CREAT|O_TRUNC;
61860582Seric #if defined(O_EXLOCK) && !defined(LOCKF)
61960582Seric 		omode |= O_EXLOCK;
62060582Seric # if !defined(OLD_NEWDB)
62160582Seric 	}
62260582Seric 	else
62360582Seric 	{
62460582Seric 		omode |= O_SHLOCK;
62560582Seric # endif
62660582Seric #endif
62760582Seric 	}
62860207Seric 
62960228Seric 	(void) strcpy(buf, map->map_file);
63060228Seric 	i = strlen(buf);
63160228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
63260228Seric 		(void) strcat(buf, ".db");
63360582Seric 	db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
63456822Seric 	if (db == NULL)
63556822Seric 	{
63660207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
63756836Seric 			syserr("Cannot open HASH database %s", map->map_file);
63856822Seric 		return FALSE;
63956822Seric 	}
64060582Seric #if !defined(OLD_NEWDB) && !defined(LOCKF)
64160582Seric # if !defined(O_EXLOCK)
64260582Seric 	if (mode == O_RDWR)
64360582Seric 		(void) lockfile(db->fd(db), map->map_file, LOCK_EX);
64460582Seric # else
64560582Seric 	if (mode == O_RDONLY)
64660582Seric 		(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
64760582Seric # endif
64860582Seric #endif
64960585Seric 
65060585Seric 	/* try to make sure that at least the database header is on disk */
65160585Seric 	if (mode == O_RDWR)
65260585Seric 		(void) db->sync(db, 0);
65360585Seric 
65460089Seric 	map->map_db2 = (void *) db;
65560207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
65660207Seric 		aliaswait(map, ".db");
65756822Seric 	return TRUE;
65856822Seric }
65956822Seric 
66056822Seric 
66156822Seric /*
66256822Seric **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
66356822Seric */
66456822Seric 
66556822Seric char *
66660089Seric db_map_lookup(map, name, av, statp)
66756822Seric 	MAP *map;
66860089Seric 	char *name;
66956822Seric 	char **av;
67059084Seric 	int *statp;
67156822Seric {
67256822Seric 	DBT key, val;
67360422Seric 	register DB *db = (DB *) map->map_db2;
67460422Seric 	int st;
67560422Seric 	int saveerrno;
67660089Seric 	char keybuf[MAXNAME + 1];
67756822Seric 
67860537Seric 	if (tTd(38, 20))
67960089Seric 		printf("db_map_lookup(%s)\n", name);
68060089Seric 
68160089Seric 	key.size = strlen(name);
68260089Seric 	if (key.size > sizeof keybuf - 1)
68360089Seric 		key.size = sizeof keybuf - 1;
68460089Seric 	key.data = keybuf;
68560089Seric 	bcopy(name, keybuf, key.size + 1);
68660207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
68760089Seric 		makelower(keybuf);
68860422Seric #ifndef OLD_NEWDB
68960422Seric 	(void) lockfile(db->fd(db), map->map_file, LOCK_SH);
69060422Seric #endif
691*63753Seric 	st = 1;
692*63753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
693*63753Seric 	{
694*63753Seric 		st = db->get(db, &key, &val, 0);
695*63753Seric 		if (st == 0)
696*63753Seric 			map->map_mflags &= ~MF_TRY1NULL;
697*63753Seric 	}
698*63753Seric 	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
699*63753Seric 	{
700*63753Seric 		key.size++;
701*63753Seric 		st = db->get(db, &key, &val, 0);
702*63753Seric 		if (st == 0)
703*63753Seric 			map->map_mflags &= ~MF_TRY0NULL;
704*63753Seric 	}
70560422Seric 	saveerrno = errno;
70660422Seric #ifndef OLD_NEWDB
70760422Seric 	(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
70860422Seric #endif
70960422Seric 	if (st != 0)
71060422Seric 	{
71160422Seric 		errno = saveerrno;
71260422Seric 		if (st < 0)
71360422Seric 			syserr("db_map_lookup: get (%s)", name);
71456822Seric 		return NULL;
71560422Seric 	}
71660207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
717*63753Seric 		return map_rewrite(map, name, strlen(name), NULL);
718*63753Seric 	else
719*63753Seric 		return map_rewrite(map, val.data, val.size, av);
72056822Seric }
72156822Seric 
72260089Seric 
72360089Seric /*
72460089Seric **  DB_MAP_STORE -- store a datum in the NEWDB database
72556822Seric */
72656822Seric 
72760089Seric void
72860089Seric db_map_store(map, lhs, rhs)
72960089Seric 	register MAP *map;
73060089Seric 	char *lhs;
73160089Seric 	char *rhs;
73256822Seric {
73360089Seric 	int stat;
73460089Seric 	DBT key;
73560089Seric 	DBT data;
73660089Seric 	register DB *db = map->map_db2;
73756822Seric 
73860537Seric 	if (tTd(38, 20))
73960089Seric 		printf("db_map_store(%s, %s)\n", lhs, rhs);
74060089Seric 
74160089Seric 	key.size = strlen(lhs);
74260089Seric 	key.data = lhs;
74360089Seric 
74460089Seric 	data.size = strlen(rhs);
74560089Seric 	data.data = rhs;
74660089Seric 
74760207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
74856822Seric 	{
74960089Seric 		key.size++;
75060089Seric 		data.size++;
75160089Seric 	}
75256836Seric 
75360089Seric 	stat = db->put(db, &key, &data, R_NOOVERWRITE);
75460089Seric 	if (stat > 0)
75560089Seric 	{
75660089Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
75760089Seric 		stat = db->put(db, &key, &data, 0);
75860089Seric 	}
75960089Seric 	if (stat != 0)
76060089Seric 		syserr("readaliases: db put (%s)", lhs);
76160089Seric }
76256836Seric 
76356847Seric 
76460089Seric /*
76560089Seric **  DB_MAP_CLOSE -- add distinguished entries and close the database
76660089Seric */
76760089Seric 
76860089Seric void
76960089Seric db_map_close(map)
77060089Seric 	MAP *map;
77160089Seric {
77260089Seric 	register DB *db = map->map_db2;
77360089Seric 
77460537Seric 	if (tTd(38, 9))
77560207Seric 		printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags);
77660089Seric 
77760207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
77858804Seric 	{
77960089Seric 		/* write out the distinguished alias */
78060089Seric 		db_map_store(map, "@", "@");
78158804Seric 	}
78258963Seric 
78360089Seric 	if (db->close(db) != 0)
78460089Seric 		syserr("readaliases: db close failure");
78556822Seric }
78657208Seric 
78760089Seric #endif
78860089Seric /*
78960089Seric **  NIS Modules
79060089Seric */
79160089Seric 
79260089Seric # ifdef NIS
79360089Seric 
79457208Seric /*
79560089Seric **  NIS_MAP_OPEN -- open DBM map
79657208Seric */
79757208Seric 
79857208Seric bool
79960089Seric nis_map_open(map, mode)
80057208Seric 	MAP *map;
80160089Seric 	int mode;
80257208Seric {
80357216Seric 	int yperr;
80460215Seric 	register char *p;
80560215Seric 	auto char *vp;
80660215Seric 	auto int vsize;
80757216Seric 	char *master;
80857216Seric 
80960537Seric 	if (tTd(38, 2))
81060089Seric 		printf("nis_map_open(%s)\n", map->map_file);
81160089Seric 
81260207Seric 	if (mode != O_RDONLY)
81360207Seric 	{
81460207Seric 		errno = ENODEV;
81560207Seric 		return FALSE;
81660207Seric 	}
81760207Seric 
81860089Seric 	p = strchr(map->map_file, '@');
81960089Seric 	if (p != NULL)
82060089Seric 	{
82160089Seric 		*p++ = '\0';
82260089Seric 		if (*p != '\0')
82360089Seric 			map->map_domain = p;
82460089Seric 	}
82560215Seric 
82660089Seric 	if (map->map_domain == NULL)
82760089Seric 		yp_get_default_domain(&map->map_domain);
82860089Seric 
82960089Seric 	if (*map->map_file == '\0')
83060089Seric 		map->map_file = "mail.aliases";
83160089Seric 
83260215Seric 	/* check to see if this map actually exists */
83360089Seric 	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
83460089Seric 			&vp, &vsize);
83560537Seric 	if (tTd(38, 10))
83660089Seric 		printf("nis_map_open: yp_match(%s, %s) => %s\n",
83760089Seric 			map->map_domain, map->map_file, yperr_string(yperr));
83860089Seric 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
83960089Seric 		return TRUE;
84060215Seric 
84160215Seric 	if (!bitset(MF_OPTIONAL, map->map_mflags))
84260215Seric 		syserr("Cannot bind to domain %s: %s", map->map_domain,
84360215Seric 			yperr_string(yperr));
84460215Seric 
84560089Seric 	return FALSE;
84660089Seric }
84760089Seric 
84860089Seric 
84960089Seric /*
85057208Seric **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
85157208Seric */
85257208Seric 
85357208Seric char *
85460089Seric nis_map_lookup(map, name, av, statp)
85557208Seric 	MAP *map;
85660089Seric 	char *name;
85757208Seric 	char **av;
85859084Seric 	int *statp;
85957208Seric {
86057208Seric 	char *vp;
86157642Seric 	auto int vsize;
86259274Seric 	int buflen;
86360215Seric 	int yperr;
86460089Seric 	char keybuf[MAXNAME + 1];
86557208Seric 
86660537Seric 	if (tTd(38, 20))
86760089Seric 		printf("nis_map_lookup(%s)\n", name);
86860089Seric 
86960089Seric 	buflen = strlen(name);
87060089Seric 	if (buflen > sizeof keybuf - 1)
87160089Seric 		buflen = sizeof keybuf - 1;
87260089Seric 	bcopy(name, keybuf, buflen + 1);
87360207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
87460089Seric 		makelower(keybuf);
875*63753Seric 	yperr = YPERR_KEY;
876*63753Seric 	if (bitset(MF_TRY0NULL, map->map_mflags))
877*63753Seric 	{
878*63753Seric 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
879*63753Seric 			     &vp, &vsize);
880*63753Seric 		if (yperr == 0)
881*63753Seric 			map->map_mflags &= ~MF_TRY1NULL;
882*63753Seric 	}
883*63753Seric 	if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
884*63753Seric 	{
88559274Seric 		buflen++;
886*63753Seric 		yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
887*63753Seric 			     &vp, &vsize);
888*63753Seric 		if (yperr == 0)
889*63753Seric 			map->map_mflags &= ~MF_TRY0NULL;
890*63753Seric 	}
89160089Seric 	if (yperr != 0)
89260089Seric 	{
89360089Seric 		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
89460215Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
89557208Seric 		return NULL;
89660089Seric 	}
89760207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
898*63753Seric 		return map_rewrite(map, name, strlen(name), NULL);
899*63753Seric 	else
900*63753Seric 		return map_rewrite(map, vp, vsize, av);
90157208Seric }
90257208Seric 
90360089Seric 
90460089Seric /*
90560207Seric **  NIS_MAP_STORE
90660089Seric */
90760089Seric 
90860089Seric void
90960089Seric nis_map_store(map, lhs, rhs)
91060089Seric 	MAP *map;
91160089Seric 	char *lhs;
91260089Seric 	char *rhs;
91360089Seric {
91460089Seric 	/* nothing */
91560089Seric }
91660089Seric 
91760089Seric 
91860089Seric /*
91960207Seric **  NIS_MAP_CLOSE
92060089Seric */
92160089Seric 
92260089Seric void
92360089Seric nis_map_close(map)
92460089Seric 	MAP *map;
92560089Seric {
92660089Seric 	/* nothing */
92760089Seric }
92860089Seric 
92960089Seric #endif /* NIS */
93057208Seric /*
93160089Seric **  STAB (Symbol Table) Modules
93260089Seric */
93360089Seric 
93460089Seric 
93560089Seric /*
93660207Seric **  STAB_MAP_LOOKUP -- look up alias in symbol table
93760089Seric */
93860089Seric 
93960089Seric char *
94061707Seric stab_map_lookup(map, name, av, pstat)
94160089Seric 	register MAP *map;
94260089Seric 	char *name;
94361707Seric 	char **av;
94461707Seric 	int *pstat;
94560089Seric {
94660089Seric 	register STAB *s;
94760089Seric 
94860537Seric 	if (tTd(38, 20))
94960089Seric 		printf("stab_lookup(%s)\n", name);
95060089Seric 
95160089Seric 	s = stab(name, ST_ALIAS, ST_FIND);
95260089Seric 	if (s != NULL)
95360089Seric 		return (s->s_alias);
95460089Seric 	return (NULL);
95560089Seric }
95660089Seric 
95760089Seric 
95860089Seric /*
95960207Seric **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
96060089Seric */
96160089Seric 
96260089Seric void
96360089Seric stab_map_store(map, lhs, rhs)
96460089Seric 	register MAP *map;
96560089Seric 	char *lhs;
96660089Seric 	char *rhs;
96760089Seric {
96860089Seric 	register STAB *s;
96960089Seric 
97060089Seric 	s = stab(lhs, ST_ALIAS, ST_ENTER);
97160089Seric 	s->s_alias = newstr(rhs);
97260089Seric }
97360089Seric 
97460089Seric 
97560089Seric /*
97660207Seric **  STAB_MAP_OPEN -- initialize (reads data file)
97760207Seric **
97860207Seric **	This is a wierd case -- it is only intended as a fallback for
97960207Seric **	aliases.  For this reason, opens for write (only during a
98060207Seric **	"newaliases") always fails, and opens for read open the
98160207Seric **	actual underlying text file instead of the database.
98260089Seric */
98360089Seric 
98460089Seric bool
98560089Seric stab_map_open(map, mode)
98660089Seric 	register MAP *map;
98760089Seric 	int mode;
98860089Seric {
98960537Seric 	if (tTd(38, 2))
99060089Seric 		printf("stab_map_open(%s)\n", map->map_file);
99160089Seric 
99260089Seric 	if (mode != O_RDONLY)
99360207Seric 	{
99460207Seric 		errno = ENODEV;
99560089Seric 		return FALSE;
99660207Seric 	}
99760089Seric 
99860089Seric 	return TRUE;
99960089Seric }
100060089Seric 
100160089Seric 
100260089Seric /*
100360207Seric **  STAB_MAP_CLOSE -- close symbol table (???)
100460089Seric */
100560089Seric 
100660089Seric void
100760089Seric stab_map_close(map)
100860089Seric 	MAP *map;
100960089Seric {
101060089Seric 	/* ignore it */
101160089Seric }
101260089Seric /*
101360089Seric **  Implicit Modules
101456822Seric **
101560089Seric **	Tries several types.  For back compatibility of aliases.
101656822Seric */
101756822Seric 
101860089Seric 
101960089Seric /*
102060207Seric **  IMPL_MAP_LOOKUP -- lookup in best open database
102160089Seric */
102260089Seric 
102360089Seric char *
102460089Seric impl_map_lookup(map, name, av, pstat)
102560089Seric 	MAP *map;
102660089Seric 	char *name;
102756822Seric 	char **av;
102860089Seric 	int *pstat;
102956822Seric {
103060537Seric 	if (tTd(38, 20))
103160089Seric 		printf("impl_map_lookup(%s)\n", name);
103256822Seric 
103360089Seric #ifdef NEWDB
103460207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
103560089Seric 		return db_map_lookup(map, name, av, pstat);
103660089Seric #endif
103760089Seric #ifdef NDBM
103860207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
103960089Seric 		return ndbm_map_lookup(map, name, av, pstat);
104060089Seric #endif
104160089Seric 	return stab_map_lookup(map, name, av, pstat);
104260089Seric }
104360089Seric 
104460089Seric /*
104560207Seric **  IMPL_MAP_STORE -- store in open databases
104660089Seric */
104760089Seric 
104860089Seric void
104960089Seric impl_map_store(map, lhs, rhs)
105060089Seric 	MAP *map;
105160089Seric 	char *lhs;
105260089Seric 	char *rhs;
105360089Seric {
105460089Seric #ifdef NEWDB
105560207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
105660089Seric 		db_map_store(map, lhs, rhs);
105760089Seric #endif
105860089Seric #ifdef NDBM
105960207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
106060089Seric 		ndbm_map_store(map, lhs, rhs);
106160089Seric #endif
106260089Seric 	stab_map_store(map, lhs, rhs);
106360089Seric }
106460089Seric 
106560089Seric /*
106660089Seric **  IMPL_MAP_OPEN -- implicit database open
106760089Seric */
106860089Seric 
106960089Seric bool
107060089Seric impl_map_open(map, mode)
107160089Seric 	MAP *map;
107260089Seric 	int mode;
107360089Seric {
107460089Seric 	struct stat stb;
107560089Seric 
107660537Seric 	if (tTd(38, 2))
107760089Seric 		printf("impl_map_open(%s)\n", map->map_file);
107860089Seric 
107960089Seric 	if (stat(map->map_file, &stb) < 0)
108056822Seric 	{
108160089Seric 		/* no alias file at all */
108260089Seric 		return FALSE;
108356822Seric 	}
108456822Seric 
108560089Seric #ifdef NEWDB
108660207Seric 	map->map_mflags |= MF_IMPL_HASH;
108760089Seric 	if (hash_map_open(map, mode))
108856822Seric 	{
108960207Seric #if defined(NDBM) && defined(YPCOMPAT)
109060561Seric 		if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0)
109160207Seric #endif
109260207Seric 			return TRUE;
109360089Seric 	}
109460207Seric 	else
109560207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
109660089Seric #endif
109760089Seric #ifdef NDBM
109860207Seric 	map->map_mflags |= MF_IMPL_NDBM;
109960089Seric 	if (ndbm_map_open(map, mode))
110060089Seric 	{
110160089Seric 		return TRUE;
110260089Seric 	}
110360207Seric 	else
110460207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
110560089Seric #endif
110656822Seric 
110760207Seric #if !defined(NEWDB) && !defined(NDBM)
110860089Seric 	if (Verbose)
110960089Seric 		message("WARNING: cannot open alias database %s", map->map_file);
111060207Seric #endif
111160089Seric 
111260207Seric 	return stab_map_open(map, mode);
111356822Seric }
111460089Seric 
111560207Seric 
111660089Seric /*
111760207Seric **  IMPL_MAP_CLOSE -- close any open database(s)
111860089Seric */
111960089Seric 
112060089Seric void
112160207Seric impl_map_close(map)
112260089Seric 	MAP *map;
112360089Seric {
112460089Seric #ifdef NEWDB
112560207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
112660089Seric 	{
112760207Seric 		db_map_close(map);
112860207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
112960089Seric 	}
113060089Seric #endif
113160089Seric 
113260089Seric #ifdef NDBM
113360207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
113460089Seric 	{
113560207Seric 		ndbm_map_close(map);
113660207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
113760089Seric 	}
113860089Seric #endif
113960089Seric }
114060207Seric /*
114160207Seric **  NULL stubs
114260089Seric */
114360089Seric 
114460207Seric bool
114560207Seric null_map_open(map, mode)
114660089Seric 	MAP *map;
114760207Seric 	int mode;
114860089Seric {
114960207Seric 	return TRUE;
115060089Seric }
115160089Seric 
115260207Seric void
115360207Seric null_map_close(map)
115460207Seric 	MAP *map;
115560089Seric {
115660207Seric 	return;
115760207Seric }
115860089Seric 
115960207Seric void
116060207Seric null_map_store(map, key, val)
116160207Seric 	MAP *map;
116260207Seric 	char *key;
116360207Seric 	char *val;
116460089Seric {
116560207Seric 	return;
116660089Seric }
1167