xref: /csrg-svn/usr.sbin/sendmail/src/map.c (revision 57252)
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.1 (Berkeley) 12/21/92";
11 #endif /* not lint */
12 
13 #include "sendmail.h"
14 #include <sys/file.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 (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 (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 (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' && !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' && !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 	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 (isupper(*p))
412 				*p = tolower(*p);
413 	}
414 	if (yp_match(map->map_domain, map->map_file, buf, bufsiz, &vp, &vsize) != 0)
415 		return NULL;
416 	if (!bitset(MF_MATCHONLY, map->map_flags))
417 		map_rewrite(vp, vsize, buf, bufsiz, av);
418 	return buf;
419 }
420 
421 #endif /* NIS_MAP */
422 /*
423 **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
424 **
425 **	Parameters:
426 **		s -- the string to rewrite, NOT necessarily null terminated.
427 **		slen -- the length of s.
428 **		buf -- the place to write it.
429 **		buflen -- the length of buf.
430 **		av -- arguments to interpolate into buf.
431 **
432 **	Returns:
433 **		none.
434 **
435 **	Side Effects:
436 **		none.
437 */
438 
439 map_rewrite(s, slen, buf, buflen, av)
440 	register char *s;
441 	int slen;
442 	char buf[];
443 	int buflen;
444 	char **av;
445 {
446 	register char *bp;
447 	char *buflim;
448 	register char c;
449 	char **avp;
450 	register char *ap;
451 
452 	if (tTd(23, 1))
453 	{
454 		printf("map_rewrite(%.*s), av =\n", slen, s);
455 		for (avp = av; *avp != NULL; avp++)
456 			printf("\t%s\n", *avp);
457 	}
458 
459 	bp = buf;
460 	buflim = &buf[buflen - 2];
461 	while (--slen >= 0 && (c = *s++) != '\0')
462 	{
463 		if (c != '%')
464 		{
465   pushc:
466 			if (bp < buflim)
467 				*bp++ = c;
468 			continue;
469 		}
470 		if (--slen < 0 || (c = *s++) == '\0')
471 			c = '%';
472 		if (c == '%')
473 			goto pushc;
474 		if (!isdigit(c))
475 		{
476 			*bp++ = '%';
477 			goto pushc;
478 		}
479 		c -= '0';
480 		for (avp = av; --c >= 0 && *avp != NULL; avp++)
481 			continue;
482 		if (*avp == NULL)
483 			continue;
484 
485 		/* transliterate argument into output string */
486 		for (ap = *avp; (c = *ap++) != '\0'; )
487 		{
488 			if (bp < buflim)
489 				*bp++ = c;
490 		}
491 	}
492 	*bp++ = '\0';
493 	if (tTd(23, 1))
494 		printf("map_rewrite => %s\n", buf);
495 }
496