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