xref: /csrg-svn/usr.sbin/sendmail/src/map.c (revision 61707)
156822Seric /*
256822Seric  * Copyright (c) 1992 Eric P. Allman.
356822Seric  * Copyright (c) 1992 Regents of the University of California.
456822Seric  * All rights reserved.
556822Seric  *
656822Seric  * %sccs.include.redist.c%
756822Seric  */
856822Seric 
956822Seric #ifndef lint
10*61707Seric static char sccsid[] = "@(#)map.c	6.28 (Berkeley) 06/05/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 
8660089Seric 	for (;;)
8760089Seric 	{
8860089Seric 		while (isascii(*p) && isspace(*p))
8960089Seric 			p++;
9060089Seric 		if (*p != '-')
9160089Seric 			break;
9260089Seric 		switch (*++p)
9360089Seric 		{
9460089Seric 		  case 'N':
9560207Seric 			map->map_mflags |= MF_INCLNULL;
9660089Seric 			break;
9760089Seric 
9860089Seric 		  case 'o':
9960207Seric 			map->map_mflags |= MF_OPTIONAL;
10060089Seric 			break;
10160089Seric 
10260089Seric 		  case 'f':
10360207Seric 			map->map_mflags |= MF_NOFOLDCASE;
10460089Seric 			break;
10560089Seric 
10660089Seric 		  case 'm':
10760207Seric 			map->map_mflags |= MF_MATCHONLY;
10860089Seric 			break;
10960089Seric 
11060089Seric 		  case 'a':
11160089Seric 			map->map_app = ++p;
11260089Seric 			break;
11360089Seric 		}
11460089Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
11560089Seric 			p++;
11660089Seric 		if (*p != '\0')
11760089Seric 			*p++ = '\0';
11860089Seric 	}
11960089Seric 	if (map->map_app != NULL)
12060089Seric 		map->map_app = newstr(map->map_app);
12160089Seric 
12260089Seric 	if (*p != '\0')
12360089Seric 	{
12460089Seric 		map->map_file = p;
12560089Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
12660089Seric 			p++;
12760089Seric 		if (*p != '\0')
12860089Seric 			*p++ = '\0';
12960089Seric 		map->map_file = newstr(map->map_file);
13060089Seric 	}
13160089Seric 
13260089Seric 	while (*p != '\0' && isascii(*p) && isspace(*p))
13360089Seric 		p++;
13460089Seric 	if (*p != '\0')
13560089Seric 		map->map_rebuild = newstr(p);
13660089Seric 
13756822Seric 	if (map->map_file == NULL)
13857208Seric 	{
13960089Seric 		syserr("No file name for %s map %s",
14060089Seric 			map->map_class->map_cname, map->map_mname);
14156822Seric 		return FALSE;
14257208Seric 	}
14360089Seric 	return TRUE;
14460089Seric }
14560089Seric /*
14660089Seric **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
14760089Seric **
14860089Seric **	It also adds the map_app string.  It can be used as a utility
14960089Seric **	in the map_lookup method.
15060089Seric **
15160089Seric **	Parameters:
15260089Seric **		map -- the map that causes this.
15360089Seric **		s -- the string to rewrite, NOT necessarily null terminated.
15460089Seric **		slen -- the length of s.
15560089Seric **		av -- arguments to interpolate into buf.
15660089Seric **
15760089Seric **	Returns:
15860089Seric **		Pointer to rewritten result.
15960089Seric **
16060089Seric **	Side Effects:
16160089Seric **		none.
16260089Seric */
16360089Seric 
16460492Seric struct rwbuf
16560492Seric {
16660492Seric 	int	rwb_len;	/* size of buffer */
16760492Seric 	char	*rwb_buf;	/* ptr to buffer */
16860492Seric };
16960492Seric 
17060492Seric struct rwbuf	RwBufs[2];	/* buffers for rewriting output */
17160492Seric 
17260089Seric char *
17360089Seric map_rewrite(map, s, slen, av)
17460089Seric 	register MAP *map;
17560089Seric 	register char *s;
17660089Seric 	int slen;
17760089Seric 	char **av;
17860089Seric {
17960089Seric 	register char *bp;
18060089Seric 	register char c;
18160089Seric 	char **avp;
18260089Seric 	register char *ap;
18360492Seric 	register struct rwbuf *rwb;
18460089Seric 	int i;
18560089Seric 	int len;
18660089Seric 
18760537Seric 	if (tTd(39, 1))
18860089Seric 	{
18960256Seric 		printf("map_rewrite(%.*s), av =", slen, s);
19060256Seric 		if (av == NULL)
19160256Seric 			printf(" (nullv)");
19260256Seric 		else
19360256Seric 		{
19460256Seric 			for (avp = av; *avp != NULL; avp++)
19560256Seric 				printf("\n\t%s", *avp);
19660256Seric 		}
19760256Seric 		printf("\n");
19860089Seric 	}
19960089Seric 
20060492Seric 	rwb = RwBufs;
20160492Seric 	if (av == NULL)
20260492Seric 		rwb++;
20360492Seric 
20460089Seric 	/* count expected size of output (can safely overestimate) */
20560089Seric 	i = len = slen;
20660089Seric 	if (av != NULL)
20760089Seric 	{
20860089Seric 		bp = s;
20960089Seric 		for (i = slen; --i >= 0 && (c = *bp++) != 0; )
21060089Seric 		{
21160089Seric 			if (c != '%')
21260089Seric 				continue;
21360089Seric 			if (--i < 0)
21460089Seric 				break;
21560089Seric 			c = *bp++;
21660089Seric 			if (!(isascii(c) && isdigit(c)))
21760089Seric 				continue;
21860089Seric 			c -= 0;
21960089Seric 			for (avp = av; --c >= 0 && *avp != NULL; avp++)
22060089Seric 				continue;
22160089Seric 			if (*avp == NULL)
22260089Seric 				continue;
22360089Seric 			len += strlen(*avp);
22460089Seric 		}
22560089Seric 	}
22660089Seric 	if (map->map_app != NULL)
22760089Seric 		len += strlen(map->map_app);
22860492Seric 	if (rwb->rwb_len < ++len)
22960089Seric 	{
23060089Seric 		/* need to malloc additional space */
23160492Seric 		rwb->rwb_len = len;
23260492Seric 		if (rwb->rwb_buf != NULL)
23360492Seric 			free(rwb->rwb_buf);
23460492Seric 		rwb->rwb_buf = xalloc(rwb->rwb_len);
23560089Seric 	}
23660089Seric 
23760492Seric 	bp = rwb->rwb_buf;
23860089Seric 	if (av == NULL)
23960089Seric 	{
24060089Seric 		bcopy(s, bp, slen);
24160089Seric 		bp += slen;
24260089Seric 	}
24360089Seric 	else
24460089Seric 	{
24560089Seric 		while (--slen >= 0 && (c = *s++) != '\0')
24660089Seric 		{
24760089Seric 			if (c != '%')
24860089Seric 			{
24960089Seric   pushc:
25060089Seric 				*bp++ = c;
25160089Seric 				continue;
25260089Seric 			}
25360089Seric 			if (--slen < 0 || (c = *s++) == '\0')
25460089Seric 				c = '%';
25560089Seric 			if (c == '%')
25660089Seric 				goto pushc;
25760089Seric 			if (!(isascii(c) && isdigit(c)))
25860089Seric 			{
25960089Seric 				*bp++ = '%';
26060089Seric 				goto pushc;
26160089Seric 			}
26260089Seric 			c -= '0';
26360089Seric 			for (avp = av; --c >= 0 && *avp != NULL; avp++)
26460089Seric 				continue;
26560089Seric 			if (*avp == NULL)
26660089Seric 				continue;
26760089Seric 
26860089Seric 			/* transliterate argument into output string */
26960089Seric 			for (ap = *avp; (c = *ap++) != '\0'; )
27060089Seric 				*bp++ = c;
27160089Seric 		}
27260089Seric 	}
27360089Seric 	if (map->map_app != NULL)
27460089Seric 		strcpy(bp, map->map_app);
27560089Seric 	else
27660089Seric 		*bp = '\0';
27760537Seric 	if (tTd(39, 1))
27860492Seric 		printf("map_rewrite => %s\n", rwb->rwb_buf);
27960492Seric 	return rwb->rwb_buf;
28060089Seric }
28160089Seric /*
28260537Seric **  INITMAPS -- initialize for aliasing
28360537Seric **
28460537Seric **	Parameters:
28560537Seric **		rebuild -- if TRUE, this rebuilds the cached versions.
28660537Seric **		e -- current envelope.
28760537Seric **
28860537Seric **	Returns:
28960537Seric **		none.
29060537Seric **
29160537Seric **	Side Effects:
29260537Seric **		initializes aliases:
29360537Seric **		if NDBM:  opens the database.
29460537Seric **		if ~NDBM: reads the aliases into the symbol table.
29560537Seric */
29660537Seric 
29760537Seric initmaps(rebuild, e)
29860537Seric 	bool rebuild;
29960537Seric 	register ENVELOPE *e;
30060537Seric {
30160537Seric 	extern void map_init();
30260537Seric 
30360537Seric 	CurEnv = e;
30460537Seric 	stabapply(map_init, rebuild);
30560537Seric }
30660537Seric 
30760537Seric void
30860537Seric map_init(s, rebuild)
30960537Seric 	register STAB *s;
31060537Seric 	int rebuild;
31160537Seric {
31260537Seric 	register MAP *map;
31360537Seric 
31460537Seric 	/* has to be a map */
31560537Seric 	if (s->s_type != ST_MAP)
31660537Seric 		return;
31760537Seric 
31860537Seric 	map = &s->s_map;
31960537Seric 	if (!bitset(MF_VALID, map->map_mflags))
32060537Seric 		return;
32160537Seric 
32260537Seric 	if (tTd(38, 2))
32360537Seric 		printf("map_init(%s:%s)\n",
32460537Seric 			map->map_class->map_cname, map->map_file);
32560537Seric 
32660537Seric 	/* if already open, close it (for nested open) */
32760537Seric 	if (bitset(MF_OPEN, map->map_mflags))
32860537Seric 	{
32960537Seric 		map->map_class->map_close(map);
33060537Seric 		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
33160537Seric 	}
33260537Seric 
33360537Seric 	if (rebuild)
33460537Seric 	{
33560926Seric 		if (bitset(MF_ALIAS, map->map_mflags) &&
33660926Seric 		    bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
33760537Seric 			rebuildaliases(map, FALSE);
33860537Seric 	}
33960537Seric 	else
34060537Seric 	{
34160537Seric 		if (map->map_class->map_open(map, O_RDONLY))
34260537Seric 		{
34360537Seric 			if (tTd(38, 4))
34460537Seric 				printf("%s:%s: valid\n",
34560537Seric 					map->map_class->map_cname,
34660537Seric 					map->map_file);
34760537Seric 			map->map_mflags |= MF_OPEN;
34860537Seric 		}
34960537Seric 		else if (tTd(38, 4))
35060537Seric 			printf("%s:%s: invalid: %s\n",
35160537Seric 				map->map_class->map_cname,
35260537Seric 				map->map_file,
35360537Seric 				errstring(errno));
35460537Seric 	}
35560537Seric }
35660537Seric /*
35760089Seric **  NDBM modules
35860089Seric */
35960089Seric 
36060089Seric #ifdef NDBM
36160089Seric 
36260089Seric /*
36360089Seric **  DBM_MAP_OPEN -- DBM-style map open
36460089Seric */
36560089Seric 
36660089Seric bool
36760089Seric ndbm_map_open(map, mode)
36860089Seric 	MAP *map;
36960089Seric 	int mode;
37060089Seric {
37160089Seric 	DBM *dbm;
37260089Seric 
37360537Seric 	if (tTd(38, 2))
37460089Seric 		printf("ndbm_map_open(%s, %d)\n", map->map_file, mode);
37560089Seric 
37660207Seric 	if (mode == O_RDWR)
37760207Seric 		mode |= O_CREAT|O_TRUNC;
37860207Seric 
37960089Seric 	/* open the database */
38060089Seric 	dbm = dbm_open(map->map_file, mode, DBMMODE);
38156822Seric 	if (dbm == NULL)
38256822Seric 	{
38360207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
38456836Seric 			syserr("Cannot open DBM database %s", map->map_file);
38556822Seric 		return FALSE;
38656822Seric 	}
38760089Seric 	map->map_db1 = (void *) dbm;
38860207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
38960604Seric 		aliaswait(map, ".pag");
39056822Seric 	return TRUE;
39156822Seric }
39260089Seric 
39360089Seric 
39460089Seric /*
39556822Seric **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
39656822Seric */
39756822Seric 
39856822Seric char *
39960089Seric ndbm_map_lookup(map, name, av, statp)
40056822Seric 	MAP *map;
40160089Seric 	char *name;
40256822Seric 	char **av;
40359084Seric 	int *statp;
40456822Seric {
40556822Seric 	datum key, val;
40660089Seric 	char keybuf[MAXNAME + 1];
40756822Seric 
40860537Seric 	if (tTd(38, 20))
40960089Seric 		printf("ndbm_map_lookup(%s)\n", name);
41060089Seric 
41160089Seric 	key.dptr = name;
41260089Seric 	key.dsize = strlen(name);
41360207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
41457014Seric 	{
41560089Seric 		if (key.dsize > sizeof keybuf - 1)
41660089Seric 			key.dsize = sizeof keybuf - 1;
41760089Seric 		bcopy(key.dptr, keybuf, key.dsize + 1);
41860089Seric 		makelower(keybuf);
41960089Seric 		key.dptr = keybuf;
42057014Seric 	}
42160207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
42256822Seric 		key.dsize++;
42360089Seric 	(void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file, LOCK_SH);
42460089Seric 	val = dbm_fetch((DBM *) map->map_db1, key);
42560089Seric 	(void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file, LOCK_UN);
42656822Seric 	if (val.dptr == NULL)
42756822Seric 		return NULL;
42860207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
42960089Seric 		av = NULL;
43060089Seric 	return map_rewrite(map, val.dptr, val.dsize, av);
43156822Seric }
43256822Seric 
43356822Seric 
43456822Seric /*
43560089Seric **  DBM_MAP_STORE -- store a datum in the database
43656822Seric */
43756822Seric 
43860089Seric void
43960089Seric ndbm_map_store(map, lhs, rhs)
44060089Seric 	register MAP *map;
44160089Seric 	char *lhs;
44260089Seric 	char *rhs;
44360089Seric {
44460089Seric 	datum key;
44560089Seric 	datum data;
44660089Seric 	int stat;
44760089Seric 
44860537Seric 	if (tTd(38, 12))
44960089Seric 		printf("ndbm_map_store(%s, %s)\n", lhs, rhs);
45060089Seric 
45160089Seric 	key.dsize = strlen(lhs);
45260089Seric 	key.dptr = lhs;
45360089Seric 
45460089Seric 	data.dsize = strlen(rhs);
45560089Seric 	data.dptr = rhs;
45660089Seric 
45760207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
45860089Seric 	{
45960089Seric 		key.dsize++;
46060089Seric 		data.dsize++;
46160089Seric 	}
46260089Seric 
46360089Seric 	stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
46460089Seric 	if (stat > 0)
46560089Seric 	{
46660089Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
46760089Seric 		stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
46860089Seric 	}
46960089Seric 	if (stat != 0)
47060089Seric 		syserr("readaliases: dbm put (%s)", lhs);
47160089Seric }
47260089Seric 
47360089Seric 
47460089Seric /*
47560207Seric **  NDBM_MAP_CLOSE -- close the database
47660089Seric */
47760089Seric 
47860089Seric void
47960089Seric ndbm_map_close(map)
48060089Seric 	register MAP  *map;
48160089Seric {
48260207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
48360089Seric 	{
48460089Seric #ifdef YPCOMPAT
48560089Seric 		char buf[200];
48660089Seric 
48760089Seric 		(void) sprintf(buf, "%010ld", curtime());
48860089Seric 		ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
48960089Seric 
49060089Seric 		(void) myhostname(buf, sizeof buf);
49160089Seric 		ndbm_map_store(map, "YP_MASTER_NAME", buf);
49260089Seric #endif
49360089Seric 
49460089Seric 		/* write out the distinguished alias */
49560089Seric 		ndbm_map_store(map, "@", "@");
49660089Seric 	}
49760089Seric 	dbm_close((DBM *) map->map_db1);
49860089Seric }
49960089Seric 
50060089Seric #endif
50160089Seric /*
50260582Seric **  NEWDB (Hash and BTree) Modules
50360089Seric */
50460089Seric 
50560089Seric #ifdef NEWDB
50660089Seric 
50760089Seric /*
50860582Seric **  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
50960582Seric **
51060582Seric **	These do rather bizarre locking.  If you can lock on open,
51160582Seric **	do that to avoid the condition of opening a database that
51260582Seric **	is being rebuilt.  If you don't, we'll try to fake it, but
51360582Seric **	there will be a race condition.  If opening for read-only,
51460582Seric **	we immediately release the lock to avoid freezing things up.
51560582Seric **	We really ought to hold the lock, but guarantee that we won't
51660582Seric **	be pokey about it.  That's hard to do.
51760089Seric */
51860089Seric 
51956822Seric bool
52060089Seric bt_map_open(map, mode)
52156822Seric 	MAP *map;
52260089Seric 	int mode;
52356822Seric {
52456822Seric 	DB *db;
52560228Seric 	int i;
52660582Seric 	int omode;
52760089Seric 	char buf[MAXNAME];
52856822Seric 
52960537Seric 	if (tTd(38, 2))
53060089Seric 		printf("bt_map_open(%s, %d)\n", map->map_file, mode);
53160089Seric 
53260582Seric 	omode = mode;
53360582Seric 	if (omode == O_RDWR)
53460582Seric 	{
53560582Seric 		omode |= O_CREAT|O_TRUNC;
53660582Seric #if defined(O_EXLOCK) && !defined(LOCKF)
53760582Seric 		omode |= O_EXLOCK;
53860582Seric # if !defined(OLD_NEWDB)
53960582Seric 	}
54060582Seric 	else
54160582Seric 	{
54260582Seric 		omode |= O_SHLOCK;
54360582Seric # endif
54460582Seric #endif
54560582Seric 	}
54660207Seric 
54760228Seric 	(void) strcpy(buf, map->map_file);
54860228Seric 	i = strlen(buf);
54960228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
55060228Seric 		(void) strcat(buf, ".db");
55160582Seric 	db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
55256822Seric 	if (db == NULL)
55356822Seric 	{
55460207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
55556836Seric 			syserr("Cannot open BTREE database %s", map->map_file);
55656822Seric 		return FALSE;
55756822Seric 	}
55860582Seric #if !defined(OLD_NEWDB) && !defined(LOCKF)
55960582Seric # if !defined(O_EXLOCK)
56060582Seric 	if (mode == O_RDWR)
56160582Seric 		(void) lockfile(db->fd(db), map->map_file, LOCK_EX);
56260582Seric # else
56360582Seric 	if (mode == O_RDONLY)
56460582Seric 		(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
56560582Seric # endif
56660582Seric #endif
56760585Seric 
56860585Seric 	/* try to make sure that at least the database header is on disk */
56960585Seric 	if (mode == O_RDWR)
57060585Seric 		(void) db->sync(db, 0);
57160585Seric 
57260089Seric 	map->map_db2 = (void *) db;
57360207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
57460207Seric 		aliaswait(map, ".db");
57556822Seric 	return TRUE;
57656822Seric }
57756822Seric 
57856822Seric 
57956822Seric /*
58056822Seric **  HASH_MAP_INIT -- HASH-style map initialization
58156822Seric */
58256822Seric 
58356822Seric bool
58460089Seric hash_map_open(map, mode)
58556822Seric 	MAP *map;
58660089Seric 	int mode;
58756822Seric {
58856822Seric 	DB *db;
58960228Seric 	int i;
59060582Seric 	int omode;
59160089Seric 	char buf[MAXNAME];
59256822Seric 
59360537Seric 	if (tTd(38, 2))
59460089Seric 		printf("hash_map_open(%s, %d)\n", map->map_file, mode);
59560089Seric 
59660582Seric 	omode = mode;
59760582Seric 	if (omode == O_RDWR)
59860582Seric 	{
59960582Seric 		omode |= O_CREAT|O_TRUNC;
60060582Seric #if defined(O_EXLOCK) && !defined(LOCKF)
60160582Seric 		omode |= O_EXLOCK;
60260582Seric # if !defined(OLD_NEWDB)
60360582Seric 	}
60460582Seric 	else
60560582Seric 	{
60660582Seric 		omode |= O_SHLOCK;
60760582Seric # endif
60860582Seric #endif
60960582Seric 	}
61060207Seric 
61160228Seric 	(void) strcpy(buf, map->map_file);
61260228Seric 	i = strlen(buf);
61360228Seric 	if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
61460228Seric 		(void) strcat(buf, ".db");
61560582Seric 	db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
61656822Seric 	if (db == NULL)
61756822Seric 	{
61860207Seric 		if (!bitset(MF_OPTIONAL, map->map_mflags))
61956836Seric 			syserr("Cannot open HASH database %s", map->map_file);
62056822Seric 		return FALSE;
62156822Seric 	}
62260582Seric #if !defined(OLD_NEWDB) && !defined(LOCKF)
62360582Seric # if !defined(O_EXLOCK)
62460582Seric 	if (mode == O_RDWR)
62560582Seric 		(void) lockfile(db->fd(db), map->map_file, LOCK_EX);
62660582Seric # else
62760582Seric 	if (mode == O_RDONLY)
62860582Seric 		(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
62960582Seric # endif
63060582Seric #endif
63160585Seric 
63260585Seric 	/* try to make sure that at least the database header is on disk */
63360585Seric 	if (mode == O_RDWR)
63460585Seric 		(void) db->sync(db, 0);
63560585Seric 
63660089Seric 	map->map_db2 = (void *) db;
63760207Seric 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
63860207Seric 		aliaswait(map, ".db");
63956822Seric 	return TRUE;
64056822Seric }
64156822Seric 
64256822Seric 
64356822Seric /*
64456822Seric **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
64556822Seric */
64656822Seric 
64756822Seric char *
64860089Seric db_map_lookup(map, name, av, statp)
64956822Seric 	MAP *map;
65060089Seric 	char *name;
65156822Seric 	char **av;
65259084Seric 	int *statp;
65356822Seric {
65456822Seric 	DBT key, val;
65560422Seric 	register DB *db = (DB *) map->map_db2;
65660422Seric 	int st;
65760422Seric 	int saveerrno;
65860089Seric 	char keybuf[MAXNAME + 1];
65956822Seric 
66060537Seric 	if (tTd(38, 20))
66160089Seric 		printf("db_map_lookup(%s)\n", name);
66260089Seric 
66360089Seric 	key.size = strlen(name);
66460089Seric 	if (key.size > sizeof keybuf - 1)
66560089Seric 		key.size = sizeof keybuf - 1;
66660089Seric 	key.data = keybuf;
66760089Seric 	bcopy(name, keybuf, key.size + 1);
66860207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
66960089Seric 		makelower(keybuf);
67060207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
67156822Seric 		key.size++;
67260422Seric #ifndef OLD_NEWDB
67360422Seric 	(void) lockfile(db->fd(db), map->map_file, LOCK_SH);
67460422Seric #endif
67560422Seric 	st = db->get(db, &key, &val, 0);
67660422Seric 	saveerrno = errno;
67760422Seric #ifndef OLD_NEWDB
67860422Seric 	(void) lockfile(db->fd(db), map->map_file, LOCK_UN);
67960422Seric #endif
68060422Seric 	if (st != 0)
68160422Seric 	{
68260422Seric 		errno = saveerrno;
68360422Seric 		if (st < 0)
68460422Seric 			syserr("db_map_lookup: get (%s)", name);
68556822Seric 		return NULL;
68660422Seric 	}
68760207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
68860089Seric 		av = NULL;
68960089Seric 	return map_rewrite(map, val.data, val.size, av);
69056822Seric }
69156822Seric 
69260089Seric 
69360089Seric /*
69460089Seric **  DB_MAP_STORE -- store a datum in the NEWDB database
69556822Seric */
69656822Seric 
69760089Seric void
69860089Seric db_map_store(map, lhs, rhs)
69960089Seric 	register MAP *map;
70060089Seric 	char *lhs;
70160089Seric 	char *rhs;
70256822Seric {
70360089Seric 	int stat;
70460089Seric 	DBT key;
70560089Seric 	DBT data;
70660089Seric 	register DB *db = map->map_db2;
70756822Seric 
70860537Seric 	if (tTd(38, 20))
70960089Seric 		printf("db_map_store(%s, %s)\n", lhs, rhs);
71060089Seric 
71160089Seric 	key.size = strlen(lhs);
71260089Seric 	key.data = lhs;
71360089Seric 
71460089Seric 	data.size = strlen(rhs);
71560089Seric 	data.data = rhs;
71660089Seric 
71760207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
71856822Seric 	{
71960089Seric 		key.size++;
72060089Seric 		data.size++;
72160089Seric 	}
72256836Seric 
72360089Seric 	stat = db->put(db, &key, &data, R_NOOVERWRITE);
72460089Seric 	if (stat > 0)
72560089Seric 	{
72660089Seric 		usrerr("050 Warning: duplicate alias name %s", lhs);
72760089Seric 		stat = db->put(db, &key, &data, 0);
72860089Seric 	}
72960089Seric 	if (stat != 0)
73060089Seric 		syserr("readaliases: db put (%s)", lhs);
73160089Seric }
73256836Seric 
73356847Seric 
73460089Seric /*
73560089Seric **  DB_MAP_CLOSE -- add distinguished entries and close the database
73660089Seric */
73760089Seric 
73860089Seric void
73960089Seric db_map_close(map)
74060089Seric 	MAP *map;
74160089Seric {
74260089Seric 	register DB *db = map->map_db2;
74360089Seric 
74460537Seric 	if (tTd(38, 9))
74560207Seric 		printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags);
74660089Seric 
74760207Seric 	if (bitset(MF_WRITABLE, map->map_mflags))
74858804Seric 	{
74960089Seric 		/* write out the distinguished alias */
75060089Seric 		db_map_store(map, "@", "@");
75158804Seric 	}
75258963Seric 
75360089Seric 	if (db->close(db) != 0)
75460089Seric 		syserr("readaliases: db close failure");
75556822Seric }
75657208Seric 
75760089Seric #endif
75860089Seric /*
75960089Seric **  NIS Modules
76060089Seric */
76160089Seric 
76260089Seric # ifdef NIS
76360089Seric 
76457208Seric /*
76560089Seric **  NIS_MAP_OPEN -- open DBM map
76657208Seric */
76757208Seric 
76857208Seric bool
76960089Seric nis_map_open(map, mode)
77057208Seric 	MAP *map;
77160089Seric 	int mode;
77257208Seric {
77357216Seric 	int yperr;
77460215Seric 	register char *p;
77560215Seric 	auto char *vp;
77660215Seric 	auto int vsize;
77757216Seric 	char *master;
77857216Seric 
77960537Seric 	if (tTd(38, 2))
78060089Seric 		printf("nis_map_open(%s)\n", map->map_file);
78160089Seric 
78260207Seric 	if (mode != O_RDONLY)
78360207Seric 	{
78460207Seric 		errno = ENODEV;
78560207Seric 		return FALSE;
78660207Seric 	}
78760207Seric 
78860089Seric 	p = strchr(map->map_file, '@');
78960089Seric 	if (p != NULL)
79060089Seric 	{
79160089Seric 		*p++ = '\0';
79260089Seric 		if (*p != '\0')
79360089Seric 			map->map_domain = p;
79460089Seric 	}
79560215Seric 
79660089Seric 	if (map->map_domain == NULL)
79760089Seric 		yp_get_default_domain(&map->map_domain);
79860089Seric 
79960089Seric 	if (*map->map_file == '\0')
80060089Seric 		map->map_file = "mail.aliases";
80160089Seric 
80260215Seric 	/* check to see if this map actually exists */
80360089Seric 	yperr = yp_match(map->map_domain, map->map_file, "@", 1,
80460089Seric 			&vp, &vsize);
80560537Seric 	if (tTd(38, 10))
80660089Seric 		printf("nis_map_open: yp_match(%s, %s) => %s\n",
80760089Seric 			map->map_domain, map->map_file, yperr_string(yperr));
80860089Seric 	if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
80960089Seric 		return TRUE;
81060215Seric 
81160215Seric 	if (!bitset(MF_OPTIONAL, map->map_mflags))
81260215Seric 		syserr("Cannot bind to domain %s: %s", map->map_domain,
81360215Seric 			yperr_string(yperr));
81460215Seric 
81560089Seric 	return FALSE;
81660089Seric }
81760089Seric 
81860089Seric 
81960089Seric /*
82057208Seric **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
82157208Seric */
82257208Seric 
82357208Seric char *
82460089Seric nis_map_lookup(map, name, av, statp)
82557208Seric 	MAP *map;
82660089Seric 	char *name;
82757208Seric 	char **av;
82859084Seric 	int *statp;
82957208Seric {
83057208Seric 	char *vp;
83157642Seric 	auto int vsize;
83259274Seric 	int buflen;
83360215Seric 	int yperr;
83460089Seric 	char keybuf[MAXNAME + 1];
83557208Seric 
83660537Seric 	if (tTd(38, 20))
83760089Seric 		printf("nis_map_lookup(%s)\n", name);
83860089Seric 
83960089Seric 	buflen = strlen(name);
84060089Seric 	if (buflen > sizeof keybuf - 1)
84160089Seric 		buflen = sizeof keybuf - 1;
84260089Seric 	bcopy(name, keybuf, buflen + 1);
84360207Seric 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
84460089Seric 		makelower(keybuf);
84560207Seric 	if (bitset(MF_INCLNULL, map->map_mflags))
84659274Seric 		buflen++;
84760089Seric 	yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
84860089Seric 		     &vp, &vsize);
84960089Seric 	if (yperr != 0)
85060089Seric 	{
85160089Seric 		if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
85260215Seric 			map->map_mflags &= ~(MF_VALID|MF_OPEN);
85357208Seric 		return NULL;
85460089Seric 	}
85560207Seric 	if (bitset(MF_MATCHONLY, map->map_mflags))
85660089Seric 		av = NULL;
85760215Seric 	return map_rewrite(map, vp, vsize, av);
85857208Seric }
85957208Seric 
86060089Seric 
86160089Seric /*
86260207Seric **  NIS_MAP_STORE
86360089Seric */
86460089Seric 
86560089Seric void
86660089Seric nis_map_store(map, lhs, rhs)
86760089Seric 	MAP *map;
86860089Seric 	char *lhs;
86960089Seric 	char *rhs;
87060089Seric {
87160089Seric 	/* nothing */
87260089Seric }
87360089Seric 
87460089Seric 
87560089Seric /*
87660207Seric **  NIS_MAP_CLOSE
87760089Seric */
87860089Seric 
87960089Seric void
88060089Seric nis_map_close(map)
88160089Seric 	MAP *map;
88260089Seric {
88360089Seric 	/* nothing */
88460089Seric }
88560089Seric 
88660089Seric #endif /* NIS */
88757208Seric /*
88860089Seric **  STAB (Symbol Table) Modules
88960089Seric */
89060089Seric 
89160089Seric 
89260089Seric /*
89360207Seric **  STAB_MAP_LOOKUP -- look up alias in symbol table
89460089Seric */
89560089Seric 
89660089Seric char *
897*61707Seric stab_map_lookup(map, name, av, pstat)
89860089Seric 	register MAP *map;
89960089Seric 	char *name;
900*61707Seric 	char **av;
901*61707Seric 	int *pstat;
90260089Seric {
90360089Seric 	register STAB *s;
90460089Seric 
90560537Seric 	if (tTd(38, 20))
90660089Seric 		printf("stab_lookup(%s)\n", name);
90760089Seric 
90860089Seric 	s = stab(name, ST_ALIAS, ST_FIND);
90960089Seric 	if (s != NULL)
91060089Seric 		return (s->s_alias);
91160089Seric 	return (NULL);
91260089Seric }
91360089Seric 
91460089Seric 
91560089Seric /*
91660207Seric **  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
91760089Seric */
91860089Seric 
91960089Seric void
92060089Seric stab_map_store(map, lhs, rhs)
92160089Seric 	register MAP *map;
92260089Seric 	char *lhs;
92360089Seric 	char *rhs;
92460089Seric {
92560089Seric 	register STAB *s;
92660089Seric 
92760089Seric 	s = stab(lhs, ST_ALIAS, ST_ENTER);
92860089Seric 	s->s_alias = newstr(rhs);
92960089Seric }
93060089Seric 
93160089Seric 
93260089Seric /*
93360207Seric **  STAB_MAP_OPEN -- initialize (reads data file)
93460207Seric **
93560207Seric **	This is a wierd case -- it is only intended as a fallback for
93660207Seric **	aliases.  For this reason, opens for write (only during a
93760207Seric **	"newaliases") always fails, and opens for read open the
93860207Seric **	actual underlying text file instead of the database.
93960089Seric */
94060089Seric 
94160089Seric bool
94260089Seric stab_map_open(map, mode)
94360089Seric 	register MAP *map;
94460089Seric 	int mode;
94560089Seric {
94660537Seric 	if (tTd(38, 2))
94760089Seric 		printf("stab_map_open(%s)\n", map->map_file);
94860089Seric 
94960089Seric 	if (mode != O_RDONLY)
95060207Seric 	{
95160207Seric 		errno = ENODEV;
95260089Seric 		return FALSE;
95360207Seric 	}
95460089Seric 
95560089Seric 	return TRUE;
95660089Seric }
95760089Seric 
95860089Seric 
95960089Seric /*
96060207Seric **  STAB_MAP_CLOSE -- close symbol table (???)
96160089Seric */
96260089Seric 
96360089Seric void
96460089Seric stab_map_close(map)
96560089Seric 	MAP *map;
96660089Seric {
96760089Seric 	/* ignore it */
96860089Seric }
96960089Seric /*
97060089Seric **  Implicit Modules
97156822Seric **
97260089Seric **	Tries several types.  For back compatibility of aliases.
97356822Seric */
97456822Seric 
97560089Seric 
97660089Seric /*
97760207Seric **  IMPL_MAP_LOOKUP -- lookup in best open database
97860089Seric */
97960089Seric 
98060089Seric char *
98160089Seric impl_map_lookup(map, name, av, pstat)
98260089Seric 	MAP *map;
98360089Seric 	char *name;
98456822Seric 	char **av;
98560089Seric 	int *pstat;
98656822Seric {
98760537Seric 	if (tTd(38, 20))
98860089Seric 		printf("impl_map_lookup(%s)\n", name);
98956822Seric 
99060089Seric #ifdef NEWDB
99160207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
99260089Seric 		return db_map_lookup(map, name, av, pstat);
99360089Seric #endif
99460089Seric #ifdef NDBM
99560207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
99660089Seric 		return ndbm_map_lookup(map, name, av, pstat);
99760089Seric #endif
99860089Seric 	return stab_map_lookup(map, name, av, pstat);
99960089Seric }
100060089Seric 
100160089Seric /*
100260207Seric **  IMPL_MAP_STORE -- store in open databases
100360089Seric */
100460089Seric 
100560089Seric void
100660089Seric impl_map_store(map, lhs, rhs)
100760089Seric 	MAP *map;
100860089Seric 	char *lhs;
100960089Seric 	char *rhs;
101060089Seric {
101160089Seric #ifdef NEWDB
101260207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
101360089Seric 		db_map_store(map, lhs, rhs);
101460089Seric #endif
101560089Seric #ifdef NDBM
101660207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
101760089Seric 		ndbm_map_store(map, lhs, rhs);
101860089Seric #endif
101960089Seric 	stab_map_store(map, lhs, rhs);
102060089Seric }
102160089Seric 
102260089Seric /*
102360089Seric **  IMPL_MAP_OPEN -- implicit database open
102460089Seric */
102560089Seric 
102660089Seric bool
102760089Seric impl_map_open(map, mode)
102860089Seric 	MAP *map;
102960089Seric 	int mode;
103060089Seric {
103160089Seric 	struct stat stb;
103260089Seric 
103360537Seric 	if (tTd(38, 2))
103460089Seric 		printf("impl_map_open(%s)\n", map->map_file);
103560089Seric 
103660089Seric 	if (stat(map->map_file, &stb) < 0)
103756822Seric 	{
103860089Seric 		/* no alias file at all */
103960089Seric 		return FALSE;
104056822Seric 	}
104156822Seric 
104260089Seric #ifdef NEWDB
104360207Seric 	map->map_mflags |= MF_IMPL_HASH;
104460089Seric 	if (hash_map_open(map, mode))
104556822Seric 	{
104660207Seric #if defined(NDBM) && defined(YPCOMPAT)
104760561Seric 		if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0)
104860207Seric #endif
104960207Seric 			return TRUE;
105060089Seric 	}
105160207Seric 	else
105260207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
105360089Seric #endif
105460089Seric #ifdef NDBM
105560207Seric 	map->map_mflags |= MF_IMPL_NDBM;
105660089Seric 	if (ndbm_map_open(map, mode))
105760089Seric 	{
105860089Seric 		return TRUE;
105960089Seric 	}
106060207Seric 	else
106160207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
106260089Seric #endif
106356822Seric 
106460207Seric #if !defined(NEWDB) && !defined(NDBM)
106560089Seric 	if (Verbose)
106660089Seric 		message("WARNING: cannot open alias database %s", map->map_file);
106760207Seric #endif
106860089Seric 
106960207Seric 	return stab_map_open(map, mode);
107056822Seric }
107160089Seric 
107260207Seric 
107360089Seric /*
107460207Seric **  IMPL_MAP_CLOSE -- close any open database(s)
107560089Seric */
107660089Seric 
107760089Seric void
107860207Seric impl_map_close(map)
107960089Seric 	MAP *map;
108060089Seric {
108160089Seric #ifdef NEWDB
108260207Seric 	if (bitset(MF_IMPL_HASH, map->map_mflags))
108360089Seric 	{
108460207Seric 		db_map_close(map);
108560207Seric 		map->map_mflags &= ~MF_IMPL_HASH;
108660089Seric 	}
108760089Seric #endif
108860089Seric 
108960089Seric #ifdef NDBM
109060207Seric 	if (bitset(MF_IMPL_NDBM, map->map_mflags))
109160089Seric 	{
109260207Seric 		ndbm_map_close(map);
109360207Seric 		map->map_mflags &= ~MF_IMPL_NDBM;
109460089Seric 	}
109560089Seric #endif
109660089Seric }
109760207Seric /*
109860207Seric **  NULL stubs
109960089Seric */
110060089Seric 
110160207Seric bool
110260207Seric null_map_open(map, mode)
110360089Seric 	MAP *map;
110460207Seric 	int mode;
110560089Seric {
110660207Seric 	return TRUE;
110760089Seric }
110860089Seric 
110960207Seric void
111060207Seric null_map_close(map)
111160207Seric 	MAP *map;
111260089Seric {
111360207Seric 	return;
111460207Seric }
111560089Seric 
111660207Seric void
111760207Seric null_map_store(map, key, val)
111860207Seric 	MAP *map;
111960207Seric 	char *key;
112060207Seric 	char *val;
112160089Seric {
112260207Seric 	return;
112360089Seric }
1124