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