xref: /csrg-svn/usr.sbin/sendmail/src/map.c (revision 59274)
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*59274Seric static char sccsid[] = "@(#)map.c	6.10 (Berkeley) 04/26/93";
1156822Seric #endif /* not lint */
1256822Seric 
1356822Seric #include "sendmail.h"
1456822Seric 
1556822Seric #ifdef DBM_MAP
1656822Seric #include <ndbm.h>
1756822Seric #endif
1856822Seric #if defined(HASH_MAP) || defined(BTREE_MAP)
1956822Seric #include <db.h>
2056822Seric #endif
2157208Seric #ifdef NIS_MAP
2257208Seric #include <rpcsvc/ypclnt.h>
2357208Seric #endif
2456822Seric 
2556822Seric 
2656822Seric #ifdef DBM_MAP
2756822Seric 
2856822Seric /*
2956822Seric **  DBM_MAP_INIT -- DBM-style map initialization
3056822Seric **
3156822Seric **	Parameters:
3256822Seric **		map -- the pointer to the actual map
3356822Seric **		mapname -- the name of the map (for error messages)
3456822Seric **		args -- a pointer to the config file line arguments
3556822Seric **
3656822Seric **	Returns:
3756822Seric **		TRUE -- if it could successfully open the map.
3856822Seric **		FALSE -- otherwise.
3956822Seric **
4056822Seric **	Side Effects:
4156822Seric **		Gives an error if it can't open the map.
4256822Seric */
4356822Seric 
4456822Seric bool
4556822Seric dbm_map_init(map, mapname, args)
4656822Seric 	MAP *map;
4756822Seric 	char *mapname;
4856822Seric 	char *args;
4956822Seric {
5056822Seric 	DBM *dbm;
5156822Seric 
5257208Seric 	map_parseargs(map, &args);
5356822Seric 	if (map->map_file == NULL)
5457208Seric 	{
5557208Seric 		syserr("No file name for DBM map %s", mapname);
5656822Seric 		return FALSE;
5757208Seric 	}
5856822Seric 	dbm = dbm_open(map->map_file, O_RDONLY, 0644);
5956822Seric 	if (dbm == NULL)
6056822Seric 	{
6156836Seric 		if (!bitset(MF_OPTIONAL, map->map_flags))
6256836Seric 			syserr("Cannot open DBM database %s", map->map_file);
6356822Seric 		return FALSE;
6456822Seric 	}
6556822Seric 	map->map_db = (void *) dbm;
6656822Seric 	return TRUE;
6756822Seric }
6856822Seric /*
6956822Seric **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
7056822Seric **
7156822Seric **	Parameters:
7256822Seric **		map -- the map to look up in.
7356822Seric **		buf -- a pointer to to the buffer containing the key.
7456822Seric **			This is a null terminated string.
7556822Seric **		bufsiz -- the size of buf -- note that this is in general
7656822Seric **			larger that strlen(buf), and buf can be changed
7756822Seric **			in place if desired.
7856822Seric **		av -- arguments from the config file (can be interpolated
7956822Seric **			into the final result).
8059084Seric **		statp -- pointer to status word (out-parameter).
8156822Seric **
8256822Seric **	Returns:
8356822Seric **		A pointer to the rewritten result.
8456822Seric **		NULL if not found in the map.
8556822Seric */
8656822Seric 
8756822Seric char *
8859084Seric dbm_map_lookup(map, buf, bufsiz, av, statp)
8956822Seric 	MAP *map;
9056822Seric 	char buf[];
9156822Seric 	int bufsiz;
9256822Seric 	char **av;
9359084Seric 	int *statp;
9456822Seric {
9556822Seric 	datum key, val;
9656822Seric 
9756822Seric 	key.dptr = buf;
9856822Seric 	key.dsize = strlen(buf);
9957033Seric 	if (!bitset(MF_NOFOLDCASE, map->map_flags))
10057014Seric 	{
10157014Seric 		register char *p;
10257014Seric 
10357014Seric 		for (p = buf; *p != '\0'; p++)
10458050Seric 			if (isascii(*p) && isupper(*p))
10557014Seric 				*p = tolower(*p);
10657014Seric 	}
10756822Seric 	if (bitset(MF_INCLNULL, map->map_flags))
10856822Seric 		key.dsize++;
10956822Seric 	val = dbm_fetch(map->map_db, key);
11056822Seric 	if (val.dptr == NULL)
11156822Seric 		return NULL;
11257208Seric 	if (!bitset(MF_MATCHONLY, map->map_flags))
11357208Seric 		map_rewrite(val.dptr, val.dsize, buf, bufsiz, av);
11456822Seric 	return buf;
11556822Seric }
11656822Seric 
11756822Seric #endif /* DBM_MAP */
11856822Seric 
11956822Seric #ifdef BTREE_MAP
12056822Seric 
12156822Seric /*
12256822Seric **  BTREE_MAP_INIT -- BTREE-style map initialization
12356822Seric **
12456822Seric **	Parameters:
12556822Seric **		map -- the pointer to the actual map
12656822Seric **		mapname -- the name of the map (for error messages)
12756822Seric **		args -- a pointer to the config file line arguments
12856822Seric **
12956822Seric **	Returns:
13056822Seric **		TRUE -- if it could successfully open the map.
13156822Seric **		FALSE -- otherwise.
13256822Seric **
13356822Seric **	Side Effects:
13456822Seric **		Gives an error if it can't open the map.
13556822Seric */
13656822Seric 
13756822Seric bool
13856822Seric bt_map_init(map, mapname, args)
13956822Seric 	MAP *map;
14056822Seric 	char *mapname;
14156822Seric 	char *args;
14256822Seric {
14356822Seric 	DB *db;
14456822Seric 
14557208Seric 	map_parseargs(map, &args);
14656822Seric 	if (map->map_file == NULL)
14757208Seric 	{
14857208Seric 		syserr("No file name for BTREE map %s", mapname);
14956822Seric 		return FALSE;
15057208Seric 	}
15156822Seric 	db = dbopen(map->map_file, O_RDONLY, 0644, DB_BTREE, NULL);
15256822Seric 	if (db == NULL)
15356822Seric 	{
15456836Seric 		if (!bitset(MF_OPTIONAL, map->map_flags))
15556836Seric 			syserr("Cannot open BTREE database %s", map->map_file);
15656822Seric 		return FALSE;
15756822Seric 	}
15856822Seric 	map->map_db = (void *) db;
15956822Seric 	return TRUE;
16056822Seric }
16156822Seric 
16256822Seric #endif /* BTREE_MAP */
16356822Seric 
16456822Seric #ifdef HASH_MAP
16556822Seric 
16656822Seric /*
16756822Seric **  HASH_MAP_INIT -- HASH-style map initialization
16856822Seric **
16956822Seric **	Parameters:
17056822Seric **		map -- the pointer to the actual map
17156822Seric **		mapname -- the name of the map (for error messages)
17256822Seric **		args -- a pointer to the config file line arguments
17356822Seric **
17456822Seric **	Returns:
17556822Seric **		TRUE -- if it could successfully open the map.
17656822Seric **		FALSE -- otherwise.
17756822Seric **
17856822Seric **	Side Effects:
17956822Seric **		Gives an error if it can't open the map.
18056822Seric */
18156822Seric 
18256822Seric bool
18356822Seric hash_map_init(map, mapname, args)
18456822Seric 	MAP *map;
18556822Seric 	char *mapname;
18656822Seric 	char *args;
18756822Seric {
18856822Seric 	DB *db;
18956822Seric 
19057208Seric 	map_parseargs(map, &args);
19156822Seric 	if (map->map_file == NULL)
19257208Seric 	{
19357208Seric 		syserr("No file name for HASH map %s", mapname);
19456822Seric 		return FALSE;
19557208Seric 	}
19656822Seric 	db = dbopen(map->map_file, O_RDONLY, 0644, DB_HASH, NULL);
19756822Seric 	if (db == NULL)
19856822Seric 	{
19956836Seric 		if (!bitset(MF_OPTIONAL, map->map_flags))
20056836Seric 			syserr("Cannot open HASH database %s", map->map_file);
20156822Seric 		return FALSE;
20256822Seric 	}
20356822Seric 	map->map_db = (void *) db;
20456822Seric 	return TRUE;
20556822Seric }
20656822Seric 
20756822Seric #endif /* HASH_MAP */
20856822Seric 
20956822Seric #if defined(BTREE_MAP) || defined(HASH_MAP)
21056822Seric 
21156822Seric /*
21256822Seric **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
21356822Seric **
21456822Seric **	Parameters:
21556822Seric **		map -- the map to look up in.
21656822Seric **		buf -- a pointer to to the buffer containing the key.
21756822Seric **			This is a null terminated string.
21856822Seric **		bufsiz -- the size of buf -- note that this is in general
21956822Seric **			larger that strlen(buf), and buf can be changed
22056822Seric **			in place if desired.
22156822Seric **		av -- arguments from the config file (can be interpolated
22256822Seric **			into the final result).
22359084Seric **		statp -- pointer to status word (out-parameter).
22456822Seric **
22556822Seric **	Returns:
22656822Seric **		A pointer to the rewritten result.
22756822Seric **		NULL if not found in the map.
22856822Seric */
22956822Seric 
23056822Seric char *
23159084Seric db_map_lookup(map, buf, bufsiz, av, statp)
23256822Seric 	MAP *map;
23356822Seric 	char buf[];
23456822Seric 	int bufsiz;
23556822Seric 	char **av;
23659084Seric 	int *statp;
23756822Seric {
23856822Seric 	DBT key, val;
23956822Seric 
24056822Seric 	key.data = buf;
24156822Seric 	key.size = strlen(buf);
24257033Seric 	if (!bitset(MF_NOFOLDCASE, map->map_flags))
24356847Seric 	{
24456847Seric 		register char *p;
24556847Seric 
24656847Seric 		for (p = buf; *p != '\0'; p++)
24758050Seric 			if (isascii(*p) && isupper(*p))
24856847Seric 				*p = tolower(*p);
24956847Seric 	}
25056822Seric 	if (bitset(MF_INCLNULL, map->map_flags))
25156822Seric 		key.size++;
25256836Seric 	if (((DB *) map->map_db)->get((DB *) map->map_db, &key, &val, 0) != 0)
25356822Seric 		return NULL;
25457208Seric 	if (!bitset(MF_MATCHONLY, map->map_flags))
25557208Seric 		map_rewrite(val.data, val.size, buf, bufsiz, av);
25656822Seric 	return buf;
25756822Seric }
25856822Seric 
25956822Seric #endif /* BTREE_MAP || HASH_MAP */
26056822Seric /*
26156822Seric **  MAP_PARSEARGS -- parse config line arguments for database lookup
26256822Seric **
26356822Seric **	Parameters:
26456822Seric **		map -- the map being initialized.
26556822Seric **		pp -- an indirect pointer to the config line.  It will
26656822Seric **			be replaced with a pointer to the next field
26756822Seric **			on the line.
26856822Seric **
26956822Seric **	Returns:
27056822Seric **		none
27156822Seric **
27256822Seric **	Side Effects:
27356822Seric **		null terminates the filename; stores it in map
27456822Seric */
27556822Seric 
27657208Seric map_parseargs(map, pp)
27756822Seric 	MAP *map;
27856822Seric 	char **pp;
27956822Seric {
28056822Seric 	register char *p = *pp;
28156822Seric 
28256822Seric 	for (;;)
28356822Seric 	{
28458050Seric 		while (isascii(*p) && isspace(*p))
28556822Seric 			p++;
28656822Seric 		if (*p != '-')
28756822Seric 			break;
28856822Seric 		switch (*++p)
28956822Seric 		{
29056822Seric 		  case 'N':
29156822Seric 			map->map_flags |= MF_INCLNULL;
29256822Seric 			break;
29356836Seric 
29456836Seric 		  case 'o':
29556836Seric 			map->map_flags |= MF_OPTIONAL;
29656836Seric 			break;
29756836Seric 
29856847Seric 		  case 'f':
29957033Seric 			map->map_flags |= MF_NOFOLDCASE;
30056847Seric 			break;
30156847Seric 
30257208Seric 		  case 'm':
30357208Seric 			map->map_flags |= MF_MATCHONLY;
30457208Seric 			break;
30557208Seric 
30656836Seric 		  case 'a':
30756836Seric 			map->map_app = ++p;
30856836Seric 			break;
30957208Seric 
31057208Seric 		  case 'd':
31157208Seric 			map->map_domain = ++p;
31257208Seric 			break;
31356822Seric 		}
31458050Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
31556822Seric 			p++;
31656836Seric 		if (*p != '\0')
31758804Seric 			*p++ = '\0';
31856822Seric 	}
31956836Seric 	if (map->map_app != NULL)
32056836Seric 		map->map_app = newstr(map->map_app);
32157208Seric 	if (map->map_domain != NULL)
32257208Seric 		map->map_domain = newstr(map->map_domain);
32356822Seric 
32456822Seric 	if (*p != '\0')
32558804Seric 	{
32658804Seric 		map->map_file = p;
32758804Seric 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
32858804Seric 			p++;
32958804Seric 		if (*p != '\0')
33058804Seric 			*p++ = '\0';
33158804Seric 		map->map_file = newstr(map->map_file);
33258804Seric 	}
33358963Seric 
33458963Seric 	while (*p != '\0' && isascii(*p) && isspace(*p))
33558963Seric 		p++;
33656822Seric 	*pp = p;
33758963Seric 	if (*p != '\0')
33858963Seric 		map->map_rebuild = newstr(p);
33956822Seric }
34057208Seric 
34157208Seric # ifdef NIS_MAP
34257208Seric 
34357208Seric /*
34457208Seric **  NIS_MAP_INIT -- initialize DBM map
34557208Seric **
34657208Seric **	Parameters:
34757208Seric **		map -- the pointer to the actual map.
34857208Seric **		mapname -- the name of the map (for error messages).
34957208Seric **		args -- a pointer to the config file line arguments.
35057208Seric **
35157208Seric **	Returns:
35257208Seric **		TRUE -- if it could successfully open the map.
35357208Seric **		FALSE -- otherwise.
35457208Seric **
35557208Seric **	Side Effects:
35657208Seric **		Prints an error if it can't open the map.
35757208Seric */
35857208Seric 
35957208Seric bool
36057208Seric nis_map_init(map, mapname, args)
36157208Seric 	MAP *map;
36257208Seric 	char *mapname;
36357208Seric 	char *args;
36457208Seric {
36557216Seric 	int yperr;
36657216Seric 	char *master;
36757216Seric 
36857208Seric 	/* parse arguments */
36957208Seric 	map_parseargs(map, &args);
37057208Seric 	if (map->map_file == NULL)
37157208Seric 	{
37257208Seric 		syserr("No NIS map name for map %s", mapname);
37357208Seric 		return FALSE;
37457208Seric 	}
37557208Seric 	if (map->map_domain == NULL)
37657208Seric 		yp_get_default_domain(&map->map_domain);
37757216Seric 
37857216Seric 	/* check to see if this map actually exists */
37957216Seric 	yperr = yp_master(map->map_domain, map->map_file, &master);
38057216Seric 	if (yperr == 0)
38157216Seric 		return TRUE;
38257216Seric 	if (!bitset(MF_OPTIONAL, map->map_flags))
38357216Seric 		syserr("Cannot bind to domain %s: %s", map->map_domain,
38457216Seric 			yperr_string(yperr));
38557216Seric 	return FALSE;
38657208Seric }
38756822Seric /*
38857208Seric **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
38957208Seric **
39057208Seric **	Parameters:
39157208Seric **		map -- the map to look up in.
39257208Seric **		buf -- a pointer to to the buffer containing the key.
39357208Seric **			This is a null terminated string.
39457208Seric **		bufsiz -- the size of buf -- note that this is in general
39557208Seric **			larger that strlen(buf), and buf can be changed
39657208Seric **			in place if desired.
39757208Seric **		av -- arguments from the config file (can be interpolated
39857208Seric **			into the final result).
39959084Seric **		statp -- pointer to status word (out-parameter).
40057208Seric **
40157208Seric **	Returns:
40257208Seric **		A pointer to the rewritten result.
40357208Seric **		NULL if not found in the map.
40457208Seric */
40557208Seric 
40657208Seric char *
40759084Seric nis_map_lookup(map, buf, bufsiz, av, statp)
40857208Seric 	MAP *map;
40957208Seric 	char buf[];
41057208Seric 	int bufsiz;
41157208Seric 	char **av;
41259084Seric 	int *statp;
41357208Seric {
41457208Seric 	char *vp;
41557642Seric 	auto int vsize;
416*59274Seric 	int buflen;
41757208Seric 
41857208Seric 	if (!bitset(MF_NOFOLDCASE, map->map_flags))
41957208Seric 	{
42057208Seric 		register char *p;
42157208Seric 
42257208Seric 		for (p = buf; *p != '\0'; p++)
42358050Seric 			if (isascii(*p) && isupper(*p))
42457208Seric 				*p = tolower(*p);
42557208Seric 	}
426*59274Seric 	buflen = strlen(buf);
427*59274Seric 	if (bitset(MF_INCLNULL, map->map_flags))
428*59274Seric 		buflen++;
429*59274Seric 	if (yp_match(map->map_domain, map->map_file, buf, buflen,
43057642Seric 		     &vp, &vsize) != 0)
43157208Seric 		return NULL;
43257208Seric 	if (!bitset(MF_MATCHONLY, map->map_flags))
43357208Seric 		map_rewrite(vp, vsize, buf, bufsiz, av);
43457208Seric 	return buf;
43557208Seric }
43657208Seric 
43757208Seric #endif /* NIS_MAP */
43857208Seric /*
43956822Seric **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
44056822Seric **
44156822Seric **	Parameters:
44256822Seric **		s -- the string to rewrite, NOT necessarily null terminated.
44356822Seric **		slen -- the length of s.
44456822Seric **		buf -- the place to write it.
44556822Seric **		buflen -- the length of buf.
44656822Seric **		av -- arguments to interpolate into buf.
44756822Seric **
44856822Seric **	Returns:
44956822Seric **		none.
45056822Seric **
45156822Seric **	Side Effects:
45256822Seric **		none.
45356822Seric */
45456822Seric 
45556822Seric map_rewrite(s, slen, buf, buflen, av)
45656822Seric 	register char *s;
45756822Seric 	int slen;
45856822Seric 	char buf[];
45956822Seric 	int buflen;
46056822Seric 	char **av;
46156822Seric {
46256822Seric 	register char *bp;
46356822Seric 	char *buflim;
46456822Seric 	register char c;
46556822Seric 	char **avp;
46656822Seric 	register char *ap;
46756822Seric 
46856822Seric 	if (tTd(23, 1))
46956822Seric 	{
47056822Seric 		printf("map_rewrite(%.*s), av =\n", slen, s);
47156822Seric 		for (avp = av; *avp != NULL; avp++)
47256822Seric 			printf("\t%s\n", *avp);
47356822Seric 	}
47456822Seric 
47556822Seric 	bp = buf;
47656822Seric 	buflim = &buf[buflen - 2];
47756822Seric 	while (--slen >= 0 && (c = *s++) != '\0')
47856822Seric 	{
47956822Seric 		if (c != '%')
48056822Seric 		{
48156822Seric   pushc:
48256822Seric 			if (bp < buflim)
48356822Seric 				*bp++ = c;
48456822Seric 			continue;
48556822Seric 		}
48656822Seric 		if (--slen < 0 || (c = *s++) == '\0')
48756822Seric 			c = '%';
48856822Seric 		if (c == '%')
48956822Seric 			goto pushc;
49058050Seric 		if (!(isascii(c) && isdigit(c)))
49156822Seric 		{
49256822Seric 			*bp++ = '%';
49356822Seric 			goto pushc;
49456822Seric 		}
49556822Seric 		c -= '0';
49656822Seric 		for (avp = av; --c >= 0 && *avp != NULL; avp++)
49756822Seric 			continue;
49856822Seric 		if (*avp == NULL)
49956822Seric 			continue;
50056822Seric 
50156822Seric 		/* transliterate argument into output string */
50256822Seric 		for (ap = *avp; (c = *ap++) != '\0'; )
50356822Seric 		{
50456822Seric 			if (bp < buflim)
50556822Seric 				*bp++ = c;
50656822Seric 		}
50756822Seric 	}
50856822Seric 	*bp++ = '\0';
50956822Seric 	if (tTd(23, 1))
51056822Seric 		printf("map_rewrite => %s\n", buf);
51156822Seric }
512