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