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