improved implementation for E line -- slightly cleaner -- plus
[unix-history] / usr / src / usr.sbin / sendmail / src / map.c
CommitLineData
4cb3af58 1/*
792e6158 2 * Copyright (c) 1992, 1995 Eric P. Allman.
eb0bafab
KB
3 * Copyright (c) 1992, 1993
4 * The Regents of the University of California. All rights reserved.
4cb3af58
EA
5 *
6 * %sccs.include.redist.c%
7 */
8
9#ifndef lint
14e29bd9 10static char sccsid[] = "@(#)map.c 8.60 (Berkeley) %G%";
4cb3af58
EA
11#endif /* not lint */
12
13#include "sendmail.h"
4cb3af58 14
713c523f 15#ifdef NDBM
aa2a7788 16# include <ndbm.h>
4cb3af58 17#endif
713c523f 18#ifdef NEWDB
aa2a7788 19# include <db.h>
4cb3af58 20#endif
713c523f 21#ifdef NIS
c0640f89 22 struct dom_binding { int dummy; }; /* needed on IRIX */
aa2a7788 23# include <rpcsvc/ypclnt.h>
33844dcf 24#endif
4cb3af58 25
4cb3af58 26/*
713c523f 27** MAP.C -- implementations for various map classes.
4cb3af58 28**
713c523f 29** Each map class implements a series of functions:
4cb3af58 30**
713c523f
EA
31** bool map_parse(MAP *map, char *args)
32** Parse the arguments from the config file. Return TRUE
33** if they were ok, FALSE otherwise. Fill in map with the
34** values.
4cb3af58 35**
f500979e
EA
36** char *map_lookup(MAP *map, char *key, char **args, int *pstat)
37** Look up the key in the given map. If found, do any
38** rewriting the map wants (including "args" if desired)
713c523f 39** and return the value. Set *pstat to the appropriate status
f500979e
EA
40** on error and return NULL. Args will be NULL if called
41** from the alias routines, although this should probably
42** not be relied upon. It is suggested you call map_rewrite
43** to return the results -- it takes care of null termination
44** and uses a dynamically expanded buffer as needed.
4cb3af58 45**
713c523f
EA
46** void map_store(MAP *map, char *key, char *value)
47** Store the key:value pair in the map.
4cb3af58 48**
713c523f 49** bool map_open(MAP *map, int mode)
f500979e
EA
50** Open the map for the indicated mode. Mode should
51** be either O_RDONLY or O_RDWR. Return TRUE if it
52** was opened successfully, FALSE otherwise. If the open
53** failed an the MF_OPTIONAL flag is not set, it should
54** also print an error. If the MF_ALIAS bit is set
55** and this map class understands the @:@ convention, it
56** should call aliaswait() before returning.
4cb3af58 57**
713c523f
EA
58** void map_close(MAP *map)
59** Close the map.
f0416b32
EA
60**
61** This file also includes the implementation for getcanonname.
62** It is currently implemented in a pretty ad-hoc manner; it ought
63** to be more properly integrated into the map structure.
4cb3af58
EA
64*/
65
713c523f 66#define DBMMODE 0644
fe3849ea
EA
67
68extern bool aliaswait __P((MAP *, char *, int));
4cb3af58
EA
69\f/*
70** MAP_PARSEARGS -- parse config line arguments for database lookup
71**
713c523f
EA
72** This is a generic version of the map_parse method.
73**
4cb3af58
EA
74** Parameters:
75** map -- the map being initialized.
713c523f 76** ap -- a pointer to the args on the config line.
4cb3af58
EA
77**
78** Returns:
713c523f
EA
79** TRUE -- if everything parsed OK.
80** FALSE -- otherwise.
4cb3af58
EA
81**
82** Side Effects:
83** null terminates the filename; stores it in map
84*/
85
713c523f
EA
86bool
87map_parseargs(map, ap)
4cb3af58 88 MAP *map;
713c523f 89 char *ap;
4cb3af58 90{
713c523f 91 register char *p = ap;
4cb3af58 92
8e5c6745 93 map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
4cb3af58
EA
94 for (;;)
95 {
2bee003d 96 while (isascii(*p) && isspace(*p))
4cb3af58
EA
97 p++;
98 if (*p != '-')
99 break;
100 switch (*++p)
101 {
102 case 'N':
31f1ab13 103 map->map_mflags |= MF_INCLNULL;
8e5c6745
EA
104 map->map_mflags &= ~MF_TRY0NULL;
105 break;
106
107 case 'O':
108 map->map_mflags &= ~MF_TRY1NULL;
4cb3af58 109 break;
32fd13db
EA
110
111 case 'o':
31f1ab13 112 map->map_mflags |= MF_OPTIONAL;
32fd13db
EA
113 break;
114
c58eb4cc 115 case 'f':
31f1ab13 116 map->map_mflags |= MF_NOFOLDCASE;
c58eb4cc
EA
117 break;
118
33844dcf 119 case 'm':
31f1ab13 120 map->map_mflags |= MF_MATCHONLY;
33844dcf
EA
121 break;
122
63ad0236
EA
123 case 'A':
124 map->map_mflags |= MF_APPEND;
125 break;
126
32fd13db
EA
127 case 'a':
128 map->map_app = ++p;
129 break;
e7f5a48c
EA
130
131 case 'k':
132 while (isascii(*++p) && isspace(*p))
133 continue;
134 map->map_keycolnm = p;
135 break;
136
137 case 'v':
138 while (isascii(*++p) && isspace(*p))
139 continue;
140 map->map_valcolnm = p;
141 break;
142
143 case 'z':
144 if (*++p != '\\')
145 map->map_coldelim = *p;
146 else
147 {
148 switch (*++p)
149 {
150 case 'n':
151 map->map_coldelim = '\n';
152 break;
153
154 case 't':
155 map->map_coldelim = '\t';
156 break;
157
158 default:
159 map->map_coldelim = '\\';
160 }
161 }
162 break;
63ad0236
EA
163#ifdef RESERVED_FOR_SUN
164 case 'd':
165 map->map_mflags |= MF_DOMAIN_WIDE;
166 break;
167
168 case 's':
169 /* info type */
170 break;
171#endif
4cb3af58 172 }
2bee003d 173 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
4cb3af58 174 p++;
32fd13db 175 if (*p != '\0')
4aaafa33 176 *p++ = '\0';
4cb3af58 177 }
32fd13db
EA
178 if (map->map_app != NULL)
179 map->map_app = newstr(map->map_app);
e7f5a48c
EA
180 if (map->map_keycolnm != NULL)
181 map->map_keycolnm = newstr(map->map_keycolnm);
182 if (map->map_valcolnm != NULL)
183 map->map_valcolnm = newstr(map->map_valcolnm);
4cb3af58 184
4cb3af58 185 if (*p != '\0')
4aaafa33
EA
186 {
187 map->map_file = p;
188 while (*p != '\0' && !(isascii(*p) && isspace(*p)))
189 p++;
190 if (*p != '\0')
191 *p++ = '\0';
192 map->map_file = newstr(map->map_file);
193 }
cc047d90
EA
194
195 while (*p != '\0' && isascii(*p) && isspace(*p))
196 p++;
cc047d90
EA
197 if (*p != '\0')
198 map->map_rebuild = newstr(p);
33844dcf 199
58831f23
EA
200 if (map->map_file == NULL &&
201 !bitset(MCF_OPTFILE, map->map_class->map_cflags))
33844dcf 202 {
713c523f
EA
203 syserr("No file name for %s map %s",
204 map->map_class->map_cname, map->map_mname);
33844dcf
EA
205 return FALSE;
206 }
713c523f 207 return TRUE;
33844dcf 208}
4cb3af58
EA
209\f/*
210** MAP_REWRITE -- rewrite a database key, interpolating %n indications.
211**
713c523f
EA
212** It also adds the map_app string. It can be used as a utility
213** in the map_lookup method.
214**
4cb3af58 215** Parameters:
713c523f 216** map -- the map that causes this.
4cb3af58
EA
217** s -- the string to rewrite, NOT necessarily null terminated.
218** slen -- the length of s.
4cb3af58
EA
219** av -- arguments to interpolate into buf.
220**
221** Returns:
ec645560
EA
222** Pointer to rewritten result. This is static data that
223** should be copied if it is to be saved!
4cb3af58
EA
224**
225** Side Effects:
226** none.
227*/
228
67d3f5c1
EA
229struct rwbuf
230{
231 int rwb_len; /* size of buffer */
232 char *rwb_buf; /* ptr to buffer */
233};
234
235struct rwbuf RwBufs[2]; /* buffers for rewriting output */
236
713c523f
EA
237char *
238map_rewrite(map, s, slen, av)
239 register MAP *map;
4cb3af58
EA
240 register char *s;
241 int slen;
4cb3af58
EA
242 char **av;
243{
244 register char *bp;
4cb3af58
EA
245 register char c;
246 char **avp;
247 register char *ap;
67d3f5c1 248 register struct rwbuf *rwb;
713c523f
EA
249 int i;
250 int len;
4cb3af58 251
36b09297 252 if (tTd(39, 1))
4cb3af58 253 {
eb76c0ac
EA
254 printf("map_rewrite(%.*s), av =", slen, s);
255 if (av == NULL)
256 printf(" (nullv)");
257 else
258 {
259 for (avp = av; *avp != NULL; avp++)
260 printf("\n\t%s", *avp);
261 }
262 printf("\n");
4cb3af58
EA
263 }
264
67d3f5c1
EA
265 rwb = RwBufs;
266 if (av == NULL)
267 rwb++;
268
713c523f
EA
269 /* count expected size of output (can safely overestimate) */
270 i = len = slen;
271 if (av != NULL)
272 {
273 bp = s;
274 for (i = slen; --i >= 0 && (c = *bp++) != 0; )
275 {
276 if (c != '%')
277 continue;
278 if (--i < 0)
279 break;
280 c = *bp++;
281 if (!(isascii(c) && isdigit(c)))
282 continue;
e6cb9fc4 283 for (avp = av; --c >= '0' && *avp != NULL; avp++)
713c523f
EA
284 continue;
285 if (*avp == NULL)
286 continue;
287 len += strlen(*avp);
288 }
289 }
290 if (map->map_app != NULL)
291 len += strlen(map->map_app);
67d3f5c1 292 if (rwb->rwb_len < ++len)
713c523f
EA
293 {
294 /* need to malloc additional space */
67d3f5c1
EA
295 rwb->rwb_len = len;
296 if (rwb->rwb_buf != NULL)
297 free(rwb->rwb_buf);
298 rwb->rwb_buf = xalloc(rwb->rwb_len);
713c523f
EA
299 }
300
67d3f5c1 301 bp = rwb->rwb_buf;
713c523f
EA
302 if (av == NULL)
303 {
304 bcopy(s, bp, slen);
305 bp += slen;
306 }
307 else
4cb3af58 308 {
713c523f 309 while (--slen >= 0 && (c = *s++) != '\0')
4cb3af58 310 {
713c523f
EA
311 if (c != '%')
312 {
4cb3af58 313 pushc:
4cb3af58 314 *bp++ = c;
713c523f
EA
315 continue;
316 }
317 if (--slen < 0 || (c = *s++) == '\0')
318 c = '%';
319 if (c == '%')
320 goto pushc;
321 if (!(isascii(c) && isdigit(c)))
322 {
323 *bp++ = '%';
324 goto pushc;
325 }
e6cb9fc4 326 for (avp = av; --c >= '0' && *avp != NULL; avp++)
713c523f
EA
327 continue;
328 if (*avp == NULL)
329 continue;
330
331 /* transliterate argument into output string */
332 for (ap = *avp; (c = *ap++) != '\0'; )
4cb3af58
EA
333 *bp++ = c;
334 }
335 }
713c523f
EA
336 if (map->map_app != NULL)
337 strcpy(bp, map->map_app);
338 else
339 *bp = '\0';
36b09297 340 if (tTd(39, 1))
67d3f5c1
EA
341 printf("map_rewrite => %s\n", rwb->rwb_buf);
342 return rwb->rwb_buf;
713c523f
EA
343}
344\f/*
36b09297
EA
345** INITMAPS -- initialize for aliasing
346**
347** Parameters:
348** rebuild -- if TRUE, this rebuilds the cached versions.
349** e -- current envelope.
350**
351** Returns:
352** none.
353**
354** Side Effects:
355** initializes aliases:
356** if NDBM: opens the database.
357** if ~NDBM: reads the aliases into the symbol table.
358*/
359
360initmaps(rebuild, e)
361 bool rebuild;
362 register ENVELOPE *e;
363{
364 extern void map_init();
365
88ed0dff
EA
366#ifdef XDEBUG
367 checkfd012("entering initmaps");
368#endif
36b09297 369 CurEnv = e;
3d401664
EA
370 if (rebuild)
371 {
372 stabapply(map_init, 1);
373 stabapply(map_init, 2);
374 }
375 else
376 {
377 stabapply(map_init, 0);
378 }
88ed0dff
EA
379#ifdef XDEBUG
380 checkfd012("exiting initmaps");
381#endif
36b09297
EA
382}
383
384void
385map_init(s, rebuild)
386 register STAB *s;
387 int rebuild;
388{
389 register MAP *map;
390
391 /* has to be a map */
392 if (s->s_type != ST_MAP)
393 return;
394
395 map = &s->s_map;
396 if (!bitset(MF_VALID, map->map_mflags))
397 return;
398
399 if (tTd(38, 2))
e7f5a48c 400 printf("map_init(%s:%s, %s, %d)\n",
5f719f17
EA
401 map->map_class->map_cname == NULL ? "NULL" :
402 map->map_class->map_cname,
e7f5a48c 403 map->map_mname == NULL ? "NULL" : map->map_mname,
3d401664
EA
404 map->map_file == NULL ? "NULL" : map->map_file,
405 rebuild);
406
407 if (rebuild == (bitset(MF_ALIAS, map->map_mflags) &&
408 bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2))
409 {
410 if (tTd(38, 3))
411 printf("\twrong pass\n");
412 return;
413 }
36b09297
EA
414
415 /* if already open, close it (for nested open) */
416 if (bitset(MF_OPEN, map->map_mflags))
417 {
418 map->map_class->map_close(map);
419 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
420 }
421
3d401664 422 if (rebuild == 2)
36b09297 423 {
3d401664 424 rebuildaliases(map, FALSE);
36b09297
EA
425 }
426 else
427 {
428 if (map->map_class->map_open(map, O_RDONLY))
429 {
430 if (tTd(38, 4))
e7f5a48c 431 printf("\t%s:%s %s: valid\n",
5f719f17
EA
432 map->map_class->map_cname == NULL ? "NULL" :
433 map->map_class->map_cname,
e7f5a48c
EA
434 map->map_mname == NULL ? "NULL" :
435 map->map_mname,
5f719f17
EA
436 map->map_file == NULL ? "NULL" :
437 map->map_file);
36b09297
EA
438 map->map_mflags |= MF_OPEN;
439 }
22944c86
EA
440 else
441 {
442 if (tTd(38, 4))
443 printf("\t%s:%s %s: invalid: %s\n",
444 map->map_class->map_cname == NULL ? "NULL" :
445 map->map_class->map_cname,
446 map->map_mname == NULL ? "NULL" :
447 map->map_mname,
448 map->map_file == NULL ? "NULL" :
449 map->map_file,
450 errstring(errno));
451 if (!bitset(MF_OPTIONAL, map->map_mflags))
452 {
453 extern MAPCLASS BogusMapClass;
454
455 map->map_class = &BogusMapClass;
456 map->map_mflags |= MF_OPEN;
457 }
458 }
36b09297
EA
459 }
460}
461\f/*
713c523f
EA
462** NDBM modules
463*/
464
465#ifdef NDBM
466
467/*
468** DBM_MAP_OPEN -- DBM-style map open
469*/
470
471bool
472ndbm_map_open(map, mode)
473 MAP *map;
474 int mode;
475{
28f94061
EA
476 register DBM *dbm;
477 struct stat st;
713c523f 478
36b09297 479 if (tTd(38, 2))
e7f5a48c
EA
480 printf("ndbm_map_open(%s, %s, %d)\n",
481 map->map_mname, map->map_file, mode);
713c523f 482
31f1ab13
EA
483 if (mode == O_RDWR)
484 mode |= O_CREAT|O_TRUNC;
485
713c523f
EA
486 /* open the database */
487 dbm = dbm_open(map->map_file, mode, DBMMODE);
488 if (dbm == NULL)
489 {
fe3849ea
EA
490 if (aliaswait(map, ".pag", FALSE))
491 return TRUE;
31f1ab13 492 if (!bitset(MF_OPTIONAL, map->map_mflags))
713c523f
EA
493 syserr("Cannot open DBM database %s", map->map_file);
494 return FALSE;
495 }
496 map->map_db1 = (void *) dbm;
c601f599
EA
497 if (mode == O_RDONLY)
498 {
499 if (bitset(MF_ALIAS, map->map_mflags) &&
500 !aliaswait(map, ".pag", TRUE))
fe3849ea 501 return FALSE;
c601f599
EA
502 }
503 else
504 {
505 int fd;
506
507 /* exclusive lock for duration of rebuild */
508 fd = dbm_dirfno((DBM *) map->map_db1);
509 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) &&
510 lockfile(fd, map->map_file, ".dir", LOCK_EX))
511 map->map_mflags |= MF_LOCKED;
512 }
fe3849ea 513 if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0)
28f94061 514 map->map_mtime = st.st_mtime;
713c523f
EA
515 return TRUE;
516}
517
518
519/*
520** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
521*/
522
523char *
524ndbm_map_lookup(map, name, av, statp)
525 MAP *map;
526 char *name;
527 char **av;
528 int *statp;
529{
530 datum key, val;
37abadde 531 int fd;
713c523f
EA
532 char keybuf[MAXNAME + 1];
533
36b09297 534 if (tTd(38, 20))
e7f5a48c
EA
535 printf("ndbm_map_lookup(%s, %s)\n",
536 map->map_mname, name);
713c523f
EA
537
538 key.dptr = name;
539 key.dsize = strlen(name);
31f1ab13 540 if (!bitset(MF_NOFOLDCASE, map->map_mflags))
713c523f
EA
541 {
542 if (key.dsize > sizeof keybuf - 1)
543 key.dsize = sizeof keybuf - 1;
544 bcopy(key.dptr, keybuf, key.dsize + 1);
545 makelower(keybuf);
546 key.dptr = keybuf;
547 }
37abadde 548 fd = dbm_dirfno((DBM *) map->map_db1);
7cd18d97 549 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
37abadde 550 (void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
8e5c6745
EA
551 val.dptr = NULL;
552 if (bitset(MF_TRY0NULL, map->map_mflags))
553 {
554 val = dbm_fetch((DBM *) map->map_db1, key);
555 if (val.dptr != NULL)
556 map->map_mflags &= ~MF_TRY1NULL;
557 }
558 if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
559 {
560 key.dsize++;
561 val = dbm_fetch((DBM *) map->map_db1, key);
562 if (val.dptr != NULL)
563 map->map_mflags &= ~MF_TRY0NULL;
564 }
7cd18d97 565 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
37abadde 566 (void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
713c523f
EA
567 if (val.dptr == NULL)
568 return NULL;
31f1ab13 569 if (bitset(MF_MATCHONLY, map->map_mflags))
8e5c6745
EA
570 return map_rewrite(map, name, strlen(name), NULL);
571 else
572 return map_rewrite(map, val.dptr, val.dsize, av);
713c523f
EA
573}
574
575
576/*
577** DBM_MAP_STORE -- store a datum in the database
578*/
579
580void
581ndbm_map_store(map, lhs, rhs)
582 register MAP *map;
583 char *lhs;
584 char *rhs;
585{
586 datum key;
587 datum data;
588 int stat;
589
36b09297 590 if (tTd(38, 12))
e7f5a48c
EA
591 printf("ndbm_map_store(%s, %s, %s)\n",
592 map->map_mname, lhs, rhs);
713c523f
EA
593
594 key.dsize = strlen(lhs);
595 key.dptr = lhs;
596
597 data.dsize = strlen(rhs);
598 data.dptr = rhs;
599
31f1ab13 600 if (bitset(MF_INCLNULL, map->map_mflags))
713c523f
EA
601 {
602 key.dsize++;
603 data.dsize++;
604 }
605
606 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
607 if (stat > 0)
608 {
63ad0236
EA
609 if (!bitset(MF_APPEND, map->map_mflags))
610 usrerr("050 Warning: duplicate alias name %s", lhs);
611 else
612 {
613 static char *buf = NULL;
614 static int bufsiz = 0;
7d1bb48a 615 auto int xstat;
63ad0236
EA
616 datum old;
617
7d1bb48a 618 old.dptr = ndbm_map_lookup(map, key.dptr, NULL, &xstat);
63ad0236
EA
619 if (old.dptr != NULL && *old.dptr != '\0')
620 {
621 old.dsize = strlen(old.dptr);
622 if (data.dsize + old.dsize + 2 > bufsiz)
623 {
624 if (buf != NULL)
625 (void) free(buf);
626 bufsiz = data.dsize + old.dsize + 2;
627 buf = xalloc(bufsiz);
628 }
629 sprintf(buf, "%s,%s", data.dptr, old.dptr);
630 data.dsize = data.dsize + old.dsize + 1;
631 data.dptr = buf;
632 if (tTd(38, 9))
633 printf("ndbm_map_store append=%s\n", data.dptr);
634 }
635 }
713c523f
EA
636 stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
637 }
638 if (stat != 0)
639 syserr("readaliases: dbm put (%s)", lhs);
640}
641
642
643/*
31f1ab13 644** NDBM_MAP_CLOSE -- close the database
713c523f
EA
645*/
646
647void
648ndbm_map_close(map)
649 register MAP *map;
650{
26999a7c 651 if (tTd(38, 9))
e7f5a48c
EA
652 printf("ndbm_map_close(%s, %s, %x)\n",
653 map->map_mname, map->map_file, map->map_mflags);
26999a7c 654
31f1ab13 655 if (bitset(MF_WRITABLE, map->map_mflags))
713c523f 656 {
35ef9fff 657#ifdef NIS
476a894f 658 bool inclnull;
713c523f
EA
659 char buf[200];
660
476a894f
EA
661 inclnull = bitset(MF_INCLNULL, map->map_mflags);
662 map->map_mflags &= ~MF_INCLNULL;
663
713c523f
EA
664 (void) sprintf(buf, "%010ld", curtime());
665 ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
666
5f0756fe 667 (void) gethostname(buf, sizeof buf);
713c523f 668 ndbm_map_store(map, "YP_MASTER_NAME", buf);
476a894f
EA
669
670 if (inclnull)
671 map->map_mflags |= MF_INCLNULL;
713c523f
EA
672#endif
673
674 /* write out the distinguished alias */
675 ndbm_map_store(map, "@", "@");
676 }
677 dbm_close((DBM *) map->map_db1);
678}
679
680#endif
681\f/*
8f43ee9e 682** NEWDB (Hash and BTree) Modules
713c523f
EA
683*/
684
685#ifdef NEWDB
686
687/*
8f43ee9e
EA
688** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
689**
690** These do rather bizarre locking. If you can lock on open,
691** do that to avoid the condition of opening a database that
692** is being rebuilt. If you don't, we'll try to fake it, but
693** there will be a race condition. If opening for read-only,
694** we immediately release the lock to avoid freezing things up.
695** We really ought to hold the lock, but guarantee that we won't
696** be pokey about it. That's hard to do.
713c523f
EA
697*/
698
699bool
700bt_map_open(map, mode)
701 MAP *map;
702 int mode;
703{
704 DB *db;
df88f2ef 705 int i;
8f43ee9e 706 int omode;
37abadde 707 int fd;
28f94061 708 struct stat st;
8446c922 709 char buf[MAXNAME + 1];
713c523f 710
36b09297 711 if (tTd(38, 2))
e7f5a48c
EA
712 printf("bt_map_open(%s, %s, %d)\n",
713 map->map_mname, map->map_file, mode);
713c523f 714
8f43ee9e
EA
715 omode = mode;
716 if (omode == O_RDWR)
717 {
718 omode |= O_CREAT|O_TRUNC;
72af7ebb 719#if defined(O_EXLOCK) && HASFLOCK
8f43ee9e 720 omode |= O_EXLOCK;
11c14c72 721# if !OLD_NEWDB
8f43ee9e
EA
722 }
723 else
724 {
725 omode |= O_SHLOCK;
726# endif
727#endif
728 }
31f1ab13 729
df88f2ef
EA
730 (void) strcpy(buf, map->map_file);
731 i = strlen(buf);
732 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
733 (void) strcat(buf, ".db");
8f43ee9e 734 db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
713c523f
EA
735 if (db == NULL)
736 {
fe3849ea
EA
737#ifdef MAYBENEXTRELEASE
738 if (aliaswait(map, ".db", FALSE))
739 return TRUE;
740#endif
31f1ab13 741 if (!bitset(MF_OPTIONAL, map->map_mflags))
713c523f
EA
742 syserr("Cannot open BTREE database %s", map->map_file);
743 return FALSE;
744 }
3b4f3997 745#if !OLD_NEWDB
37abadde 746 fd = db->fd(db);
1688afb9
EA
747# if defined(O_EXLOCK) && HASFLOCK
748 if (fd >= 0)
749 {
750 if (mode == O_RDONLY)
751 (void) lockfile(fd, map->map_file, ".db", LOCK_UN);
752 else
753 map->map_mflags |= MF_LOCKED;
754 }
755# else
37abadde 756 if (mode == O_RDWR && fd >= 0)
7cd18d97
EA
757 {
758 if (lockfile(fd, map->map_file, ".db", LOCK_EX))
759 map->map_mflags |= MF_LOCKED;
760 }
8f43ee9e
EA
761# endif
762#endif
b215b035
EA
763
764 /* try to make sure that at least the database header is on disk */
765 if (mode == O_RDWR)
11c14c72 766#if OLD_NEWDB
37abadde
EA
767 (void) db->sync(db);
768#else
b215b035
EA
769 (void) db->sync(db, 0);
770
37abadde 771 if (fd >= 0 && fstat(fd, &st) >= 0)
28f94061
EA
772 map->map_mtime = st.st_mtime;
773#endif
774
713c523f 775 map->map_db2 = (void *) db;
31f1ab13 776 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
fe3849ea
EA
777 if (!aliaswait(map, ".db", TRUE))
778 return FALSE;
713c523f
EA
779 return TRUE;
780}
781
782
783/*
784** HASH_MAP_INIT -- HASH-style map initialization
785*/
786
787bool
788hash_map_open(map, mode)
789 MAP *map;
790 int mode;
791{
792 DB *db;
df88f2ef 793 int i;
8f43ee9e 794 int omode;
37abadde 795 int fd;
28f94061 796 struct stat st;
8446c922 797 char buf[MAXNAME + 1];
713c523f 798
36b09297 799 if (tTd(38, 2))
e7f5a48c
EA
800 printf("hash_map_open(%s, %s, %d)\n",
801 map->map_mname, map->map_file, mode);
713c523f 802
8f43ee9e
EA
803 omode = mode;
804 if (omode == O_RDWR)
805 {
806 omode |= O_CREAT|O_TRUNC;
72af7ebb 807#if defined(O_EXLOCK) && HASFLOCK
8f43ee9e 808 omode |= O_EXLOCK;
11c14c72 809# if !OLD_NEWDB
8f43ee9e
EA
810 }
811 else
812 {
813 omode |= O_SHLOCK;
814# endif
815#endif
816 }
31f1ab13 817
df88f2ef
EA
818 (void) strcpy(buf, map->map_file);
819 i = strlen(buf);
820 if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
821 (void) strcat(buf, ".db");
8f43ee9e 822 db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
713c523f
EA
823 if (db == NULL)
824 {
fe3849ea
EA
825#ifdef MAYBENEXTRELEASE
826 if (aliaswait(map, ".db", FALSE))
827 return TRUE;
828#endif
31f1ab13 829 if (!bitset(MF_OPTIONAL, map->map_mflags))
713c523f
EA
830 syserr("Cannot open HASH database %s", map->map_file);
831 return FALSE;
832 }
3b4f3997 833#if !OLD_NEWDB
37abadde 834 fd = db->fd(db);
1688afb9
EA
835# if defined(O_EXLOCK) && HASFLOCK
836 if (fd >= 0)
837 {
838 if (mode == O_RDONLY)
839 (void) lockfile(fd, map->map_file, ".db", LOCK_UN);
840 else
841 map->map_mflags |= MF_LOCKED;
842 }
843# else
37abadde 844 if (mode == O_RDWR && fd >= 0)
7cd18d97
EA
845 {
846 if (lockfile(fd, map->map_file, ".db", LOCK_EX))
847 map->map_mflags |= MF_LOCKED;
848 }
8f43ee9e
EA
849# endif
850#endif
b215b035
EA
851
852 /* try to make sure that at least the database header is on disk */
853 if (mode == O_RDWR)
11c14c72 854#if OLD_NEWDB
37abadde
EA
855 (void) db->sync(db);
856#else
b215b035
EA
857 (void) db->sync(db, 0);
858
37abadde 859 if (fd >= 0 && fstat(fd, &st) >= 0)
28f94061
EA
860 map->map_mtime = st.st_mtime;
861#endif
862
713c523f 863 map->map_db2 = (void *) db;
31f1ab13 864 if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
fe3849ea
EA
865 if (!aliaswait(map, ".db", TRUE))
866 return FALSE;
713c523f
EA
867 return TRUE;
868}
869
870
871/*
872** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
873*/
874
875char *
876db_map_lookup(map, name, av, statp)
877 MAP *map;
878 char *name;
879 char **av;
880 int *statp;
881{
882 DBT key, val;
31ffabe6
EA
883 register DB *db = (DB *) map->map_db2;
884 int st;
885 int saveerrno;
37abadde 886 int fd;
713c523f
EA
887 char keybuf[MAXNAME + 1];
888
36b09297 889 if (tTd(38, 20))
e7f5a48c
EA
890 printf("db_map_lookup(%s, %s)\n",
891 map->map_mname, name);
713c523f
EA
892
893 key.size = strlen(name);
894 if (key.size > sizeof keybuf - 1)
895 key.size = sizeof keybuf - 1;
896 key.data = keybuf;
897 bcopy(name, keybuf, key.size + 1);
31f1ab13 898 if (!bitset(MF_NOFOLDCASE, map->map_mflags))
713c523f 899 makelower(keybuf);
11c14c72 900#if !OLD_NEWDB
7cd18d97
EA
901 fd = db->fd(db);
902 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
903 (void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH);
31ffabe6 904#endif
8e5c6745
EA
905 st = 1;
906 if (bitset(MF_TRY0NULL, map->map_mflags))
907 {
908 st = db->get(db, &key, &val, 0);
909 if (st == 0)
910 map->map_mflags &= ~MF_TRY1NULL;
911 }
912 if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
913 {
914 key.size++;
915 st = db->get(db, &key, &val, 0);
916 if (st == 0)
917 map->map_mflags &= ~MF_TRY0NULL;
918 }
31ffabe6 919 saveerrno = errno;
11c14c72 920#if !OLD_NEWDB
7cd18d97 921 if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
37abadde 922 (void) lockfile(fd, map->map_file, ".db", LOCK_UN);
31ffabe6
EA
923#endif
924 if (st != 0)
925 {
926 errno = saveerrno;
927 if (st < 0)
928 syserr("db_map_lookup: get (%s)", name);
713c523f 929 return NULL;
31ffabe6 930 }
31f1ab13 931 if (bitset(MF_MATCHONLY, map->map_mflags))
8e5c6745
EA
932 return map_rewrite(map, name, strlen(name), NULL);
933 else
934 return map_rewrite(map, val.data, val.size, av);
713c523f
EA
935}
936
937
938/*
939** DB_MAP_STORE -- store a datum in the NEWDB database
940*/
941
942void
943db_map_store(map, lhs, rhs)
944 register MAP *map;
945 char *lhs;
946 char *rhs;
947{
948 int stat;
949 DBT key;
950 DBT data;
951 register DB *db = map->map_db2;
952
36b09297 953 if (tTd(38, 20))
e7f5a48c
EA
954 printf("db_map_store(%s, %s, %s)\n",
955 map->map_mname, lhs, rhs);
713c523f
EA
956
957 key.size = strlen(lhs);
958 key.data = lhs;
959
960 data.size = strlen(rhs);
961 data.data = rhs;
962
31f1ab13 963 if (bitset(MF_INCLNULL, map->map_mflags))
713c523f
EA
964 {
965 key.size++;
966 data.size++;
967 }
968
969 stat = db->put(db, &key, &data, R_NOOVERWRITE);
970 if (stat > 0)
971 {
63ad0236
EA
972 if (!bitset(MF_APPEND, map->map_mflags))
973 usrerr("050 Warning: duplicate alias name %s", lhs);
974 else
975 {
976 static char *buf = NULL;
977 static int bufsiz = 0;
978 DBT old;
979
980 old.data = db_map_lookup(map, key.data, NULL, &stat);
981 if (old.data != NULL)
982 {
983 old.size = strlen(old.data);
984 if (data.size + old.size + 2 > bufsiz)
985 {
986 if (buf != NULL)
987 (void) free(buf);
988 bufsiz = data.size + old.size + 2;
989 buf = xalloc(bufsiz);
990 }
991 sprintf(buf, "%s,%s", data.data, old.data);
992 data.size = data.size + old.size + 1;
993 data.data = buf;
994 if (tTd(38, 9))
995 printf("db_map_store append=%s\n", data.data);
996 }
997 }
713c523f
EA
998 stat = db->put(db, &key, &data, 0);
999 }
1000 if (stat != 0)
1001 syserr("readaliases: db put (%s)", lhs);
1002}
1003
1004
713c523f
EA
1005/*
1006** DB_MAP_CLOSE -- add distinguished entries and close the database
1007*/
1008
1009void
1010db_map_close(map)
1011 MAP *map;
1012{
1013 register DB *db = map->map_db2;
1014
36b09297 1015 if (tTd(38, 9))
e7f5a48c
EA
1016 printf("db_map_close(%s, %s, %x)\n",
1017 map->map_mname, map->map_file, map->map_mflags);
713c523f 1018
31f1ab13 1019 if (bitset(MF_WRITABLE, map->map_mflags))
713c523f
EA
1020 {
1021 /* write out the distinguished alias */
1022 db_map_store(map, "@", "@");
1023 }
1024
1025 if (db->close(db) != 0)
1026 syserr("readaliases: db close failure");
1027}
1028
1029#endif
1030\f/*
1031** NIS Modules
1032*/
1033
1034# ifdef NIS
1035
81c3b06b
EA
1036# ifndef YPERR_BUSY
1037# define YPERR_BUSY 16
1038# endif
1039
713c523f
EA
1040/*
1041** NIS_MAP_OPEN -- open DBM map
1042*/
1043
1044bool
1045nis_map_open(map, mode)
1046 MAP *map;
1047 int mode;
1048{
1049 int yperr;
94b8a28b
EA
1050 register char *p;
1051 auto char *vp;
1052 auto int vsize;
713c523f
EA
1053 char *master;
1054
36b09297 1055 if (tTd(38, 2))
e7f5a48c
EA
1056 printf("nis_map_open(%s, %s)\n",
1057 map->map_mname, map->map_file);
713c523f 1058
31f1ab13
EA
1059 if (mode != O_RDONLY)
1060 {
ed6d397f
EA
1061 /* issue a pseudo-error message */
1062#ifdef ENOSYS
1063 errno = ENOSYS;
1064#else
1065# ifdef EFTYPE
1066 errno = EFTYPE;
1067# else
1068 errno = ENXIO;
1069# endif
1070#endif
31f1ab13
EA
1071 return FALSE;
1072 }
1073
713c523f
EA
1074 p = strchr(map->map_file, '@');
1075 if (p != NULL)
1076 {
1077 *p++ = '\0';
1078 if (*p != '\0')
1079 map->map_domain = p;
1080 }
94b8a28b 1081
713c523f
EA
1082 if (*map->map_file == '\0')
1083 map->map_file = "mail.aliases";
1084
449e4486
EA
1085 if (map->map_domain == NULL)
1086 {
1087 yperr = yp_get_default_domain(&map->map_domain);
1088 if (yperr != 0)
1089 {
3b238b99 1090 if (!bitset(MF_OPTIONAL, map->map_mflags))
22944c86 1091 syserr("421 NIS map %s specified, but NIS not running\n",
3b238b99 1092 map->map_file);
449e4486
EA
1093 return FALSE;
1094 }
1095 }
1096
94b8a28b 1097 /* check to see if this map actually exists */
713c523f
EA
1098 yperr = yp_match(map->map_domain, map->map_file, "@", 1,
1099 &vp, &vsize);
36b09297 1100 if (tTd(38, 10))
713c523f
EA
1101 printf("nis_map_open: yp_match(%s, %s) => %s\n",
1102 map->map_domain, map->map_file, yperr_string(yperr));
1103 if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
f5be4a13
EA
1104 {
1105 if (!bitset(MF_ALIAS, map->map_mflags) ||
1106 aliaswait(map, NULL, TRUE))
1107 return TRUE;
1108 }
94b8a28b
EA
1109
1110 if (!bitset(MF_OPTIONAL, map->map_mflags))
8fd1c47c
EA
1111 {
1112 syserr("421 Cannot bind to map %s in domain %s: %s",
1113 map->map_file, map->map_domain, yperr_string(yperr));
1114 }
94b8a28b 1115
713c523f
EA
1116 return FALSE;
1117}
1118
1119
1120/*
1121** NIS_MAP_LOOKUP -- look up a datum in a NIS map
1122*/
1123
1124char *
1125nis_map_lookup(map, name, av, statp)
1126 MAP *map;
1127 char *name;
1128 char **av;
1129 int *statp;
1130{
1131 char *vp;
1132 auto int vsize;
1133 int buflen;
94b8a28b 1134 int yperr;
713c523f
EA
1135 char keybuf[MAXNAME + 1];
1136
36b09297 1137 if (tTd(38, 20))
e7f5a48c
EA
1138 printf("nis_map_lookup(%s, %s)\n",
1139 map->map_mname, name);
713c523f
EA
1140
1141 buflen = strlen(name);
1142 if (buflen > sizeof keybuf - 1)
1143 buflen = sizeof keybuf - 1;
1144 bcopy(name, keybuf, buflen + 1);
31f1ab13 1145 if (!bitset(MF_NOFOLDCASE, map->map_mflags))
713c523f 1146 makelower(keybuf);
8e5c6745
EA
1147 yperr = YPERR_KEY;
1148 if (bitset(MF_TRY0NULL, map->map_mflags))
1149 {
1150 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
1151 &vp, &vsize);
1152 if (yperr == 0)
1153 map->map_mflags &= ~MF_TRY1NULL;
1154 }
1155 if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
1156 {
713c523f 1157 buflen++;
8e5c6745
EA
1158 yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
1159 &vp, &vsize);
1160 if (yperr == 0)
1161 map->map_mflags &= ~MF_TRY0NULL;
1162 }
713c523f
EA
1163 if (yperr != 0)
1164 {
1165 if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
94b8a28b 1166 map->map_mflags &= ~(MF_VALID|MF_OPEN);
713c523f
EA
1167 return NULL;
1168 }
31f1ab13 1169 if (bitset(MF_MATCHONLY, map->map_mflags))
8e5c6745
EA
1170 return map_rewrite(map, name, strlen(name), NULL);
1171 else
1172 return map_rewrite(map, vp, vsize, av);
713c523f
EA
1173}
1174
f0416b32
EA
1175
1176/*
1177** NIS_GETCANONNAME -- look up canonical name in NIS
1178*/
1179
1180bool
1181nis_getcanonname(name, hbsize, statp)
1182 char *name;
1183 int hbsize;
1184 int *statp;
1185{
1186 char *vp;
1187 auto int vsize;
1188 int keylen;
1189 int yperr;
1190 static bool try0null = TRUE;
1191 static bool try1null = TRUE;
1192 static char *yp_domain = NULL;
1193 char *domain, *p;
1194 char host_record[MAXLINE];
1195 char buf[MAXNAME];
1196 char *cname;
1197 extern char *get_column();
1198
1199 if (tTd(38, 20))
1200 printf("nis_getcanonname(%s)\n", name);
1201
1202 shorten_hostname(name);
1203
1204 /* we only accept single token search key */
1205 if (strchr(name, '.'))
1206 {
1207 *statp = EX_NOHOST;
1208 return FALSE;
1209 }
1210
1211 keylen = strlen(name);
1212
1213 if (yp_domain == NULL)
1214 yp_get_default_domain(&yp_domain);
1215 makelower(name);
1216 yperr = YPERR_KEY;
1217 if (try0null)
1218 {
1219 yperr = yp_match(yp_domain, "hosts.byname", name, keylen,
1220 &vp, &vsize);
1221 if (yperr == 0)
1222 try1null = FALSE;
1223 }
1224 if (yperr == YPERR_KEY && try1null)
1225 {
1226 keylen++;
1227 yperr = yp_match(yp_domain, "hosts.byname", name, keylen,
1228 &vp, &vsize);
1229 if (yperr == 0)
1230 try0null = FALSE;
1231 }
1232 if (yperr != 0)
1233 {
1234 if (yperr == YPERR_KEY)
1235 *statp = EX_NOHOST;
1236 else if (yperr == YPERR_BUSY)
1237 *statp = EX_TEMPFAIL;
1238 else
1239 *statp = EX_UNAVAILABLE;
1240 return FALSE;
1241 }
1242 strncpy(host_record, vp, vsize);
1243 host_record[vsize] = '\0';
1244 cname = get_column(host_record, 1, '\t', buf);
1245 if (cname == NULL)
1246 {
1247 /* this should not happen, but.... */
1248 *statp = EX_NOHOST;
1249 return FALSE;
1250 }
1251
1252 if (hbsize >= strlen(cname))
1253 {
1254 strcpy(name, cname);
1255 *statp = EX_OK;
1256 return TRUE;
1257 }
1258 *statp = EX_UNAVAILABLE;
1259 return FALSE;
1260}
1261
f5e8ddb6
EA
1262#endif
1263\f/*
437376a9
EA
1264** NISPLUS Modules
1265**
1266** This code donated by Sun Microsystems.
1267*/
1268
1269#ifdef NISPLUS
1270
1271#undef NIS /* symbol conflict in nis.h */
1272#include <rpcsvc/nis.h>
1273#include <rpcsvc/nislib.h>
1274
1275#define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
1276#define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
1277#define COL_MAX(res) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
1278#define PARTIAL_NAME(x) ((x)[strlen(x) - 1] != '.')
1279
1280/*
1281** NISPLUS_MAP_OPEN -- open nisplus table
1282*/
1283
1284bool
1285nisplus_map_open(map, mode)
1286 MAP *map;
1287 int mode;
1288{
1289 register char *p;
1290 char qbuf[MAXLINE + NIS_MAXNAMELEN];
1291 nis_result *res = NULL;
1292 u_int objs_len;
1293 nis_object *obj_ptr;
1294 int retry_cnt, max_col, i;
1295
1296 if (tTd(38, 2))
1297 printf("nisplus_map_open(%s, %s, %d)\n",
1298 map->map_mname, map->map_file, mode);
1299
1300 if (mode != O_RDONLY)
1301 {
1302 errno = ENODEV;
1303 return FALSE;
1304 }
1305
1306 if (*map->map_file == '\0')
1307 map->map_file = "mail_aliases.org_dir";
1308
1309 if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
1310 {
1311 /* set default NISPLUS Domain to $m */
1312 extern char *nisplus_default_domain();
1313
1314 map->map_domain = newstr(nisplus_default_domain());
1315 if (tTd(38, 2))
1316 printf("nisplus_map_open(%s): using domain %s\n",
1317 map->map_file, map->map_domain);
1318 }
1319 if (!PARTIAL_NAME(map->map_file))
1320 map->map_domain = newstr("");
1321
1322 /* check to see if this map actually exists */
1323 if (PARTIAL_NAME(map->map_file))
1324 sprintf(qbuf, "%s.%s", map->map_file, map->map_domain);
1325 else
1326 strcpy(qbuf, map->map_file);
1327
1328 retry_cnt = 0;
1329 while (res == NULL || res->status != NIS_SUCCESS)
1330 {
1331 res = nis_lookup(qbuf, FOLLOW_LINKS);
1332 switch (res->status)
1333 {
1334 case NIS_SUCCESS:
1335 case NIS_TRYAGAIN:
1336 case NIS_RPCERROR:
1337 case NIS_NAMEUNREACHABLE:
1338 break;
1339
1340 default: /* all other nisplus errors */
1341#if 0
1342 if (!bitset(MF_OPTIONAL, map->map_mflags))
22944c86 1343 syserr("421 Cannot find table %s.%s: %s",
437376a9
EA
1344 map->map_file, map->map_domain,
1345 nis_sperrno(res->status));
1346#endif
1347 errno = EBADR;
1348 return FALSE;
1349 }
1350 sleep(2); /* try not to overwhelm hosed server */
1351 if (retry_cnt++ > 4)
1352 {
1353 errno = EBADR;
1354 return FALSE;
1355 }
1356 }
1357
1358 if (NIS_RES_NUMOBJ(res) != 1 ||
1359 (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
1360 {
1361 if (tTd(38, 10))
1362 printf("nisplus_map_open: %s is not a table\n", qbuf);
1363#if 0
1364 if (!bitset(MF_OPTIONAL, map->map_mflags))
22944c86 1365 syserr("421 %s.%s: %s is not a table",
437376a9
EA
1366 map->map_file, map->map_domain,
1367 nis_sperrno(res->status));
1368#endif
1369 errno = EBADR;
1370 return FALSE;
1371 }
1372 /* default key column is column 0 */
1373 if (map->map_keycolnm == NULL)
1374 map->map_keycolnm = newstr(COL_NAME(res,0));
1375
1376 max_col = COL_MAX(res);
1377
1378 /* verify the key column exist */
1379 for (i=0; i< max_col; i++)
1380 {
1381 if (!strcmp(map->map_keycolnm, COL_NAME(res,i)))
1382 break;
1383 }
1384 if (i == max_col)
1385 {
1386 if (tTd(38, 2))
1387 printf("nisplus_map_open(%s): can not find key column %s\n",
1388 map->map_file, map->map_keycolnm);
1389 errno = EBADR;
1390 return FALSE;
1391 }
1392
1393 /* default value column is the last column */
1394 if (map->map_valcolnm == NULL)
1395 {
1396 map->map_valcolno = max_col - 1;
1397 return TRUE;
1398 }
1399
1400 for (i=0; i< max_col; i++)
1401 {
1402 if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
1403 {
1404 map->map_valcolno = i;
1405 return TRUE;
1406 }
1407 }
1408
1409 if (tTd(38, 2))
1410 printf("nisplus_map_open(%s): can not find column %s\n",
1411 map->map_file, map->map_keycolnm);
1412 errno = EBADR;
1413 return FALSE;
1414}
1415
1416
1417/*
1418** NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
1419*/
1420
1421char *
1422nisplus_map_lookup(map, name, av, statp)
1423 MAP *map;
1424 char *name;
1425 char **av;
1426 int *statp;
1427{
1428 char *vp;
1429 auto int vsize;
1430 int buflen;
1431 char search_key[MAXNAME + 1];
1432 char qbuf[MAXLINE + NIS_MAXNAMELEN];
1433 nis_result *result;
1434
1435 if (tTd(38, 20))
1436 printf("nisplus_map_lookup(%s, %s)\n",
1437 map->map_mname, name);
1438
1439 if (!bitset(MF_OPEN, map->map_mflags))
1440 {
1441 if (nisplus_map_open(map, O_RDONLY))
1442 map->map_mflags |= MF_OPEN;
1443 else
1444 {
1445 *statp = EX_UNAVAILABLE;
1446 return NULL;
1447 }
1448 }
1449
1450 buflen = strlen(name);
1451 if (buflen > sizeof search_key - 1)
1452 buflen = sizeof search_key - 1;
1453 bcopy(name, search_key, buflen + 1);
1454 if (!bitset(MF_NOFOLDCASE, map->map_mflags))
1455 makelower(search_key);
1456
1457 /* construct the query */
1458 if (PARTIAL_NAME(map->map_file))
1459 sprintf(qbuf, "[%s=%s],%s.%s", map->map_keycolnm,
1460 search_key, map->map_file, map->map_domain);
1461 else
1462 sprintf(qbuf, "[%s=%s],%s", map->map_keycolnm,
1463 search_key, map->map_file);
1464
1465 if (tTd(38, 20))
1466 printf("qbuf=%s\n", qbuf);
1467 result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
1468 if (result->status == NIS_SUCCESS)
1469 {
1470 int count;
1471 char *str;
1472
1473 if ((count = NIS_RES_NUMOBJ(result)) != 1)
1474 {
1475 if (LogLevel > 10)
1476 syslog(LOG_WARNING,
1477 "%s:Lookup error, expected 1 entry, got (%d)",
1478 map->map_file, count);
1479
1480 /* ignore second entry */
1481 if (tTd(38, 20))
1482 printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
1483 name, count);
1484 }
1485
1486 vp = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
1487 /* set the length of the result */
1488 if (vp == NULL)
1489 vp = "";
1490 vsize = strlen(vp);
1491 if (tTd(38, 20))
1492 printf("nisplus_map_lookup(%s), found %s\n",
1493 name, vp);
1494 if (bitset(MF_MATCHONLY, map->map_mflags))
1495 str = map_rewrite(map, name, strlen(name), NULL);
1496 else
1497 str = map_rewrite(map, vp, vsize, av);
1498 nis_freeresult(result);
1499#ifdef MAP_EXIT_STAT
1500 *statp = EX_OK;
1501#endif
1502 return str;
1503 }
1504 else
1505 {
1506#ifdef MAP_EXIT_STAT
1507 if (result->status == NIS_NOTFOUND)
1508 *statp = EX_NOTFOUND;
1509 else if (result->status == NIS_TRYAGAIN)
1510 *statp = EX_TEMPFAIL;
1511 else
1512 {
1513 *statp = EX_UNAVAILABLE;
1514 map->map_mflags &= ~(MF_VALID|MF_OPEN);
1515 }
1516#else
1517 if ((result->status != NIS_NOTFOUND) &&
1518 (result->status != NIS_TRYAGAIN))
1519 map->map_mflags &= ~(MF_VALID|MF_OPEN);
1520#endif
1521 }
1522 if (tTd(38, 20))
1523 printf("nisplus_map_lookup(%s), failed\n", name);
1524 nis_freeresult(result);
1525 return NULL;
1526}
1527
1528
f0416b32
EA
1529
1530/*
1531** NISPLUS_GETCANONNAME -- look up canonical name in NIS+
1532*/
1533
1534bool
1535nisplus_getcanonname(name, hbsize, statp)
1536 char *name;
1537 int hbsize;
1538 int *statp;
1539{
1540 char *vp;
1541 auto int vsize;
1542 int buflen;
14e29bd9 1543 char buf[MAXLINE + NIS_MAXNAMELEN];
f0416b32
EA
1544 nis_result *result;
1545 char *p;
1546 int len;
1547
f0416b32
EA
1548 shorten_hostname(name);
1549
1550 p = strchr(name, '.');
1551 if (p == NULL)
1552 {
1553 /* single token */
14e29bd9 1554 sprintf(buf, "[name=%s],hosts.org_dir", name);
f0416b32
EA
1555 }
1556 else if (p[1] != '\0')
1557 {
1558 /* multi token -- take only first token in name buf */
1559 *p = '\0';
14e29bd9 1560 sprintf(buf, "[name=%s],hosts.org_dir.%s", name, &p[1]);
f0416b32
EA
1561 }
1562 else
1563 {
1564 *statp = EX_NOHOST;
1565 return FALSE;
1566 }
1567
1568 if (tTd(38, 20))
1569 printf("\nnisplus_getcanoname(%s), qbuf=%s\n%s\n",
14e29bd9 1570 name, buf, nis_path);
f0416b32 1571
14e29bd9 1572 result = nis_list(buf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
f0416b32
EA
1573 NULL, NULL);
1574
f0416b32
EA
1575 if (result->status == NIS_SUCCESS)
1576 {
1577 int count;
1578 char *str;
1579 char *domain;
1580
1581 if ((count = NIS_RES_NUMOBJ(result)) != 1)
1582 {
1583#ifdef LOG
1584 if (LogLevel > 10)
1585 syslog(LOG_WARNING,
1586 "nisplus_getcanonname: Lookup error, expected 1 entry, got (%d)",
1587 count);
1588#endif
1589
1590 /* ignore second entry */
1591 if (tTd(38, 20))
1592 printf("nisplus_getcanoname(%s), got %d entries, addtional entries ignores\n", name);
1593 }
1594
1595 if (tTd(38, 20))
1596 printf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
1597 name, (NIS_RES_OBJECT(result))->zo_domain);
1598
1599
1600 vp = ((NIS_RES_OBJECT(result))->EN_col(0));
1601 vsize = strlen(vp);
1602 if (tTd(38, 20))
1603 printf("nisplus_getcanonname(%s), found %s\n",
1604 name, vp);
1605 domain = macvalue('m', CurEnv);
1606 if (hbsize > (vsize + ((int) strlen(domain))))
1607 {
1608 sprintf(name, "%s.%s", vp, domain);
1609 *statp = EX_OK;
1610 }
1611 else
1612 *statp = EX_NOHOST;
1613 nis_freeresult(result);
1614 return TRUE;
1615 }
1616 else
1617 {
1618 if (result->status == NIS_NOTFOUND)
1619 *statp = EX_NOHOST;
1620 else if (result->status == NIS_TRYAGAIN)
1621 *statp = EX_TEMPFAIL;
1622 else
1623 {
1624 *statp = EX_UNAVAILABLE;
1625 }
1626 }
1627 if (tTd(38, 20))
1628 printf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
1629 name, result->status, *statp);
1630 nis_freeresult(result);
1631 return FALSE;
1632}
1633
1634
437376a9
EA
1635char *
1636nisplus_default_domain()
1637{
8446c922 1638 static char default_domain[MAXNAME + 1] = "";
437376a9
EA
1639 char *p;
1640
1641 if (default_domain[0] != '\0')
1642 return(default_domain);
1643
ea8e7ca1 1644 p = nis_local_directory();
437376a9 1645 strcpy(default_domain, p);
ea8e7ca1 1646 return default_domain;
437376a9
EA
1647}
1648
1649#endif /* NISPLUS */
1650\f/*
f5e8ddb6 1651** HESIOD Modules
f5e8ddb6
EA
1652*/
1653
1654#ifdef HESIOD
1655
2a1b82eb
EA
1656#include <hesiod.h>
1657
f5e8ddb6
EA
1658char *
1659hes_map_lookup(map, name, av, statp)
1660 MAP *map;
1661 char *name;
1662 char **av;
1663 int *statp;
1664{
2a1b82eb
EA
1665 char **hp;
1666 char *retdata = NULL;
1667 int i;
f5e8ddb6
EA
1668
1669 if (tTd(38, 20))
2a1b82eb 1670 printf("hes_map_lookup(%s, %s)\n", map->map_file, name);
f5e8ddb6 1671
2a1b82eb
EA
1672 hp = hes_resolve(name, map->map_file);
1673 if (hp == NULL)
f5e8ddb6 1674 return NULL;
2a1b82eb
EA
1675
1676 if (hp[0] != NULL)
437376a9 1677 {
2a1b82eb
EA
1678 if (bitset(MF_MATCHONLY, map->map_mflags))
1679 retdata = map_rewrite(map, name, strlen(name), NULL);
1680 else
1681 retdata = map_rewrite(map, hp[0], strlen(hp[0]), av);
437376a9 1682 }
2a1b82eb
EA
1683
1684 for (i = 0; hp[i] != NULL; i++)
1685 free(hp[i]);
1686 free(hp);
1687 return retdata;
f5e8ddb6
EA
1688}
1689
234c9ed0
EA
1690#endif
1691\f/*
1692** NeXT NETINFO Modules
1693*/
1694
1695#ifdef NETINFO
1696
1697#define NETINFO_DEFAULT_DIR "/aliases"
1698#define NETINFO_DEFAULT_PROPERTY "members"
1699
1700
1701/*
1702** NI_MAP_OPEN -- open NetInfo Aliases
1703*/
1704
437376a9 1705bool
234c9ed0
EA
1706ni_map_open(map, mode)
1707 MAP *map;
1708 int mode;
1709{
1710 char *p;
1711
1712 if (tTd(38, 20))
1713 printf("ni_map_open: %s\n", map->map_file);
1714
234c9ed0
EA
1715 if (*map->map_file == '\0')
1716 map->map_file = NETINFO_DEFAULT_DIR;
1717
34088257
EA
1718 if (map->map_valcolnm == NULL)
1719 map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
234c9ed0 1720
bc3bfc33
EA
1721 if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
1722 map->map_coldelim = ',';
234c9ed0
EA
1723
1724 return TRUE;
1725}
1726
1727
1728/*
1729** NI_MAP_LOOKUP -- look up a datum in NetInfo
1730*/
1731
1732char *
1733ni_map_lookup(map, name, av, statp)
1734 MAP *map;
1735 char *name;
1736 char **av;
1737 int *statp;
1738{
1739 char *res;
1740 char *propval;
1741 extern char *ni_propval();
1742
1743 if (tTd(38, 20))
437376a9 1744 printf("ni_map_lookup(%s, %s)\n",
234c9ed0
EA
1745 map->map_mname, name);
1746
1747 propval = ni_propval(map->map_file, map->map_keycolnm, name,
1748 map->map_valcolnm, map->map_coldelim);
1749
437376a9 1750 if (propval == NULL)
234c9ed0
EA
1751 return NULL;
1752
1753 if (bitset(MF_MATCHONLY, map->map_mflags))
1754 res = map_rewrite(map, name, strlen(name), NULL);
1755 else
1756 res = map_rewrite(map, propval, strlen(propval), av);
1757 free(propval);
1758 return res;
1759}
1760
e7f5a48c 1761#endif
713c523f 1762\f/*
437376a9
EA
1763** TEXT (unindexed text file) Modules
1764**
1765** This code donated by Sun Microsystems.
1766*/
1767
1768
1769/*
1770** TEXT_MAP_OPEN -- open text table
1771*/
1772
1773bool
1774text_map_open(map, mode)
1775 MAP *map;
1776 int mode;
1777{
1778 struct stat sbuf;
1779
1780 if (tTd(38, 2))
1781 printf("text_map_open(%s, %s, %d)\n",
1782 map->map_mname, map->map_file, mode);
1783
1784 if (mode != O_RDONLY)
1785 {
1786 errno = ENODEV;
1787 return FALSE;
1788 }
1789
1790 if (*map->map_file == '\0')
1791 {
1792 if (tTd(38, 2))
1793 printf("text_map_open: file name required\n");
1794 return FALSE;
1795 }
1796
1797 if (map->map_file[0] != '/')
1798 {
1799 if (tTd(38, 2))
1800 printf("text_map_open(%s): file name must be fully qualified\n",
1801 map->map_file);
1802 return FALSE;
1803 }
1804 /* check to see if this map actually accessable */
1805 if (access(map->map_file, R_OK) <0)
1806 return FALSE;
1807
1808 /* check to see if this map actually exist */
1809 if (stat(map->map_file, &sbuf) <0)
1810 {
1811 if (tTd(38, 2))
1812 printf("text_map_open(%s): can not stat %s\n",
1813 map->map_file, map->map_file);
1814 return FALSE;
1815 }
1816
1817 if (!S_ISREG(sbuf.st_mode))
1818 {
1819 if (tTd(38, 2))
1820 printf("text_map_open(%s): %s is not a file\n",
1821 map->map_file, map->map_file);
1822 return FALSE;
1823 }
1824
1825 if (map->map_keycolnm == NULL)
1826 map->map_keycolno = 0;
1827 else
1828 {
1829 if (!isdigit(*map->map_keycolnm))
1830 {
1831 if (tTd(38, 2))
1832 printf("text_map_open(%s): -k should specify a number, not %s\n",
1833 map->map_file, map->map_keycolnm);
1834 return FALSE;
1835 }
1836 map->map_keycolno = atoi(map->map_keycolnm);
1837 }
1838
1839 if (map->map_valcolnm == NULL)
1840 map->map_valcolno = 0;
1841 else
1842 {
1843 if (!isdigit(*map->map_valcolnm))
1844 {
1845 if (tTd(38, 2))
1846 printf("text_map_open(%s): -v should specify a number, not %s\n",
1847 map->map_file, map->map_valcolnm);
1848 return FALSE;
1849 }
1850 map->map_valcolno = atoi(map->map_valcolnm);
1851 }
1852
437376a9
EA
1853 if (tTd(38, 2))
1854 {
1714a2c7
EA
1855 printf("text_map_open(%s): delimiter = ",
1856 map->map_file);
1857 if (map->map_coldelim == '\0')
1858 printf("(white space)\n");
1859 else
1860 printf("%c\n", map->map_coldelim);
437376a9
EA
1861 }
1862
1863 return TRUE;
1864}
1865
1866
1867/*
1868** TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
1869*/
1870
1871char *
1872text_map_lookup(map, name, av, statp)
1873 MAP *map;
1874 char *name;
1875 char **av;
1876 int *statp;
1877{
1878 char *vp;
1879 auto int vsize;
1880 int buflen;
1881 char search_key[MAXNAME + 1];
1882 char linebuf[MAXLINE];
1883 FILE *f;
8446c922 1884 char buf[MAXNAME + 1];
437376a9
EA
1885 char delim;
1886 int key_idx;
1887 bool found_it;
1888 extern char *get_column();
1889
1890
1891 found_it = FALSE;
1892 if (tTd(38, 20))
1893 printf("text_map_lookup(%s)\n", name);
1894
1895 buflen = strlen(name);
1896 if (buflen > sizeof search_key - 1)
1897 buflen = sizeof search_key - 1;
1898 bcopy(name, search_key, buflen + 1);
1899 if (!bitset(MF_NOFOLDCASE, map->map_mflags))
1900 makelower(search_key);
1901
1902 f = fopen(map->map_file, "r");
1903 if (f == NULL)
1904 {
1905 map->map_mflags &= ~(MF_VALID|MF_OPEN);
1906 *statp = EX_UNAVAILABLE;
1907 return NULL;
1908 }
1909 key_idx = map->map_keycolno;
1910 delim = map->map_coldelim;
1911 while (fgets(linebuf, MAXLINE, f))
1912 {
1913 char *lf;
1914 if (linebuf[0] == '#')
1915 continue; /* skip comment line */
1916 if (lf = strchr(linebuf, '\n'))
1917 *lf = '\0';
1918 if (!strcasecmp(search_key,
1919 get_column(linebuf, key_idx, delim, buf)))
1920 {
1921 found_it = TRUE;
1922 break;
1923 }
1924 }
1925 fclose(f);
1926 if (!found_it)
1927 {
1928#ifdef MAP_EXIT_STAT
1929 *statp = EX_NOTFOUND;
1930#endif
1931 return(NULL);
1932 }
1933 vp = get_column(linebuf, map->map_valcolno, delim, buf);
1934 vsize = strlen(vp);
1935#ifdef MAP_EXIT_STAT
1936 *statp = EX_OK;
1937#endif
1938 if (bitset(MF_MATCHONLY, map->map_mflags))
1939 return map_rewrite(map, name, strlen(name), NULL);
1940 else
1941 return map_rewrite(map, vp, vsize, av);
1942}
f0416b32
EA
1943
1944
1945/*
1946** TEXT_GETCANONNAME -- look up canonical name in hosts file
1947*/
1948
1949bool
1950text_getcanonname(name, hbsize, statp)
1951 char *name;
1952 int hbsize;
1953 int *statp;
1954{
1955 int buflen;
1956 char delim;
1957 int key_idx;
1958 char *cname;
1959 bool found;
1960 char *domain;
1961 FILE *f;
1962 char linebuf[MAXLINE];
1963 char cbuf[MAXNAME + 1];
1964 char buf[MAXNAME + 1];
1965 extern char *get_column();
1966
1967 shorten_hostname(name);
1968
1969 /* we only accept single token search key */
1970 if (strchr(name, '.') != NULL)
1971 {
1972 *statp = EX_NOHOST;
1973 return FALSE;
1974 }
1975
1976 found = FALSE;
1977
1978 f = fopen(HostsFile, "r");
1979 if (f == NULL)
1980 {
1981#ifdef MAP_EXIT_STAT
1982 *statp = EX_UNAVAILABLE;
1983#endif
1984 return FALSE;
1985 }
1986 delim = '\t';
1987 while (!found && fgets(linebuf, MAXLINE, f) != NULL)
1988 {
1989 char *p;
1990
1991 if (linebuf[0] == '#')
1992 continue;
1993 if ((p = strchr(linebuf, '\n')) != NULL)
1994 *p = '\0';
1995 cname = get_column(linebuf, 1, delim, cbuf);
1996 if (cname != NULL && strcasecmp(name, cname) == 0)
1997 {
1998 found = TRUE;
1999 break;
2000 }
2001
2002 key_idx = 2;
2003 while ((p = get_column(linebuf, key_idx, delim, buf)) != NULL)
2004 {
2005 if (strcasecmp(name, p) == 0)
2006 {
2007 found = TRUE;
2008 break;
2009 }
2010 key_idx++;
2011 }
2012 }
2013 fclose(f);
2014 if (!found)
2015 {
2016 *statp = EX_NOHOST;
2017 return FALSE;
2018 }
2019
2020 if (hbsize >= strlen(cname))
2021 {
2022 strcpy(name, cname);
2023 *statp = EX_OK;
2024 return TRUE;
2025 }
2026 *statp = EX_UNAVAILABLE;
2027 return FALSE;
2028}
437376a9 2029\f/*
713c523f
EA
2030** STAB (Symbol Table) Modules
2031*/
2032
2033
2034/*
31f1ab13 2035** STAB_MAP_LOOKUP -- look up alias in symbol table
713c523f
EA
2036*/
2037
2038char *
a3934270 2039stab_map_lookup(map, name, av, pstat)
713c523f
EA
2040 register MAP *map;
2041 char *name;
a3934270
EA
2042 char **av;
2043 int *pstat;
713c523f
EA
2044{
2045 register STAB *s;
2046
36b09297 2047 if (tTd(38, 20))
e7f5a48c
EA
2048 printf("stab_lookup(%s, %s)\n",
2049 map->map_mname, name);
713c523f
EA
2050
2051 s = stab(name, ST_ALIAS, ST_FIND);
2052 if (s != NULL)
2053 return (s->s_alias);
2054 return (NULL);
2055}
2056
2057
2058/*
31f1ab13 2059** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
713c523f
EA
2060*/
2061
2062void
2063stab_map_store(map, lhs, rhs)
2064 register MAP *map;
2065 char *lhs;
2066 char *rhs;
2067{
2068 register STAB *s;
2069
2070 s = stab(lhs, ST_ALIAS, ST_ENTER);
2071 s->s_alias = newstr(rhs);
2072}
2073
2074
2075/*
31f1ab13
EA
2076** STAB_MAP_OPEN -- initialize (reads data file)
2077**
2078** This is a wierd case -- it is only intended as a fallback for
2079** aliases. For this reason, opens for write (only during a
2080** "newaliases") always fails, and opens for read open the
2081** actual underlying text file instead of the database.
713c523f
EA
2082*/
2083
2084bool
2085stab_map_open(map, mode)
2086 register MAP *map;
2087 int mode;
2088{
1fe2880b 2089 FILE *af;
28f94061 2090 struct stat st;
1fe2880b 2091
36b09297 2092 if (tTd(38, 2))
e7f5a48c
EA
2093 printf("stab_map_open(%s, %s)\n",
2094 map->map_mname, map->map_file);
713c523f
EA
2095
2096 if (mode != O_RDONLY)
31f1ab13
EA
2097 {
2098 errno = ENODEV;
713c523f 2099 return FALSE;
31f1ab13 2100 }
713c523f 2101
1fe2880b
EA
2102 af = fopen(map->map_file, "r");
2103 if (af == NULL)
2104 return FALSE;
d023870f 2105 readaliases(map, af, FALSE, FALSE);
28f94061
EA
2106
2107 if (fstat(fileno(af), &st) >= 0)
2108 map->map_mtime = st.st_mtime;
1fe2880b
EA
2109 fclose(af);
2110
713c523f
EA
2111 return TRUE;
2112}
713c523f
EA
2113\f/*
2114** Implicit Modules
2115**
2116** Tries several types. For back compatibility of aliases.
2117*/
2118
2119
2120/*
31f1ab13 2121** IMPL_MAP_LOOKUP -- lookup in best open database
713c523f
EA
2122*/
2123
2124char *
2125impl_map_lookup(map, name, av, pstat)
2126 MAP *map;
2127 char *name;
2128 char **av;
2129 int *pstat;
2130{
36b09297 2131 if (tTd(38, 20))
e7f5a48c
EA
2132 printf("impl_map_lookup(%s, %s)\n",
2133 map->map_mname, name);
713c523f
EA
2134
2135#ifdef NEWDB
31f1ab13 2136 if (bitset(MF_IMPL_HASH, map->map_mflags))
713c523f
EA
2137 return db_map_lookup(map, name, av, pstat);
2138#endif
2139#ifdef NDBM
31f1ab13 2140 if (bitset(MF_IMPL_NDBM, map->map_mflags))
713c523f
EA
2141 return ndbm_map_lookup(map, name, av, pstat);
2142#endif
2143 return stab_map_lookup(map, name, av, pstat);
2144}
2145
2146/*
31f1ab13 2147** IMPL_MAP_STORE -- store in open databases
713c523f
EA
2148*/
2149
2150void
2151impl_map_store(map, lhs, rhs)
2152 MAP *map;
2153 char *lhs;
2154 char *rhs;
2155{
2156#ifdef NEWDB
31f1ab13 2157 if (bitset(MF_IMPL_HASH, map->map_mflags))
713c523f
EA
2158 db_map_store(map, lhs, rhs);
2159#endif
2160#ifdef NDBM
31f1ab13 2161 if (bitset(MF_IMPL_NDBM, map->map_mflags))
713c523f
EA
2162 ndbm_map_store(map, lhs, rhs);
2163#endif
2164 stab_map_store(map, lhs, rhs);
2165}
2166
2167/*
2168** IMPL_MAP_OPEN -- implicit database open
2169*/
2170
2171bool
2172impl_map_open(map, mode)
2173 MAP *map;
2174 int mode;
2175{
2176 struct stat stb;
2177
36b09297 2178 if (tTd(38, 2))
e7f5a48c
EA
2179 printf("impl_map_open(%s, %s, %d)\n",
2180 map->map_mname, map->map_file, mode);
713c523f
EA
2181
2182 if (stat(map->map_file, &stb) < 0)
2183 {
2184 /* no alias file at all */
fe3849ea
EA
2185 if (tTd(38, 3))
2186 printf("no map file\n");
713c523f
EA
2187 return FALSE;
2188 }
2189
2190#ifdef NEWDB
31f1ab13 2191 map->map_mflags |= MF_IMPL_HASH;
713c523f
EA
2192 if (hash_map_open(map, mode))
2193 {
35ef9fff 2194#if defined(NDBM) && defined(NIS)
08979aed 2195 if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0)
31f1ab13
EA
2196#endif
2197 return TRUE;
713c523f 2198 }
31f1ab13
EA
2199 else
2200 map->map_mflags &= ~MF_IMPL_HASH;
713c523f
EA
2201#endif
2202#ifdef NDBM
31f1ab13 2203 map->map_mflags |= MF_IMPL_NDBM;
713c523f
EA
2204 if (ndbm_map_open(map, mode))
2205 {
713c523f
EA
2206 return TRUE;
2207 }
31f1ab13
EA
2208 else
2209 map->map_mflags &= ~MF_IMPL_NDBM;
713c523f
EA
2210#endif
2211
ed6d397f 2212#if defined(NEWDB) || defined(NDBM)
713c523f
EA
2213 if (Verbose)
2214 message("WARNING: cannot open alias database %s", map->map_file);
c601f599
EA
2215#else
2216 if (mode != O_RDONLY)
2217 usrerr("Cannot rebuild aliases: no database format defined");
31f1ab13 2218#endif
713c523f 2219
31f1ab13 2220 return stab_map_open(map, mode);
713c523f
EA
2221}
2222
31f1ab13 2223
713c523f 2224/*
31f1ab13 2225** IMPL_MAP_CLOSE -- close any open database(s)
713c523f
EA
2226*/
2227
2228void
31f1ab13 2229impl_map_close(map)
713c523f 2230 MAP *map;
713c523f 2231{
fd6d3804
EA
2232 if (tTd(38, 20))
2233 printf("impl_map_close(%s, %s, %x)\n",
2234 map->map_mname, map->map_file, map->map_mflags);
713c523f 2235#ifdef NEWDB
31f1ab13 2236 if (bitset(MF_IMPL_HASH, map->map_mflags))
713c523f 2237 {
31f1ab13
EA
2238 db_map_close(map);
2239 map->map_mflags &= ~MF_IMPL_HASH;
713c523f
EA
2240 }
2241#endif
2242
2243#ifdef NDBM
31f1ab13 2244 if (bitset(MF_IMPL_NDBM, map->map_mflags))
713c523f 2245 {
31f1ab13
EA
2246 ndbm_map_close(map);
2247 map->map_mflags &= ~MF_IMPL_NDBM;
713c523f
EA
2248 }
2249#endif
713c523f 2250}
31f1ab13 2251\f/*
e7f5a48c
EA
2252** User map class.
2253**
2254** Provides access to the system password file.
2255*/
2256
2257/*
2258** USER_MAP_OPEN -- open user map
2259**
2260** Really just binds field names to field numbers.
2261*/
2262
2263bool
2264user_map_open(map, mode)
2265 MAP *map;
2266 int mode;
2267{
2268 if (tTd(38, 2))
2269 printf("user_map_open(%s)\n", map->map_mname);
2270
2271 if (mode != O_RDONLY)
2272 {
2273 /* issue a pseudo-error message */
2274#ifdef ENOSYS
2275 errno = ENOSYS;
2276#else
2277# ifdef EFTYPE
2278 errno = EFTYPE;
2279# else
2280 errno = ENXIO;
2281# endif
2282#endif
2283 return FALSE;
2284 }
2285 if (map->map_valcolnm == NULL)
2286 /* nothing */ ;
2287 else if (strcasecmp(map->map_valcolnm, "name") == 0)
2288 map->map_valcolno = 1;
2289 else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
2290 map->map_valcolno = 2;
2291 else if (strcasecmp(map->map_valcolnm, "uid") == 0)
2292 map->map_valcolno = 3;
2293 else if (strcasecmp(map->map_valcolnm, "gid") == 0)
2294 map->map_valcolno = 4;
2295 else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
2296 map->map_valcolno = 5;
2297 else if (strcasecmp(map->map_valcolnm, "dir") == 0)
2298 map->map_valcolno = 6;
2299 else if (strcasecmp(map->map_valcolnm, "shell") == 0)
2300 map->map_valcolno = 7;
2301 else
2302 {
2303 syserr("User map %s: unknown column name %s",
2304 map->map_mname, map->map_valcolnm);
2305 return FALSE;
2306 }
2307 return TRUE;
2308}
2309
2310
2311/*
2312** USER_MAP_LOOKUP -- look up a user in the passwd file.
2313*/
2314
e7f5a48c
EA
2315char *
2316user_map_lookup(map, key, av, statp)
2317 MAP *map;
2318 char *key;
2319 char **av;
2320 int *statp;
2321{
2322 struct passwd *pw;
2323
2324 if (tTd(38, 20))
2325 printf("user_map_lookup(%s, %s)\n",
2326 map->map_mname, key);
2327
5b7a2dfe 2328 pw = sm_getpwnam(key);
e7f5a48c
EA
2329 if (pw == NULL)
2330 return NULL;
2331 if (bitset(MF_MATCHONLY, map->map_mflags))
2332 return map_rewrite(map, key, strlen(key), NULL);
2333 else
2334 {
ea07b2d2 2335 char *rwval = NULL;
e7f5a48c
EA
2336 char buf[30];
2337
2338 switch (map->map_valcolno)
2339 {
2340 case 0:
2341 case 1:
437376a9 2342 rwval = pw->pw_name;
e7f5a48c
EA
2343 break;
2344
2345 case 2:
2346 rwval = pw->pw_passwd;
2347 break;
2348
2349 case 3:
2350 sprintf(buf, "%d", pw->pw_uid);
2351 rwval = buf;
2352 break;
2353
2354 case 4:
2355 sprintf(buf, "%d", pw->pw_gid);
2356 rwval = buf;
2357 break;
2358
2359 case 5:
2360 rwval = pw->pw_gecos;
2361 break;
2362
2363 case 6:
2364 rwval = pw->pw_dir;
2365 break;
2366
2367 case 7:
2368 rwval = pw->pw_shell;
2369 break;
2370 }
2371 return map_rewrite(map, rwval, strlen(rwval), av);
2372 }
2373}
2374\f/*
6c0da0dd
EA
2375** BESTMX -- find the best MX for a name
2376**
2377** This is really a hack, but I don't see any obvious way
2378** to generalize it at the moment.
2379*/
2380
2381#if NAMED_BIND
2382
2383char *
2384bestmx_map_lookup(map, name, av, statp)
2385 MAP *map;
2386 char *name;
2387 char **av;
2388 int *statp;
2389{
2390 int nmx;
2391 auto int rcode;
2392 char *mxhosts[MAXMXHOSTS + 1];
2393
2394 nmx = getmxrr(name, mxhosts, FALSE, &rcode);
2395 if (nmx <= 0)
2396 return NULL;
2397 if (bitset(MF_MATCHONLY, map->map_mflags))
2398 return map_rewrite(map, name, strlen(name), NULL);
2399 else
2400 return map_rewrite(map, mxhosts[0], strlen(mxhosts[0]), av);
2401}
2402
2403#endif
2404\f/*
1c356459
EA
2405** Program map type.
2406**
2407** This provides access to arbitrary programs. It should be used
2408** only very sparingly, since there is no way to bound the cost
2409** of invoking an arbitrary program.
2410*/
2411
2412char *
2413prog_map_lookup(map, name, av, statp)
2414 MAP *map;
2415 char *name;
2416 char **av;
2417 int *statp;
2418{
2419 int i;
2420 register char *p;
2421 int fd;
2422 auto pid_t pid;
2423 char *argv[MAXPV + 1];
2424 char buf[MAXLINE];
2425
2426 if (tTd(38, 20))
2427 printf("prog_map_lookup(%s, %s) %s\n",
2428 map->map_mname, name, map->map_file);
2429
2430 i = 0;
2431 argv[i++] = map->map_file;
2432 strcpy(buf, map->map_rebuild);
2433 for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
2434 {
2435 if (i >= MAXPV - 1)
2436 break;
2437 argv[i++] = p;
2438 }
2439 argv[i++] = name;
2440 argv[i] = NULL;
2441 pid = prog_open(argv, &fd, CurEnv);
2442 if (pid < 0)
2443 {
2444 if (tTd(38, 9))
2445 printf("prog_map_lookup(%s) failed (%s) -- closing",
2446 map->map_mname, errstring(errno));
2447 map->map_mflags &= ~(MF_VALID|MF_OPEN);
2448 return NULL;
2449 }
2450 i = read(fd, buf, sizeof buf - 1);
2451 if (i <= 0 && tTd(38, 2))
2452 printf("prog_map_lookup(%s): read error %s\n",
2453 map->map_mname, strerror(errno));
2454 if (i > 0)
2455 {
2456 char *rval;
2457
2458 buf[i] = '\0';
2459 p = strchr(buf, '\n');
2460 if (p != NULL)
2461 *p = '\0';
2462
2463 /* collect the return value */
2464 if (bitset(MF_MATCHONLY, map->map_mflags))
2465 rval = map_rewrite(map, name, strlen(name), NULL);
2466 else
2467 rval = map_rewrite(map, buf, strlen(buf), NULL);
2468
2469 /* now flush any additional output */
2470 while ((i = read(fd, buf, sizeof buf)) > 0)
2471 continue;
2472 close(fd);
2473
2474 /* and wait for the process to terminate */
2475 *statp = waitfor(pid);
2476
2477 return rval;
2478 }
2479
2480 close(fd);
2481 *statp = waitfor(pid);
2482 return NULL;
2483}
2484\f/*
e7f5a48c
EA
2485** Sequenced map type.
2486**
2487** Tries each map in order until something matches, much like
2488** implicit. Stores go to the first map in the list that can
2489** support storing.
437376a9
EA
2490**
2491** This is slightly unusual in that there are two interfaces.
2492** The "sequence" interface lets you stack maps arbitrarily.
2493** The "switch" interface builds a sequence map by looking
2494** at a system-dependent configuration file such as
2495** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
2496**
2497** We don't need an explicit open, since all maps are
2498** opened during startup, including underlying maps.
e7f5a48c
EA
2499*/
2500
2501/*
2502** SEQ_MAP_PARSE -- Sequenced map parsing
2503*/
2504
2505bool
2506seq_map_parse(map, ap)
2507 MAP *map;
2508 char *ap;
2509{
2510 int maxmap;
2511
2512 if (tTd(38, 2))
2513 printf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
2514 maxmap = 0;
2515 while (*ap != '\0')
2516 {
2517 register char *p;
2518 STAB *s;
2519
2520 /* find beginning of map name */
2521 while (isascii(*ap) && isspace(*ap))
2522 ap++;
2523 for (p = ap; isascii(*p) && isalnum(*p); p++)
2524 continue;
2525 if (*p != '\0')
2526 *p++ = '\0';
2527 while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
2528 p++;
2529 if (*ap == '\0')
2530 {
2531 ap = p;
2532 continue;
2533 }
2534 s = stab(ap, ST_MAP, ST_FIND);
2535 if (s == NULL)
2536 {
2537 syserr("Sequence map %s: unknown member map %s",
2538 map->map_mname, ap);
2539 }
2540 else if (maxmap == MAXMAPSTACK)
2541 {
2542 syserr("Sequence map %s: too many member maps (%d max)",
2543 map->map_mname, MAXMAPSTACK);
2544 maxmap++;
2545 }
2546 else if (maxmap < MAXMAPSTACK)
2547 {
2548 map->map_stack[maxmap++] = &s->s_map;
2549 }
2550 ap = p;
2551 }
2552 return TRUE;
2553}
2554
2555
437376a9
EA
2556/*
2557** SWITCH_MAP_OPEN -- open a switched map
2558**
2559** This looks at the system-dependent configuration and builds
2560** a sequence map that does the same thing.
2561**
2562** Every system must define a switch_map_find routine in conf.c
2563** that will return the list of service types associated with a
2564** given service class.
2565*/
2566
2567bool
2568switch_map_open(map, mode)
2569 MAP *map;
2570 int mode;
2571{
2572 int mapno;
2573 int nmaps;
2574 char *maptype[MAXMAPSTACK];
2575
2576 if (tTd(38, 2))
2577 printf("switch_map_open(%s, %s, %d)\n",
2578 map->map_mname, map->map_file, mode);
2579
10adf2ed 2580 nmaps = switch_map_find(map->map_file, maptype, map->map_return);
437376a9
EA
2581 if (tTd(38, 19))
2582 {
2583 printf("\tswitch_map_find => %d\n", nmaps);
2584 for (mapno = 0; mapno < nmaps; mapno++)
2585 printf("\t\t%s\n", maptype[mapno]);
2586 }
2587 if (nmaps <= 0 || nmaps > MAXMAPSTACK)
2588 return FALSE;
2589
2590 for (mapno = 0; mapno < nmaps; mapno++)
2591 {
2592 register STAB *s;
2593 char nbuf[MAXNAME + 1];
2594
2595 if (maptype[mapno] == NULL)
2596 continue;
2597 (void) sprintf(nbuf, "%s.%s", map->map_file, maptype[mapno]);
2598 s = stab(nbuf, ST_MAP, ST_FIND);
2599 if (s == NULL)
2600 {
2601 syserr("Switch map %s: unknown member map %s",
2602 map->map_mname, nbuf);
2603 }
2604 else
2605 {
2606 map->map_stack[mapno] = &s->s_map;
2607 if (tTd(38, 4))
2608 printf("\tmap_stack[%d] = %s:%s\n",
2609 mapno, s->s_map.map_class->map_cname,
2610 nbuf);
2611 }
2612 }
2613 return TRUE;
2614}
2615
2616
2617/*
2618** SEQ_MAP_CLOSE -- close all underlying maps
2619*/
2620
2621seq_map_close(map)
2622 MAP *map;
2623{
2624 int mapno;
2625
2626 if (tTd(38, 20))
2627 printf("seq_map_close(%s)\n", map->map_mname);
2628 for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
2629 {
2630 MAP *mm = map->map_stack[mapno];
2631
2632 if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
2633 continue;
2634 mm->map_class->map_close(mm);
9c9c4ae2 2635 mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
437376a9
EA
2636 }
2637}
2638
2639
e7f5a48c
EA
2640/*
2641** SEQ_MAP_LOOKUP -- sequenced map lookup
2642*/
2643
2644char *
2645seq_map_lookup(map, key, args, pstat)
2646 MAP *map;
2647 char *key;
2648 char **args;
2649 int *pstat;
2650{
2651 int mapno;
2652 int mapbit = 0x01;
2653
2654 if (tTd(38, 20))
2655 printf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
2656
2657 for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
2658 {
2659 MAP *mm = map->map_stack[mapno];
2660 int stat = 0;
2661 char *rv;
2662
2663 if (mm == NULL)
2664 continue;
2665 if (!bitset(MF_OPEN, mm->map_mflags))
2666 {
2667 if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
437376a9
EA
2668 {
2669 *pstat = EX_UNAVAILABLE;
e7f5a48c 2670 return NULL;
437376a9 2671 }
e7f5a48c
EA
2672 continue;
2673 }
2674 rv = mm->map_class->map_lookup(mm, key, args, &stat);
2675 if (rv != NULL)
2676 return rv;
2677 if (stat == 0 && bitset(mapbit, map->map_return[MA_NOTFOUND]))
2678 return NULL;
2679 if (stat != 0 && bitset(mapbit, map->map_return[MA_TRYAGAIN]))
2680 {
2681 *pstat = stat;
2682 return NULL;
2683 }
2684 }
2685 return NULL;
2686}
2687
2688
2689/*
2690** SEQ_MAP_STORE -- sequenced map store
2691*/
2692
2693void
2694seq_map_store(map, key, val)
2695 MAP *map;
2696 char *key;
2697 char *val;
2698{
2699 int mapno;
2700
2701 if (tTd(38, 12))
2702 printf("seq_map_store(%s, %s, %s)\n",
2703 map->map_mname, key, val);
2704
2705 for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
2706 {
2707 MAP *mm = map->map_stack[mapno];
2708
2709 if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
2710 continue;
2711
2712 mm->map_class->map_store(mm, key, val);
2713 return;
2714 }
2715 syserr("seq_map_store(%s, %s, %s): no writable map",
2716 map->map_mname, key, val);
2717}
2718\f/*
f0416b32
EA
2719** GETCANONNAME -- look up name using service switch
2720**
2721** Parameters:
2722** host -- the host name to look up.
2723** hbsize -- the size of the host buffer.
2724** trymx -- if set, try MX records.
2725**
2726** Returns:
2727** TRUE -- if the host was found.
2728** FALSE -- otherwise.
2729*/
2730
2731bool
2732getcanonname(host, hbsize, trymx)
2733 char *host;
2734 int hbsize;
2735 bool trymx;
2736{
2737 int nmaps;
2738 int mapno;
2739 bool found = FALSE;
2740 auto int stat;
2741 char *maptype[MAXMAPSTACK];
2742 short mapreturn[MAXMAPACTIONS];
2743 extern int h_errno;
2744
2745 nmaps = switch_map_find("hosts", maptype, mapreturn);
2746 for (mapno = 0; mapno < nmaps; mapno++)
2747 {
2748 int i;
2749
2750 if (tTd(38, 20))
2751 printf("getcanonname(%s), trying %s\n",
2752 host, maptype[mapno]);
2753 if (strcmp("files", maptype[mapno]) == 0)
2754 found = text_getcanonname(host, hbsize, &stat);
2755#ifdef NIS
2756 else if (strcmp("nis", maptype[mapno]) == 0)
2757 found = nis_getcanonname(host, hbsize, &stat);
2758#endif
2759#ifdef NISPLUS
2760 else if (strcmp("nisplus", maptype[mapno]) == 0)
2761 found = nisplus_getcanonname(host, hbsize, &stat);
2762#endif
2763#if NAMED_BIND
2764 else if (strcmp("dns", maptype[mapno]) == 0)
2765 found = dns_getcanonname(host, hbsize, trymx, &stat);
2766#endif
2767 else
2768 {
2769 found = FALSE;
2770 stat = EX_UNAVAILABLE;
2771 }
2772 if (found)
2773 break;
2774
2775 /* see if we should continue */
2776 if (stat == EX_TEMPFAIL)
2777 i = MA_TRYAGAIN;
2778 else if (stat == EX_NOHOST)
2779 i = MA_NOTFOUND;
2780 else
2781 i = MA_UNAVAIL;
2782 if (bitset(1 << mapno, mapreturn[i]))
2783 break;
2784 }
2785
2786 if (found)
2787 {
2788 char *d;
2789
2790 if (tTd(38, 20))
2791 printf("getcanonname(%s), found\n", host);
2792
2793 /*
2794 ** If returned name is still single token, compensate
2795 ** by tagging on $m. This is because some sites set
2796 ** up their DNS or NIS databases wrong.
2797 */
2798
2799 if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
2800 {
2801 d = macvalue('m', CurEnv);
2802 if (d != NULL &&
2803 hbsize > (int) (strlen(host) + strlen(d) + 1))
2804 {
2805 if (host[strlen(host) - 1] != '.')
2806 strcat(host, ".");
2807 strcat(host, d);
2808 }
2809 else
2810 {
2811 return FALSE;
2812 }
2813 }
2814 return TRUE;
2815 }
2816
2817 if (tTd(38, 20))
2818 printf("getcanonname(%s), failed, stat=%d\n", host, stat);
2819
2820#if NAMED_BIND
2821 if (stat == EX_NOHOST)
2822 h_errno = HOST_NOT_FOUND;
2823 else
2824 h_errno = TRY_AGAIN;
2825#endif
2826
2827 return FALSE;
2828}
2829\f/*
31f1ab13 2830** NULL stubs
713c523f
EA
2831*/
2832
31f1ab13
EA
2833bool
2834null_map_open(map, mode)
713c523f 2835 MAP *map;
31f1ab13 2836 int mode;
713c523f 2837{
31f1ab13 2838 return TRUE;
713c523f 2839}
713c523f 2840
31f1ab13
EA
2841void
2842null_map_close(map)
2843 MAP *map;
713c523f 2844{
31f1ab13
EA
2845 return;
2846}
713c523f 2847
31f1ab13
EA
2848void
2849null_map_store(map, key, val)
2850 MAP *map;
2851 char *key;
2852 char *val;
713c523f 2853{
31f1ab13 2854 return;
4cb3af58 2855}
22944c86
EA
2856
2857
2858/*
2859** BOGUS stubs
2860*/
2861
2862char *
2863bogus_map_lookup(map, key, args, pstat)
2864 MAP *map;
2865 char *key;
2866 char **args;
2867 int *pstat;
2868{
2869 *pstat = EX_TEMPFAIL;
2870 return NULL;
2871}
2872
2873MAPCLASS BogusMapClass =
2874{
2875 "bogus-map", NULL, 0,
2876 NULL, bogus_map_lookup, null_map_store,
2877 null_map_open, null_map_close,
2878};