xref: /original-bsd/usr.sbin/sendmail/src/map.c (revision 42acfcb0)
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.10 (Berkeley) 04/26/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 #include <db.h>
20 #endif
21 #ifdef NIS_MAP
22 #include <rpcsvc/ypclnt.h>
23 #endif
24 
25 
26 #ifdef DBM_MAP
27 
28 /*
29 **  DBM_MAP_INIT -- DBM-style map initialization
30 **
31 **	Parameters:
32 **		map -- the pointer to the actual map
33 **		mapname -- the name of the map (for error messages)
34 **		args -- a pointer to the config file line arguments
35 **
36 **	Returns:
37 **		TRUE -- if it could successfully open the map.
38 **		FALSE -- otherwise.
39 **
40 **	Side Effects:
41 **		Gives an error if it can't open the map.
42 */
43 
44 bool
45 dbm_map_init(map, mapname, args)
46 	MAP *map;
47 	char *mapname;
48 	char *args;
49 {
50 	DBM *dbm;
51 
52 	map_parseargs(map, &args);
53 	if (map->map_file == NULL)
54 	{
55 		syserr("No file name for DBM map %s", mapname);
56 		return FALSE;
57 	}
58 	dbm = dbm_open(map->map_file, O_RDONLY, 0644);
59 	if (dbm == NULL)
60 	{
61 		if (!bitset(MF_OPTIONAL, map->map_flags))
62 			syserr("Cannot open DBM database %s", map->map_file);
63 		return FALSE;
64 	}
65 	map->map_db = (void *) dbm;
66 	return TRUE;
67 }
68 /*
69 **  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
70 **
71 **	Parameters:
72 **		map -- the map to look up in.
73 **		buf -- a pointer to to the buffer containing the key.
74 **			This is a null terminated string.
75 **		bufsiz -- the size of buf -- note that this is in general
76 **			larger that strlen(buf), and buf can be changed
77 **			in place if desired.
78 **		av -- arguments from the config file (can be interpolated
79 **			into the final result).
80 **		statp -- pointer to status word (out-parameter).
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, statp)
89 	MAP *map;
90 	char buf[];
91 	int bufsiz;
92 	char **av;
93 	int *statp;
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 (isascii(*p) && 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 **		statp -- pointer to status word (out-parameter).
224 **
225 **	Returns:
226 **		A pointer to the rewritten result.
227 **		NULL if not found in the map.
228 */
229 
230 char *
231 db_map_lookup(map, buf, bufsiz, av, statp)
232 	MAP *map;
233 	char buf[];
234 	int bufsiz;
235 	char **av;
236 	int *statp;
237 {
238 	DBT key, val;
239 
240 	key.data = buf;
241 	key.size = strlen(buf);
242 	if (!bitset(MF_NOFOLDCASE, map->map_flags))
243 	{
244 		register char *p;
245 
246 		for (p = buf; *p != '\0'; p++)
247 			if (isascii(*p) && isupper(*p))
248 				*p = tolower(*p);
249 	}
250 	if (bitset(MF_INCLNULL, map->map_flags))
251 		key.size++;
252 	if (((DB *) map->map_db)->get((DB *) map->map_db, &key, &val, 0) != 0)
253 		return NULL;
254 	if (!bitset(MF_MATCHONLY, map->map_flags))
255 		map_rewrite(val.data, val.size, buf, bufsiz, av);
256 	return buf;
257 }
258 
259 #endif /* BTREE_MAP || HASH_MAP */
260 /*
261 **  MAP_PARSEARGS -- parse config line arguments for database lookup
262 **
263 **	Parameters:
264 **		map -- the map being initialized.
265 **		pp -- an indirect pointer to the config line.  It will
266 **			be replaced with a pointer to the next field
267 **			on the line.
268 **
269 **	Returns:
270 **		none
271 **
272 **	Side Effects:
273 **		null terminates the filename; stores it in map
274 */
275 
276 map_parseargs(map, pp)
277 	MAP *map;
278 	char **pp;
279 {
280 	register char *p = *pp;
281 
282 	for (;;)
283 	{
284 		while (isascii(*p) && isspace(*p))
285 			p++;
286 		if (*p != '-')
287 			break;
288 		switch (*++p)
289 		{
290 		  case 'N':
291 			map->map_flags |= MF_INCLNULL;
292 			break;
293 
294 		  case 'o':
295 			map->map_flags |= MF_OPTIONAL;
296 			break;
297 
298 		  case 'f':
299 			map->map_flags |= MF_NOFOLDCASE;
300 			break;
301 
302 		  case 'm':
303 			map->map_flags |= MF_MATCHONLY;
304 			break;
305 
306 		  case 'a':
307 			map->map_app = ++p;
308 			break;
309 
310 		  case 'd':
311 			map->map_domain = ++p;
312 			break;
313 		}
314 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
315 			p++;
316 		if (*p != '\0')
317 			*p++ = '\0';
318 	}
319 	if (map->map_app != NULL)
320 		map->map_app = newstr(map->map_app);
321 	if (map->map_domain != NULL)
322 		map->map_domain = newstr(map->map_domain);
323 
324 	if (*p != '\0')
325 	{
326 		map->map_file = p;
327 		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
328 			p++;
329 		if (*p != '\0')
330 			*p++ = '\0';
331 		map->map_file = newstr(map->map_file);
332 	}
333 
334 	while (*p != '\0' && isascii(*p) && isspace(*p))
335 		p++;
336 	*pp = p;
337 	if (*p != '\0')
338 		map->map_rebuild = newstr(p);
339 }
340 
341 # ifdef NIS_MAP
342 
343 /*
344 **  NIS_MAP_INIT -- initialize DBM map
345 **
346 **	Parameters:
347 **		map -- the pointer to the actual map.
348 **		mapname -- the name of the map (for error messages).
349 **		args -- a pointer to the config file line arguments.
350 **
351 **	Returns:
352 **		TRUE -- if it could successfully open the map.
353 **		FALSE -- otherwise.
354 **
355 **	Side Effects:
356 **		Prints an error if it can't open the map.
357 */
358 
359 bool
360 nis_map_init(map, mapname, args)
361 	MAP *map;
362 	char *mapname;
363 	char *args;
364 {
365 	int yperr;
366 	char *master;
367 
368 	/* parse arguments */
369 	map_parseargs(map, &args);
370 	if (map->map_file == NULL)
371 	{
372 		syserr("No NIS map name for map %s", mapname);
373 		return FALSE;
374 	}
375 	if (map->map_domain == NULL)
376 		yp_get_default_domain(&map->map_domain);
377 
378 	/* check to see if this map actually exists */
379 	yperr = yp_master(map->map_domain, map->map_file, &master);
380 	if (yperr == 0)
381 		return TRUE;
382 	if (!bitset(MF_OPTIONAL, map->map_flags))
383 		syserr("Cannot bind to domain %s: %s", map->map_domain,
384 			yperr_string(yperr));
385 	return FALSE;
386 }
387 /*
388 **  NIS_MAP_LOOKUP -- look up a datum in a NIS map
389 **
390 **	Parameters:
391 **		map -- the map to look up in.
392 **		buf -- a pointer to to the buffer containing the key.
393 **			This is a null terminated string.
394 **		bufsiz -- the size of buf -- note that this is in general
395 **			larger that strlen(buf), and buf can be changed
396 **			in place if desired.
397 **		av -- arguments from the config file (can be interpolated
398 **			into the final result).
399 **		statp -- pointer to status word (out-parameter).
400 **
401 **	Returns:
402 **		A pointer to the rewritten result.
403 **		NULL if not found in the map.
404 */
405 
406 char *
407 nis_map_lookup(map, buf, bufsiz, av, statp)
408 	MAP *map;
409 	char buf[];
410 	int bufsiz;
411 	char **av;
412 	int *statp;
413 {
414 	char *vp;
415 	auto int vsize;
416 	int buflen;
417 
418 	if (!bitset(MF_NOFOLDCASE, map->map_flags))
419 	{
420 		register char *p;
421 
422 		for (p = buf; *p != '\0'; p++)
423 			if (isascii(*p) && isupper(*p))
424 				*p = tolower(*p);
425 	}
426 	buflen = strlen(buf);
427 	if (bitset(MF_INCLNULL, map->map_flags))
428 		buflen++;
429 	if (yp_match(map->map_domain, map->map_file, buf, buflen,
430 		     &vp, &vsize) != 0)
431 		return NULL;
432 	if (!bitset(MF_MATCHONLY, map->map_flags))
433 		map_rewrite(vp, vsize, buf, bufsiz, av);
434 	return buf;
435 }
436 
437 #endif /* NIS_MAP */
438 /*
439 **  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
440 **
441 **	Parameters:
442 **		s -- the string to rewrite, NOT necessarily null terminated.
443 **		slen -- the length of s.
444 **		buf -- the place to write it.
445 **		buflen -- the length of buf.
446 **		av -- arguments to interpolate into buf.
447 **
448 **	Returns:
449 **		none.
450 **
451 **	Side Effects:
452 **		none.
453 */
454 
455 map_rewrite(s, slen, buf, buflen, av)
456 	register char *s;
457 	int slen;
458 	char buf[];
459 	int buflen;
460 	char **av;
461 {
462 	register char *bp;
463 	char *buflim;
464 	register char c;
465 	char **avp;
466 	register char *ap;
467 
468 	if (tTd(23, 1))
469 	{
470 		printf("map_rewrite(%.*s), av =\n", slen, s);
471 		for (avp = av; *avp != NULL; avp++)
472 			printf("\t%s\n", *avp);
473 	}
474 
475 	bp = buf;
476 	buflim = &buf[buflen - 2];
477 	while (--slen >= 0 && (c = *s++) != '\0')
478 	{
479 		if (c != '%')
480 		{
481   pushc:
482 			if (bp < buflim)
483 				*bp++ = c;
484 			continue;
485 		}
486 		if (--slen < 0 || (c = *s++) == '\0')
487 			c = '%';
488 		if (c == '%')
489 			goto pushc;
490 		if (!(isascii(c) && isdigit(c)))
491 		{
492 			*bp++ = '%';
493 			goto pushc;
494 		}
495 		c -= '0';
496 		for (avp = av; --c >= 0 && *avp != NULL; avp++)
497 			continue;
498 		if (*avp == NULL)
499 			continue;
500 
501 		/* transliterate argument into output string */
502 		for (ap = *avp; (c = *ap++) != '\0'; )
503 		{
504 			if (bp < buflim)
505 				*bp++ = c;
506 		}
507 	}
508 	*bp++ = '\0';
509 	if (tTd(23, 1))
510 		printf("map_rewrite => %s\n", buf);
511 }
512