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