xref: /original-bsd/usr.sbin/sendmail/src/map.c (revision 4a884f8b)
1 /*
2  * Copyright (c) 1992 Eric P. Allman.
3  * Copyright (c) 1992 Regents of the University of California.
4  * All rights reserved.
5  *
6  * %sccs.include.redist.c%
7  */
8 
9 #ifndef lint
10 static char sccsid[] = "@(#)map.c	6.5 (Berkeley) 02/18/93";
11 #endif /* not lint */
12 
13 #include "sendmail.h"
14 #include <fcntl.h>
15 
16 #ifdef DBM_MAP
17 #include <ndbm.h>
18 #endif
19 #if defined(HASH_MAP) || defined(BTREE_MAP)
20 #include <db.h>
21 #endif
22 #ifdef NIS_MAP
23 #include <rpcsvc/ypclnt.h>
24 #endif
25 
26 
27 #ifdef DBM_MAP
28 
29 /*
30 **  DBM_MAP_INIT -- DBM-style map initialization
31 **
32 **	Parameters:
33 **		map -- the pointer to the actual map
34 **		mapname -- the name of the map (for error messages)
35 **		args -- a pointer to the config file line arguments
36 **
37 **	Returns:
38 **		TRUE -- if it could successfully open the map.
39 **		FALSE -- otherwise.
40 **
41 **	Side Effects:
42 **		Gives an error if it can't open the map.
43 */
44 
45 bool
46 dbm_map_init(map, mapname, args)
47 	MAP *map;
48 	char *mapname;
49 	char *args;
50 {
51 	DBM *dbm;
52 
53 	map_parseargs(map, &args);
54 	if (map->map_file == NULL)
55 	{
56 		syserr("No file name for DBM map %s", mapname);
57 		return FALSE;
58 	}
59 	dbm = dbm_open(map->map_file, O_RDONLY, 0644);
60 	if (dbm == NULL)
61 	{
62 		if (!bitset(MF_OPTIONAL, map->map_flags))
63 			syserr("Cannot open DBM database %s", map->map_file);
64 		return FALSE;
65 	}
66 	map->map_db = (void *) dbm;
67 	return TRUE;
68 }
69 /*
70 **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
71 **
72 **	Parameters:
73 **		map -- the map to look up in.
74 **		buf -- a pointer to to the buffer containing the key.
75 **			This is a null terminated string.
76 **		bufsiz -- the size of buf -- note that this is in general
77 **			larger that strlen(buf), and buf can be changed
78 **			in place if desired.
79 **		av -- arguments from the config file (can be interpolated
80 **			into the final result).
81 **
82 **	Returns:
83 **		A pointer to the rewritten result.
84 **		NULL if not found in the map.
85 */
86 
87 char *
88 dbm_map_lookup(map, buf, bufsiz, av)
89 	MAP *map;
90 	char buf[];
91 	int bufsiz;
92 	char **av;
93 {
94 	datum key, val;
95 
96 	key.dptr = buf;
97 	key.dsize = strlen(buf);
98 	if (!bitset(MF_NOFOLDCASE, map->map_flags))
99 	{
100 		register char *p;
101 
102 		for (p = buf; *p != '\0'; p++)
103 			if (isascii(*p) && isupper(*p))
104 				*p = tolower(*p);
105 	}
106 	if (bitset(MF_INCLNULL, map->map_flags))
107 		key.dsize++;
108 	val = dbm_fetch(map->map_db, key);
109 	if (val.dptr == NULL)
110 		return NULL;
111 	if (!bitset(MF_MATCHONLY, map->map_flags))
112 		map_rewrite(val.dptr, val.dsize, buf, bufsiz, av);
113 	return buf;
114 }
115 
116 #endif /* DBM_MAP */
117 
118 #ifdef BTREE_MAP
119 
120 /*
121 **  BTREE_MAP_INIT -- BTREE-style map initialization
122 **
123 **	Parameters:
124 **		map -- the pointer to the actual map
125 **		mapname -- the name of the map (for error messages)
126 **		args -- a pointer to the config file line arguments
127 **
128 **	Returns:
129 **		TRUE -- if it could successfully open the map.
130 **		FALSE -- otherwise.
131 **
132 **	Side Effects:
133 **		Gives an error if it can't open the map.
134 */
135 
136 bool
137 bt_map_init(map, mapname, args)
138 	MAP *map;
139 	char *mapname;
140 	char *args;
141 {
142 	DB *db;
143 
144 	map_parseargs(map, &args);
145 	if (map->map_file == NULL)
146 	{
147 		syserr("No file name for BTREE map %s", mapname);
148 		return FALSE;
149 	}
150 	db = dbopen(map->map_file, O_RDONLY, 0644, DB_BTREE, NULL);
151 	if (db == NULL)
152 	{
153 		if (!bitset(MF_OPTIONAL, map->map_flags))
154 			syserr("Cannot open BTREE database %s", map->map_file);
155 		return FALSE;
156 	}
157 	map->map_db = (void *) db;
158 	return TRUE;
159 }
160 
161 #endif /* BTREE_MAP */
162 
163 #ifdef HASH_MAP
164 
165 /*
166 **  HASH_MAP_INIT -- HASH-style map initialization
167 **
168 **	Parameters:
169 **		map -- the pointer to the actual map
170 **		mapname -- the name of the map (for error messages)
171 **		args -- a pointer to the config file line arguments
172 **
173 **	Returns:
174 **		TRUE -- if it could successfully open the map.
175 **		FALSE -- otherwise.
176 **
177 **	Side Effects:
178 **		Gives an error if it can't open the map.
179 */
180 
181 bool
182 hash_map_init(map, mapname, args)
183 	MAP *map;
184 	char *mapname;
185 	char *args;
186 {
187 	DB *db;
188 
189 	map_parseargs(map, &args);
190 	if (map->map_file == NULL)
191 	{
192 		syserr("No file name for HASH map %s", mapname);
193 		return FALSE;
194 	}
195 	db = dbopen(map->map_file, O_RDONLY, 0644, DB_HASH, NULL);
196 	if (db == NULL)
197 	{
198 		if (!bitset(MF_OPTIONAL, map->map_flags))
199 			syserr("Cannot open HASH database %s", map->map_file);
200 		return FALSE;
201 	}
202 	map->map_db = (void *) db;
203 	return TRUE;
204 }
205 
206 #endif /* HASH_MAP */
207 
208 #if defined(BTREE_MAP) || defined(HASH_MAP)
209 
210 /*
211 **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
212 **
213 **	Parameters:
214 **		map -- the map to look up in.
215 **		buf -- a pointer to to the buffer containing the key.
216 **			This is a null terminated string.
217 **		bufsiz -- the size of buf -- note that this is in general
218 **			larger that strlen(buf), and buf can be changed
219 **			in place if desired.
220 **		av -- arguments from the config file (can be interpolated
221 **			into the final result).
222 **
223 **	Returns:
224 **		A pointer to the rewritten result.
225 **		NULL if not found in the map.
226 */
227 
228 char *
229 db_map_lookup(map, buf, bufsiz, av)
230 	MAP *map;
231 	char buf[];
232 	int bufsiz;
233 	char **av;
234 {
235 	DBT key, val;
236 
237 	key.data = buf;
238 	key.size = strlen(buf);
239 	if (!bitset(MF_NOFOLDCASE, map->map_flags))
240 	{
241 		register char *p;
242 
243 		for (p = buf; *p != '\0'; p++)
244 			if (isascii(*p) && isupper(*p))
245 				*p = tolower(*p);
246 	}
247 	if (bitset(MF_INCLNULL, map->map_flags))
248 		key.size++;
249 	if (((DB *) map->map_db)->get((DB *) map->map_db, &key, &val, 0) != 0)
250 		return NULL;
251 	if (!bitset(MF_MATCHONLY, map->map_flags))
252 		map_rewrite(val.data, val.size, buf, bufsiz, av);
253 	return buf;
254 }
255 
256 #endif /* BTREE_MAP || HASH_MAP */
257 /*
258 **  MAP_PARSEARGS -- parse config line arguments for database lookup
259 **
260 **	Parameters:
261 **		map -- the map being initialized.
262 **		pp -- an indirect pointer to the config line.  It will
263 **			be replaced with a pointer to the next field
264 **			on the line.
265 **
266 **	Returns:
267 **		none
268 **
269 **	Side Effects:
270 **		null terminates the filename; stores it in map
271 */
272 
273 map_parseargs(map, pp)
274 	MAP *map;
275 	char **pp;
276 {
277 	register char *p = *pp;
278 
279 	for (;;)
280 	{
281 		while (isascii(*p) && isspace(*p))
282 			p++;
283 		if (*p != '-')
284 			break;
285 		switch (*++p)
286 		{
287 		  case 'N':
288 			map->map_flags |= MF_INCLNULL;
289 			break;
290 
291 		  case 'o':
292 			map->map_flags |= MF_OPTIONAL;
293 			break;
294 
295 		  case 'f':
296 			map->map_flags |= MF_NOFOLDCASE;
297 			break;
298 
299 		  case 'm':
300 			map->map_flags |= MF_MATCHONLY;
301 			break;
302 
303 		  case 'a':
304 			map->map_app = ++p;
305 			break;
306 
307 		  case 'd':
308 			map->map_domain = ++p;
309 			break;
310 		}
311 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
312 			p++;
313 		if (*p != '\0')
314 			*p++ = 0;
315 	}
316 	if (map->map_app != NULL)
317 		map->map_app = newstr(map->map_app);
318 	if (map->map_domain != NULL)
319 		map->map_domain = newstr(map->map_domain);
320 
321 	if (*p == '\0')
322 		return NULL;
323 	map->map_file = p;
324 	while (*p != '\0' && !(isascii(*p) && isspace(*p)))
325 		p++;
326 	if (*p != '\0')
327 		*p++ = '\0';
328 	map->map_file = newstr(map->map_file);
329 	*pp = p;
330 }
331 
332 # ifdef NIS_MAP
333 
334 /*
335 **  NIS_MAP_INIT -- initialize DBM map
336 **
337 **	Parameters:
338 **		map -- the pointer to the actual map.
339 **		mapname -- the name of the map (for error messages).
340 **		args -- a pointer to the config file line arguments.
341 **
342 **	Returns:
343 **		TRUE -- if it could successfully open the map.
344 **		FALSE -- otherwise.
345 **
346 **	Side Effects:
347 **		Prints an error if it can't open the map.
348 */
349 
350 bool
351 nis_map_init(map, mapname, args)
352 	MAP *map;
353 	char *mapname;
354 	char *args;
355 {
356 	int yperr;
357 	char *master;
358 
359 	/* parse arguments */
360 	map_parseargs(map, &args);
361 	if (map->map_file == NULL)
362 	{
363 		syserr("No NIS map name for map %s", mapname);
364 		return FALSE;
365 	}
366 	if (map->map_domain == NULL)
367 		yp_get_default_domain(&map->map_domain);
368 
369 	/* check to see if this map actually exists */
370 	yperr = yp_master(map->map_domain, map->map_file, &master);
371 	if (yperr == 0)
372 		return TRUE;
373 	if (!bitset(MF_OPTIONAL, map->map_flags))
374 		syserr("Cannot bind to domain %s: %s", map->map_domain,
375 			yperr_string(yperr));
376 	return FALSE;
377 }
378 /*
379 **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
380 **
381 **	Parameters:
382 **		map -- the map to look up in.
383 **		buf -- a pointer to to the buffer containing the key.
384 **			This is a null terminated string.
385 **		bufsiz -- the size of buf -- note that this is in general
386 **			larger that strlen(buf), and buf can be changed
387 **			in place if desired.
388 **		av -- arguments from the config file (can be interpolated
389 **			into the final result).
390 **
391 **	Returns:
392 **		A pointer to the rewritten result.
393 **		NULL if not found in the map.
394 */
395 
396 char *
397 nis_map_lookup(map, buf, bufsiz, av)
398 	MAP *map;
399 	char buf[];
400 	int bufsiz;
401 	char **av;
402 {
403 	char *vp;
404 	auto int vsize;
405 
406 	if (!bitset(MF_NOFOLDCASE, map->map_flags))
407 	{
408 		register char *p;
409 
410 		for (p = buf; *p != '\0'; p++)
411 			if (isascii(*p) && isupper(*p))
412 				*p = tolower(*p);
413 	}
414 	if (yp_match(map->map_domain, map->map_file, buf, strlen(buf) + 1,
415 		     &vp, &vsize) != 0)
416 		return NULL;
417 	if (!bitset(MF_MATCHONLY, map->map_flags))
418 		map_rewrite(vp, vsize, buf, bufsiz, av);
419 	return buf;
420 }
421 
422 #endif /* NIS_MAP */
423 /*
424 **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
425 **
426 **	Parameters:
427 **		s -- the string to rewrite, NOT necessarily null terminated.
428 **		slen -- the length of s.
429 **		buf -- the place to write it.
430 **		buflen -- the length of buf.
431 **		av -- arguments to interpolate into buf.
432 **
433 **	Returns:
434 **		none.
435 **
436 **	Side Effects:
437 **		none.
438 */
439 
440 map_rewrite(s, slen, buf, buflen, av)
441 	register char *s;
442 	int slen;
443 	char buf[];
444 	int buflen;
445 	char **av;
446 {
447 	register char *bp;
448 	char *buflim;
449 	register char c;
450 	char **avp;
451 	register char *ap;
452 
453 	if (tTd(23, 1))
454 	{
455 		printf("map_rewrite(%.*s), av =\n", slen, s);
456 		for (avp = av; *avp != NULL; avp++)
457 			printf("\t%s\n", *avp);
458 	}
459 
460 	bp = buf;
461 	buflim = &buf[buflen - 2];
462 	while (--slen >= 0 && (c = *s++) != '\0')
463 	{
464 		if (c != '%')
465 		{
466   pushc:
467 			if (bp < buflim)
468 				*bp++ = c;
469 			continue;
470 		}
471 		if (--slen < 0 || (c = *s++) == '\0')
472 			c = '%';
473 		if (c == '%')
474 			goto pushc;
475 		if (!(isascii(c) && isdigit(c)))
476 		{
477 			*bp++ = '%';
478 			goto pushc;
479 		}
480 		c -= '0';
481 		for (avp = av; --c >= 0 && *avp != NULL; avp++)
482 			continue;
483 		if (*avp == NULL)
484 			continue;
485 
486 		/* transliterate argument into output string */
487 		for (ap = *avp; (c = *ap++) != '\0'; )
488 		{
489 			if (bp < buflim)
490 				*bp++ = c;
491 		}
492 	}
493 	*bp++ = '\0';
494 	if (tTd(23, 1))
495 		printf("map_rewrite => %s\n", buf);
496 }
497