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