156822Seric /* 256822Seric * Copyright (c) 1992 Eric P. Allman. 362526Sbostic * Copyright (c) 1992, 1993 462526Sbostic * The Regents of the University of California. All rights reserved. 556822Seric * 656822Seric * %sccs.include.redist.c% 756822Seric */ 856822Seric 956822Seric #ifndef lint 10*64671Seric static char sccsid[] = "@(#)map.c 8.15 (Berkeley) 09/27/93"; 1156822Seric #endif /* not lint */ 1256822Seric 1356822Seric #include "sendmail.h" 1456822Seric 1560089Seric #ifdef NDBM 1656822Seric #include <ndbm.h> 1756822Seric #endif 1860089Seric #ifdef NEWDB 1956822Seric #include <db.h> 2056822Seric #endif 2160089Seric #ifdef NIS 2257208Seric #include <rpcsvc/ypclnt.h> 2357208Seric #endif 2456822Seric 2556822Seric /* 2660089Seric ** MAP.C -- implementations for various map classes. 2756822Seric ** 2860089Seric ** Each map class implements a series of functions: 2960089Seric ** 3060089Seric ** bool map_parse(MAP *map, char *args) 3160089Seric ** Parse the arguments from the config file. Return TRUE 3260089Seric ** if they were ok, FALSE otherwise. Fill in map with the 3360089Seric ** values. 3460089Seric ** 3560222Seric ** char *map_lookup(MAP *map, char *key, char **args, int *pstat) 3660222Seric ** Look up the key in the given map. If found, do any 3760222Seric ** rewriting the map wants (including "args" if desired) 3860089Seric ** and return the value. Set *pstat to the appropriate status 3960222Seric ** on error and return NULL. Args will be NULL if called 4060222Seric ** from the alias routines, although this should probably 4160222Seric ** not be relied upon. It is suggested you call map_rewrite 4260222Seric ** to return the results -- it takes care of null termination 4360222Seric ** and uses a dynamically expanded buffer as needed. 4460089Seric ** 4560089Seric ** void map_store(MAP *map, char *key, char *value) 4660089Seric ** Store the key:value pair in the map. 4760089Seric ** 4860089Seric ** bool map_open(MAP *map, int mode) 4960222Seric ** Open the map for the indicated mode. Mode should 5060222Seric ** be either O_RDONLY or O_RDWR. Return TRUE if it 5160222Seric ** was opened successfully, FALSE otherwise. If the open 5260222Seric ** failed an the MF_OPTIONAL flag is not set, it should 5360222Seric ** also print an error. If the MF_ALIAS bit is set 5460222Seric ** and this map class understands the @:@ convention, it 5560222Seric ** should call aliaswait() before returning. 5660089Seric ** 5760089Seric ** void map_close(MAP *map) 5860089Seric ** Close the map. 5960089Seric */ 6060089Seric 6160089Seric #define DBMMODE 0644 6260089Seric /* 6360089Seric ** MAP_PARSEARGS -- parse config line arguments for database lookup 6460089Seric ** 6560089Seric ** This is a generic version of the map_parse method. 6660089Seric ** 6756822Seric ** Parameters: 6860089Seric ** map -- the map being initialized. 6960089Seric ** ap -- a pointer to the args on the config line. 7056822Seric ** 7156822Seric ** Returns: 7260089Seric ** TRUE -- if everything parsed OK. 7356822Seric ** FALSE -- otherwise. 7456822Seric ** 7556822Seric ** Side Effects: 7660089Seric ** null terminates the filename; stores it in map 7756822Seric */ 7856822Seric 7956822Seric bool 8060089Seric map_parseargs(map, ap) 8156822Seric MAP *map; 8260089Seric char *ap; 8356822Seric { 8460089Seric register char *p = ap; 8556822Seric 8663753Seric map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL; 8760089Seric for (;;) 8860089Seric { 8960089Seric while (isascii(*p) && isspace(*p)) 9060089Seric p++; 9160089Seric if (*p != '-') 9260089Seric break; 9360089Seric switch (*++p) 9460089Seric { 9560089Seric case 'N': 9660207Seric map->map_mflags |= MF_INCLNULL; 9763753Seric map->map_mflags &= ~MF_TRY0NULL; 9860089Seric break; 9960089Seric 10063753Seric case 'O': 10163753Seric map->map_mflags &= ~MF_TRY1NULL; 10263753Seric break; 10363753Seric 10460089Seric case 'o': 10560207Seric map->map_mflags |= MF_OPTIONAL; 10660089Seric break; 10760089Seric 10860089Seric case 'f': 10960207Seric map->map_mflags |= MF_NOFOLDCASE; 11060089Seric break; 11160089Seric 11260089Seric case 'm': 11360207Seric map->map_mflags |= MF_MATCHONLY; 11460089Seric break; 11560089Seric 11660089Seric case 'a': 11760089Seric map->map_app = ++p; 11860089Seric break; 11960089Seric } 12060089Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 12160089Seric p++; 12260089Seric if (*p != '\0') 12360089Seric *p++ = '\0'; 12460089Seric } 12560089Seric if (map->map_app != NULL) 12660089Seric map->map_app = newstr(map->map_app); 12760089Seric 12860089Seric if (*p != '\0') 12960089Seric { 13060089Seric map->map_file = p; 13160089Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 13260089Seric p++; 13360089Seric if (*p != '\0') 13460089Seric *p++ = '\0'; 13560089Seric map->map_file = newstr(map->map_file); 13660089Seric } 13760089Seric 13860089Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 13960089Seric p++; 14060089Seric if (*p != '\0') 14160089Seric map->map_rebuild = newstr(p); 14260089Seric 14356822Seric if (map->map_file == NULL) 14457208Seric { 14560089Seric syserr("No file name for %s map %s", 14660089Seric map->map_class->map_cname, map->map_mname); 14756822Seric return FALSE; 14857208Seric } 14960089Seric return TRUE; 15060089Seric } 15160089Seric /* 15260089Seric ** MAP_REWRITE -- rewrite a database key, interpolating %n indications. 15360089Seric ** 15460089Seric ** It also adds the map_app string. It can be used as a utility 15560089Seric ** in the map_lookup method. 15660089Seric ** 15760089Seric ** Parameters: 15860089Seric ** map -- the map that causes this. 15960089Seric ** s -- the string to rewrite, NOT necessarily null terminated. 16060089Seric ** slen -- the length of s. 16160089Seric ** av -- arguments to interpolate into buf. 16260089Seric ** 16360089Seric ** Returns: 16460089Seric ** Pointer to rewritten result. 16560089Seric ** 16660089Seric ** Side Effects: 16760089Seric ** none. 16860089Seric */ 16960089Seric 17060492Seric struct rwbuf 17160492Seric { 17260492Seric int rwb_len; /* size of buffer */ 17360492Seric char *rwb_buf; /* ptr to buffer */ 17460492Seric }; 17560492Seric 17660492Seric struct rwbuf RwBufs[2]; /* buffers for rewriting output */ 17760492Seric 17860089Seric char * 17960089Seric map_rewrite(map, s, slen, av) 18060089Seric register MAP *map; 18160089Seric register char *s; 18260089Seric int slen; 18360089Seric char **av; 18460089Seric { 18560089Seric register char *bp; 18660089Seric register char c; 18760089Seric char **avp; 18860089Seric register char *ap; 18960492Seric register struct rwbuf *rwb; 19060089Seric int i; 19160089Seric int len; 19260089Seric 19360537Seric if (tTd(39, 1)) 19460089Seric { 19560256Seric printf("map_rewrite(%.*s), av =", slen, s); 19660256Seric if (av == NULL) 19760256Seric printf(" (nullv)"); 19860256Seric else 19960256Seric { 20060256Seric for (avp = av; *avp != NULL; avp++) 20160256Seric printf("\n\t%s", *avp); 20260256Seric } 20360256Seric printf("\n"); 20460089Seric } 20560089Seric 20660492Seric rwb = RwBufs; 20760492Seric if (av == NULL) 20860492Seric rwb++; 20960492Seric 21060089Seric /* count expected size of output (can safely overestimate) */ 21160089Seric i = len = slen; 21260089Seric if (av != NULL) 21360089Seric { 21460089Seric bp = s; 21560089Seric for (i = slen; --i >= 0 && (c = *bp++) != 0; ) 21660089Seric { 21760089Seric if (c != '%') 21860089Seric continue; 21960089Seric if (--i < 0) 22060089Seric break; 22160089Seric c = *bp++; 22260089Seric if (!(isascii(c) && isdigit(c))) 22360089Seric continue; 22463937Seric for (avp = av; --c >= '0' && *avp != NULL; avp++) 22560089Seric continue; 22660089Seric if (*avp == NULL) 22760089Seric continue; 22860089Seric len += strlen(*avp); 22960089Seric } 23060089Seric } 23160089Seric if (map->map_app != NULL) 23260089Seric len += strlen(map->map_app); 23360492Seric if (rwb->rwb_len < ++len) 23460089Seric { 23560089Seric /* need to malloc additional space */ 23660492Seric rwb->rwb_len = len; 23760492Seric if (rwb->rwb_buf != NULL) 23860492Seric free(rwb->rwb_buf); 23960492Seric rwb->rwb_buf = xalloc(rwb->rwb_len); 24060089Seric } 24160089Seric 24260492Seric bp = rwb->rwb_buf; 24360089Seric if (av == NULL) 24460089Seric { 24560089Seric bcopy(s, bp, slen); 24660089Seric bp += slen; 24760089Seric } 24860089Seric else 24960089Seric { 25060089Seric while (--slen >= 0 && (c = *s++) != '\0') 25160089Seric { 25260089Seric if (c != '%') 25360089Seric { 25460089Seric pushc: 25560089Seric *bp++ = c; 25660089Seric continue; 25760089Seric } 25860089Seric if (--slen < 0 || (c = *s++) == '\0') 25960089Seric c = '%'; 26060089Seric if (c == '%') 26160089Seric goto pushc; 26260089Seric if (!(isascii(c) && isdigit(c))) 26360089Seric { 26460089Seric *bp++ = '%'; 26560089Seric goto pushc; 26660089Seric } 26763937Seric for (avp = av; --c >= '0' && *avp != NULL; avp++) 26860089Seric continue; 26960089Seric if (*avp == NULL) 27060089Seric continue; 27160089Seric 27260089Seric /* transliterate argument into output string */ 27360089Seric for (ap = *avp; (c = *ap++) != '\0'; ) 27460089Seric *bp++ = c; 27560089Seric } 27660089Seric } 27760089Seric if (map->map_app != NULL) 27860089Seric strcpy(bp, map->map_app); 27960089Seric else 28060089Seric *bp = '\0'; 28160537Seric if (tTd(39, 1)) 28260492Seric printf("map_rewrite => %s\n", rwb->rwb_buf); 28360492Seric return rwb->rwb_buf; 28460089Seric } 28560089Seric /* 28660537Seric ** INITMAPS -- initialize for aliasing 28760537Seric ** 28860537Seric ** Parameters: 28960537Seric ** rebuild -- if TRUE, this rebuilds the cached versions. 29060537Seric ** e -- current envelope. 29160537Seric ** 29260537Seric ** Returns: 29360537Seric ** none. 29460537Seric ** 29560537Seric ** Side Effects: 29660537Seric ** initializes aliases: 29760537Seric ** if NDBM: opens the database. 29860537Seric ** if ~NDBM: reads the aliases into the symbol table. 29960537Seric */ 30060537Seric 30160537Seric initmaps(rebuild, e) 30260537Seric bool rebuild; 30360537Seric register ENVELOPE *e; 30460537Seric { 30560537Seric extern void map_init(); 30660537Seric 307*64671Seric #ifdef XDEBUG 308*64671Seric checkfd012("entering initmaps"); 309*64671Seric #endif 31060537Seric CurEnv = e; 31160537Seric stabapply(map_init, rebuild); 312*64671Seric #ifdef XDEBUG 313*64671Seric checkfd012("exiting initmaps"); 314*64671Seric #endif 31560537Seric } 31660537Seric 31760537Seric void 31860537Seric map_init(s, rebuild) 31960537Seric register STAB *s; 32060537Seric int rebuild; 32160537Seric { 32260537Seric register MAP *map; 32360537Seric 32460537Seric /* has to be a map */ 32560537Seric if (s->s_type != ST_MAP) 32660537Seric return; 32760537Seric 32860537Seric map = &s->s_map; 32960537Seric if (!bitset(MF_VALID, map->map_mflags)) 33060537Seric return; 33160537Seric 33260537Seric if (tTd(38, 2)) 33360537Seric printf("map_init(%s:%s)\n", 33460537Seric map->map_class->map_cname, map->map_file); 33560537Seric 33660537Seric /* if already open, close it (for nested open) */ 33760537Seric if (bitset(MF_OPEN, map->map_mflags)) 33860537Seric { 33960537Seric map->map_class->map_close(map); 34060537Seric map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 34160537Seric } 34260537Seric 34360537Seric if (rebuild) 34460537Seric { 34560926Seric if (bitset(MF_ALIAS, map->map_mflags) && 34660926Seric bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 34760537Seric rebuildaliases(map, FALSE); 34860537Seric } 34960537Seric else 35060537Seric { 35160537Seric if (map->map_class->map_open(map, O_RDONLY)) 35260537Seric { 35360537Seric if (tTd(38, 4)) 35460537Seric printf("%s:%s: valid\n", 35560537Seric map->map_class->map_cname, 35660537Seric map->map_file); 35760537Seric map->map_mflags |= MF_OPEN; 35860537Seric } 35960537Seric else if (tTd(38, 4)) 36060537Seric printf("%s:%s: invalid: %s\n", 36160537Seric map->map_class->map_cname, 36260537Seric map->map_file, 36360537Seric errstring(errno)); 36460537Seric } 36560537Seric } 36660537Seric /* 36760089Seric ** NDBM modules 36860089Seric */ 36960089Seric 37060089Seric #ifdef NDBM 37160089Seric 37260089Seric /* 37360089Seric ** DBM_MAP_OPEN -- DBM-style map open 37460089Seric */ 37560089Seric 37660089Seric bool 37760089Seric ndbm_map_open(map, mode) 37860089Seric MAP *map; 37960089Seric int mode; 38060089Seric { 38164284Seric register DBM *dbm; 38264284Seric struct stat st; 38360089Seric 38460537Seric if (tTd(38, 2)) 38560089Seric printf("ndbm_map_open(%s, %d)\n", map->map_file, mode); 38660089Seric 38760207Seric if (mode == O_RDWR) 38860207Seric mode |= O_CREAT|O_TRUNC; 38960207Seric 39060089Seric /* open the database */ 39160089Seric dbm = dbm_open(map->map_file, mode, DBMMODE); 39256822Seric if (dbm == NULL) 39356822Seric { 39460207Seric if (!bitset(MF_OPTIONAL, map->map_mflags)) 39556836Seric syserr("Cannot open DBM database %s", map->map_file); 39656822Seric return FALSE; 39756822Seric } 39860089Seric map->map_db1 = (void *) dbm; 39960207Seric if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 40060604Seric aliaswait(map, ".pag"); 40164284Seric if (fstat(dbm_dirfno(dbm), &st) >= 0) 40264284Seric map->map_mtime = st.st_mtime; 40356822Seric return TRUE; 40456822Seric } 40560089Seric 40660089Seric 40760089Seric /* 40856822Seric ** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map 40956822Seric */ 41056822Seric 41156822Seric char * 41260089Seric ndbm_map_lookup(map, name, av, statp) 41356822Seric MAP *map; 41460089Seric char *name; 41556822Seric char **av; 41659084Seric int *statp; 41756822Seric { 41856822Seric datum key, val; 41964373Seric int fd; 42060089Seric char keybuf[MAXNAME + 1]; 42156822Seric 42260537Seric if (tTd(38, 20)) 42360089Seric printf("ndbm_map_lookup(%s)\n", name); 42460089Seric 42560089Seric key.dptr = name; 42660089Seric key.dsize = strlen(name); 42760207Seric if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 42857014Seric { 42960089Seric if (key.dsize > sizeof keybuf - 1) 43060089Seric key.dsize = sizeof keybuf - 1; 43160089Seric bcopy(key.dptr, keybuf, key.dsize + 1); 43260089Seric makelower(keybuf); 43360089Seric key.dptr = keybuf; 43457014Seric } 43564373Seric fd = dbm_dirfno((DBM *) map->map_db1); 43664388Seric if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 43764373Seric (void) lockfile(fd, map->map_file, ".dir", LOCK_SH); 43863753Seric val.dptr = NULL; 43963753Seric if (bitset(MF_TRY0NULL, map->map_mflags)) 44063753Seric { 44163753Seric val = dbm_fetch((DBM *) map->map_db1, key); 44263753Seric if (val.dptr != NULL) 44363753Seric map->map_mflags &= ~MF_TRY1NULL; 44463753Seric } 44563753Seric if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags)) 44663753Seric { 44756822Seric key.dsize++; 44863753Seric val = dbm_fetch((DBM *) map->map_db1, key); 44963753Seric if (val.dptr != NULL) 45063753Seric map->map_mflags &= ~MF_TRY0NULL; 45163753Seric } 45264388Seric if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 45364373Seric (void) lockfile(fd, map->map_file, ".dir", LOCK_UN); 45456822Seric if (val.dptr == NULL) 45556822Seric return NULL; 45660207Seric if (bitset(MF_MATCHONLY, map->map_mflags)) 45763753Seric return map_rewrite(map, name, strlen(name), NULL); 45863753Seric else 45963753Seric return map_rewrite(map, val.dptr, val.dsize, av); 46056822Seric } 46156822Seric 46256822Seric 46356822Seric /* 46460089Seric ** DBM_MAP_STORE -- store a datum in the database 46556822Seric */ 46656822Seric 46760089Seric void 46860089Seric ndbm_map_store(map, lhs, rhs) 46960089Seric register MAP *map; 47060089Seric char *lhs; 47160089Seric char *rhs; 47260089Seric { 47360089Seric datum key; 47460089Seric datum data; 47560089Seric int stat; 47660089Seric 47760537Seric if (tTd(38, 12)) 47860089Seric printf("ndbm_map_store(%s, %s)\n", lhs, rhs); 47960089Seric 48060089Seric key.dsize = strlen(lhs); 48160089Seric key.dptr = lhs; 48260089Seric 48360089Seric data.dsize = strlen(rhs); 48460089Seric data.dptr = rhs; 48560089Seric 48660207Seric if (bitset(MF_INCLNULL, map->map_mflags)) 48760089Seric { 48860089Seric key.dsize++; 48960089Seric data.dsize++; 49060089Seric } 49160089Seric 49260089Seric stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT); 49360089Seric if (stat > 0) 49460089Seric { 49560089Seric usrerr("050 Warning: duplicate alias name %s", lhs); 49660089Seric stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE); 49760089Seric } 49860089Seric if (stat != 0) 49960089Seric syserr("readaliases: dbm put (%s)", lhs); 50060089Seric } 50160089Seric 50260089Seric 50360089Seric /* 50460207Seric ** NDBM_MAP_CLOSE -- close the database 50560089Seric */ 50660089Seric 50760089Seric void 50860089Seric ndbm_map_close(map) 50960089Seric register MAP *map; 51060089Seric { 51160207Seric if (bitset(MF_WRITABLE, map->map_mflags)) 51260089Seric { 51364250Seric #ifdef NIS 51464075Seric bool inclnull; 51560089Seric char buf[200]; 51660089Seric 51764075Seric inclnull = bitset(MF_INCLNULL, map->map_mflags); 51864075Seric map->map_mflags &= ~MF_INCLNULL; 51964075Seric 52060089Seric (void) sprintf(buf, "%010ld", curtime()); 52160089Seric ndbm_map_store(map, "YP_LAST_MODIFIED", buf); 52260089Seric 52360089Seric (void) myhostname(buf, sizeof buf); 52460089Seric ndbm_map_store(map, "YP_MASTER_NAME", buf); 52564075Seric 52664075Seric if (inclnull) 52764075Seric map->map_mflags |= MF_INCLNULL; 52860089Seric #endif 52960089Seric 53060089Seric /* write out the distinguished alias */ 53160089Seric ndbm_map_store(map, "@", "@"); 53260089Seric } 53360089Seric dbm_close((DBM *) map->map_db1); 53460089Seric } 53560089Seric 53660089Seric #endif 53760089Seric /* 53860582Seric ** NEWDB (Hash and BTree) Modules 53960089Seric */ 54060089Seric 54160089Seric #ifdef NEWDB 54260089Seric 54360089Seric /* 54460582Seric ** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives. 54560582Seric ** 54660582Seric ** These do rather bizarre locking. If you can lock on open, 54760582Seric ** do that to avoid the condition of opening a database that 54860582Seric ** is being rebuilt. If you don't, we'll try to fake it, but 54960582Seric ** there will be a race condition. If opening for read-only, 55060582Seric ** we immediately release the lock to avoid freezing things up. 55160582Seric ** We really ought to hold the lock, but guarantee that we won't 55260582Seric ** be pokey about it. That's hard to do. 55360089Seric */ 55460089Seric 55556822Seric bool 55660089Seric bt_map_open(map, mode) 55756822Seric MAP *map; 55860089Seric int mode; 55956822Seric { 56056822Seric DB *db; 56160228Seric int i; 56260582Seric int omode; 56364373Seric int fd; 56464284Seric struct stat st; 56560089Seric char buf[MAXNAME]; 56656822Seric 56760537Seric if (tTd(38, 2)) 56860089Seric printf("bt_map_open(%s, %d)\n", map->map_file, mode); 56960089Seric 57060582Seric omode = mode; 57160582Seric if (omode == O_RDWR) 57260582Seric { 57360582Seric omode |= O_CREAT|O_TRUNC; 57464035Seric #if defined(O_EXLOCK) && defined(HASFLOCK) 57560582Seric omode |= O_EXLOCK; 57660582Seric # if !defined(OLD_NEWDB) 57760582Seric } 57860582Seric else 57960582Seric { 58060582Seric omode |= O_SHLOCK; 58160582Seric # endif 58260582Seric #endif 58360582Seric } 58460207Seric 58560228Seric (void) strcpy(buf, map->map_file); 58660228Seric i = strlen(buf); 58760228Seric if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 58860228Seric (void) strcat(buf, ".db"); 58960582Seric db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL); 59056822Seric if (db == NULL) 59156822Seric { 59260207Seric if (!bitset(MF_OPTIONAL, map->map_mflags)) 59356836Seric syserr("Cannot open BTREE database %s", map->map_file); 59456822Seric return FALSE; 59556822Seric } 59664035Seric #if !defined(OLD_NEWDB) && defined(HASFLOCK) 59764373Seric fd = db->fd(db); 59860582Seric # if !defined(O_EXLOCK) 59964373Seric if (mode == O_RDWR && fd >= 0) 60064388Seric { 60164388Seric if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 60264388Seric map->map_mflags |= MF_LOCKED; 60364388Seric } 60460582Seric # else 60564373Seric if (mode == O_RDONLY && fd >= 0) 60664373Seric (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 60764388Seric else 60864388Seric map->map_mflags |= MF_LOCKED; 60960582Seric # endif 61060582Seric #endif 61160585Seric 61260585Seric /* try to make sure that at least the database header is on disk */ 61360585Seric if (mode == O_RDWR) 61464373Seric #ifdef OLD_NEWDB 61564373Seric (void) db->sync(db); 61664373Seric #else 61760585Seric (void) db->sync(db, 0); 61860585Seric 61964373Seric if (fd >= 0 && fstat(fd, &st) >= 0) 62064284Seric map->map_mtime = st.st_mtime; 62164284Seric #endif 62264284Seric 62360089Seric map->map_db2 = (void *) db; 62460207Seric if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 62560207Seric aliaswait(map, ".db"); 62656822Seric return TRUE; 62756822Seric } 62856822Seric 62956822Seric 63056822Seric /* 63156822Seric ** HASH_MAP_INIT -- HASH-style map initialization 63256822Seric */ 63356822Seric 63456822Seric bool 63560089Seric hash_map_open(map, mode) 63656822Seric MAP *map; 63760089Seric int mode; 63856822Seric { 63956822Seric DB *db; 64060228Seric int i; 64160582Seric int omode; 64264373Seric int fd; 64364284Seric struct stat st; 64460089Seric char buf[MAXNAME]; 64556822Seric 64660537Seric if (tTd(38, 2)) 64760089Seric printf("hash_map_open(%s, %d)\n", map->map_file, mode); 64860089Seric 64960582Seric omode = mode; 65060582Seric if (omode == O_RDWR) 65160582Seric { 65260582Seric omode |= O_CREAT|O_TRUNC; 65364035Seric #if defined(O_EXLOCK) && defined(HASFLOCK) 65460582Seric omode |= O_EXLOCK; 65560582Seric # if !defined(OLD_NEWDB) 65660582Seric } 65760582Seric else 65860582Seric { 65960582Seric omode |= O_SHLOCK; 66060582Seric # endif 66160582Seric #endif 66260582Seric } 66360207Seric 66460228Seric (void) strcpy(buf, map->map_file); 66560228Seric i = strlen(buf); 66660228Seric if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 66760228Seric (void) strcat(buf, ".db"); 66860582Seric db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL); 66956822Seric if (db == NULL) 67056822Seric { 67160207Seric if (!bitset(MF_OPTIONAL, map->map_mflags)) 67256836Seric syserr("Cannot open HASH database %s", map->map_file); 67356822Seric return FALSE; 67456822Seric } 67564035Seric #if !defined(OLD_NEWDB) && defined(HASFLOCK) 67664373Seric fd = db->fd(db); 67760582Seric # if !defined(O_EXLOCK) 67864373Seric if (mode == O_RDWR && fd >= 0) 67964388Seric { 68064388Seric if (lockfile(fd, map->map_file, ".db", LOCK_EX)) 68164388Seric map->map_mflags |= MF_LOCKED; 68264388Seric } 68360582Seric # else 68464373Seric if (mode == O_RDONLY && fd >= 0) 68564373Seric (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 68664388Seric else 68764388Seric map->map_mflags |= MF_LOCKED; 68860582Seric # endif 68960582Seric #endif 69060585Seric 69160585Seric /* try to make sure that at least the database header is on disk */ 69260585Seric if (mode == O_RDWR) 69364373Seric #ifdef OLD_NEWDB 69464373Seric (void) db->sync(db); 69564373Seric #else 69660585Seric (void) db->sync(db, 0); 69760585Seric 69864373Seric if (fd >= 0 && fstat(fd, &st) >= 0) 69964284Seric map->map_mtime = st.st_mtime; 70064284Seric #endif 70164284Seric 70260089Seric map->map_db2 = (void *) db; 70360207Seric if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 70460207Seric aliaswait(map, ".db"); 70556822Seric return TRUE; 70656822Seric } 70756822Seric 70856822Seric 70956822Seric /* 71056822Seric ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 71156822Seric */ 71256822Seric 71356822Seric char * 71460089Seric db_map_lookup(map, name, av, statp) 71556822Seric MAP *map; 71660089Seric char *name; 71756822Seric char **av; 71859084Seric int *statp; 71956822Seric { 72056822Seric DBT key, val; 72160422Seric register DB *db = (DB *) map->map_db2; 72260422Seric int st; 72360422Seric int saveerrno; 72464373Seric int fd; 72560089Seric char keybuf[MAXNAME + 1]; 72656822Seric 72760537Seric if (tTd(38, 20)) 72860089Seric printf("db_map_lookup(%s)\n", name); 72960089Seric 73060089Seric key.size = strlen(name); 73160089Seric if (key.size > sizeof keybuf - 1) 73260089Seric key.size = sizeof keybuf - 1; 73360089Seric key.data = keybuf; 73460089Seric bcopy(name, keybuf, key.size + 1); 73560207Seric if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 73660089Seric makelower(keybuf); 73760422Seric #ifndef OLD_NEWDB 73864388Seric fd = db->fd(db); 73964388Seric if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 74064388Seric (void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH); 74160422Seric #endif 74263753Seric st = 1; 74363753Seric if (bitset(MF_TRY0NULL, map->map_mflags)) 74463753Seric { 74563753Seric st = db->get(db, &key, &val, 0); 74663753Seric if (st == 0) 74763753Seric map->map_mflags &= ~MF_TRY1NULL; 74863753Seric } 74963753Seric if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags)) 75063753Seric { 75163753Seric key.size++; 75263753Seric st = db->get(db, &key, &val, 0); 75363753Seric if (st == 0) 75463753Seric map->map_mflags &= ~MF_TRY0NULL; 75563753Seric } 75660422Seric saveerrno = errno; 75760422Seric #ifndef OLD_NEWDB 75864388Seric if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 75964373Seric (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 76060422Seric #endif 76160422Seric if (st != 0) 76260422Seric { 76360422Seric errno = saveerrno; 76460422Seric if (st < 0) 76560422Seric syserr("db_map_lookup: get (%s)", name); 76656822Seric return NULL; 76760422Seric } 76860207Seric if (bitset(MF_MATCHONLY, map->map_mflags)) 76963753Seric return map_rewrite(map, name, strlen(name), NULL); 77063753Seric else 77163753Seric return map_rewrite(map, val.data, val.size, av); 77256822Seric } 77356822Seric 77460089Seric 77560089Seric /* 77660089Seric ** DB_MAP_STORE -- store a datum in the NEWDB database 77756822Seric */ 77856822Seric 77960089Seric void 78060089Seric db_map_store(map, lhs, rhs) 78160089Seric register MAP *map; 78260089Seric char *lhs; 78360089Seric char *rhs; 78456822Seric { 78560089Seric int stat; 78660089Seric DBT key; 78760089Seric DBT data; 78860089Seric register DB *db = map->map_db2; 78956822Seric 79060537Seric if (tTd(38, 20)) 79160089Seric printf("db_map_store(%s, %s)\n", lhs, rhs); 79260089Seric 79360089Seric key.size = strlen(lhs); 79460089Seric key.data = lhs; 79560089Seric 79660089Seric data.size = strlen(rhs); 79760089Seric data.data = rhs; 79860089Seric 79960207Seric if (bitset(MF_INCLNULL, map->map_mflags)) 80056822Seric { 80160089Seric key.size++; 80260089Seric data.size++; 80360089Seric } 80456836Seric 80560089Seric stat = db->put(db, &key, &data, R_NOOVERWRITE); 80660089Seric if (stat > 0) 80760089Seric { 80860089Seric usrerr("050 Warning: duplicate alias name %s", lhs); 80960089Seric stat = db->put(db, &key, &data, 0); 81060089Seric } 81160089Seric if (stat != 0) 81260089Seric syserr("readaliases: db put (%s)", lhs); 81360089Seric } 81456836Seric 81556847Seric 81660089Seric /* 81760089Seric ** DB_MAP_CLOSE -- add distinguished entries and close the database 81860089Seric */ 81960089Seric 82060089Seric void 82160089Seric db_map_close(map) 82260089Seric MAP *map; 82360089Seric { 82460089Seric register DB *db = map->map_db2; 82560089Seric 82660537Seric if (tTd(38, 9)) 82760207Seric printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags); 82860089Seric 82960207Seric if (bitset(MF_WRITABLE, map->map_mflags)) 83058804Seric { 83160089Seric /* write out the distinguished alias */ 83260089Seric db_map_store(map, "@", "@"); 83358804Seric } 83458963Seric 83560089Seric if (db->close(db) != 0) 83660089Seric syserr("readaliases: db close failure"); 83756822Seric } 83857208Seric 83960089Seric #endif 84060089Seric /* 84160089Seric ** NIS Modules 84260089Seric */ 84360089Seric 84460089Seric # ifdef NIS 84560089Seric 84664369Seric # ifndef YPERR_BUSY 84764369Seric # define YPERR_BUSY 16 84864369Seric # endif 84964369Seric 85057208Seric /* 85160089Seric ** NIS_MAP_OPEN -- open DBM map 85257208Seric */ 85357208Seric 85457208Seric bool 85560089Seric nis_map_open(map, mode) 85657208Seric MAP *map; 85760089Seric int mode; 85857208Seric { 85957216Seric int yperr; 86060215Seric register char *p; 86160215Seric auto char *vp; 86260215Seric auto int vsize; 86357216Seric char *master; 86457216Seric 86560537Seric if (tTd(38, 2)) 86660089Seric printf("nis_map_open(%s)\n", map->map_file); 86760089Seric 86860207Seric if (mode != O_RDONLY) 86960207Seric { 87064650Seric /* issue a pseudo-error message */ 87164650Seric #ifdef ENOSYS 87264650Seric errno = ENOSYS; 87364650Seric #else 87464650Seric # ifdef EFTYPE 87564650Seric errno = EFTYPE; 87664650Seric # else 87764650Seric errno = ENXIO; 87864650Seric # endif 87964650Seric #endif 88060207Seric return FALSE; 88160207Seric } 88260207Seric 88360089Seric p = strchr(map->map_file, '@'); 88460089Seric if (p != NULL) 88560089Seric { 88660089Seric *p++ = '\0'; 88760089Seric if (*p != '\0') 88860089Seric map->map_domain = p; 88960089Seric } 89060215Seric 89160089Seric if (map->map_domain == NULL) 89260089Seric yp_get_default_domain(&map->map_domain); 89360089Seric 89460089Seric if (*map->map_file == '\0') 89560089Seric map->map_file = "mail.aliases"; 89660089Seric 89760215Seric /* check to see if this map actually exists */ 89860089Seric yperr = yp_match(map->map_domain, map->map_file, "@", 1, 89960089Seric &vp, &vsize); 90060537Seric if (tTd(38, 10)) 90160089Seric printf("nis_map_open: yp_match(%s, %s) => %s\n", 90260089Seric map->map_domain, map->map_file, yperr_string(yperr)); 90360089Seric if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) 90460089Seric return TRUE; 90560215Seric 90660215Seric if (!bitset(MF_OPTIONAL, map->map_mflags)) 90760215Seric syserr("Cannot bind to domain %s: %s", map->map_domain, 90860215Seric yperr_string(yperr)); 90960215Seric 91060089Seric return FALSE; 91160089Seric } 91260089Seric 91360089Seric 91460089Seric /* 91557208Seric ** NIS_MAP_LOOKUP -- look up a datum in a NIS map 91657208Seric */ 91757208Seric 91857208Seric char * 91960089Seric nis_map_lookup(map, name, av, statp) 92057208Seric MAP *map; 92160089Seric char *name; 92257208Seric char **av; 92359084Seric int *statp; 92457208Seric { 92557208Seric char *vp; 92657642Seric auto int vsize; 92759274Seric int buflen; 92860215Seric int yperr; 92960089Seric char keybuf[MAXNAME + 1]; 93057208Seric 93160537Seric if (tTd(38, 20)) 93260089Seric printf("nis_map_lookup(%s)\n", name); 93360089Seric 93460089Seric buflen = strlen(name); 93560089Seric if (buflen > sizeof keybuf - 1) 93660089Seric buflen = sizeof keybuf - 1; 93760089Seric bcopy(name, keybuf, buflen + 1); 93860207Seric if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 93960089Seric makelower(keybuf); 94063753Seric yperr = YPERR_KEY; 94163753Seric if (bitset(MF_TRY0NULL, map->map_mflags)) 94263753Seric { 94363753Seric yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 94463753Seric &vp, &vsize); 94563753Seric if (yperr == 0) 94663753Seric map->map_mflags &= ~MF_TRY1NULL; 94763753Seric } 94863753Seric if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags)) 94963753Seric { 95059274Seric buflen++; 95163753Seric yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 95263753Seric &vp, &vsize); 95363753Seric if (yperr == 0) 95463753Seric map->map_mflags &= ~MF_TRY0NULL; 95563753Seric } 95660089Seric if (yperr != 0) 95760089Seric { 95860089Seric if (yperr != YPERR_KEY && yperr != YPERR_BUSY) 95960215Seric map->map_mflags &= ~(MF_VALID|MF_OPEN); 96057208Seric return NULL; 96160089Seric } 96260207Seric if (bitset(MF_MATCHONLY, map->map_mflags)) 96363753Seric return map_rewrite(map, name, strlen(name), NULL); 96463753Seric else 96563753Seric return map_rewrite(map, vp, vsize, av); 96657208Seric } 96757208Seric 96860089Seric 96960089Seric /* 97060207Seric ** NIS_MAP_STORE 97160089Seric */ 97260089Seric 97360089Seric void 97460089Seric nis_map_store(map, lhs, rhs) 97560089Seric MAP *map; 97660089Seric char *lhs; 97760089Seric char *rhs; 97860089Seric { 97960089Seric /* nothing */ 98060089Seric } 98160089Seric 98260089Seric 98360089Seric /* 98460207Seric ** NIS_MAP_CLOSE 98560089Seric */ 98660089Seric 98760089Seric void 98860089Seric nis_map_close(map) 98960089Seric MAP *map; 99060089Seric { 99160089Seric /* nothing */ 99260089Seric } 99360089Seric 99460089Seric #endif /* NIS */ 99557208Seric /* 99660089Seric ** STAB (Symbol Table) Modules 99760089Seric */ 99860089Seric 99960089Seric 100060089Seric /* 100160207Seric ** STAB_MAP_LOOKUP -- look up alias in symbol table 100260089Seric */ 100360089Seric 100460089Seric char * 100561707Seric stab_map_lookup(map, name, av, pstat) 100660089Seric register MAP *map; 100760089Seric char *name; 100861707Seric char **av; 100961707Seric int *pstat; 101060089Seric { 101160089Seric register STAB *s; 101260089Seric 101360537Seric if (tTd(38, 20)) 101460089Seric printf("stab_lookup(%s)\n", name); 101560089Seric 101660089Seric s = stab(name, ST_ALIAS, ST_FIND); 101760089Seric if (s != NULL) 101860089Seric return (s->s_alias); 101960089Seric return (NULL); 102060089Seric } 102160089Seric 102260089Seric 102360089Seric /* 102460207Seric ** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild) 102560089Seric */ 102660089Seric 102760089Seric void 102860089Seric stab_map_store(map, lhs, rhs) 102960089Seric register MAP *map; 103060089Seric char *lhs; 103160089Seric char *rhs; 103260089Seric { 103360089Seric register STAB *s; 103460089Seric 103560089Seric s = stab(lhs, ST_ALIAS, ST_ENTER); 103660089Seric s->s_alias = newstr(rhs); 103760089Seric } 103860089Seric 103960089Seric 104060089Seric /* 104160207Seric ** STAB_MAP_OPEN -- initialize (reads data file) 104260207Seric ** 104360207Seric ** This is a wierd case -- it is only intended as a fallback for 104460207Seric ** aliases. For this reason, opens for write (only during a 104560207Seric ** "newaliases") always fails, and opens for read open the 104660207Seric ** actual underlying text file instead of the database. 104760089Seric */ 104860089Seric 104960089Seric bool 105060089Seric stab_map_open(map, mode) 105160089Seric register MAP *map; 105260089Seric int mode; 105360089Seric { 105463835Seric FILE *af; 105564284Seric struct stat st; 105663835Seric 105760537Seric if (tTd(38, 2)) 105860089Seric printf("stab_map_open(%s)\n", map->map_file); 105960089Seric 106060089Seric if (mode != O_RDONLY) 106160207Seric { 106260207Seric errno = ENODEV; 106360089Seric return FALSE; 106460207Seric } 106560089Seric 106663835Seric af = fopen(map->map_file, "r"); 106763835Seric if (af == NULL) 106863835Seric return FALSE; 106963835Seric readaliases(map, af, TRUE); 107064284Seric 107164284Seric if (fstat(fileno(af), &st) >= 0) 107264284Seric map->map_mtime = st.st_mtime; 107363835Seric fclose(af); 107463835Seric 107560089Seric return TRUE; 107660089Seric } 107760089Seric 107860089Seric 107960089Seric /* 108064642Seric ** STAB_MAP_CLOSE -- close symbol table. 108164642Seric ** 108264642Seric ** Since this is in memory, there is nothing to do. 108360089Seric */ 108460089Seric 108560089Seric void 108660089Seric stab_map_close(map) 108760089Seric MAP *map; 108860089Seric { 108960089Seric /* ignore it */ 109060089Seric } 109160089Seric /* 109260089Seric ** Implicit Modules 109356822Seric ** 109460089Seric ** Tries several types. For back compatibility of aliases. 109556822Seric */ 109656822Seric 109760089Seric 109860089Seric /* 109960207Seric ** IMPL_MAP_LOOKUP -- lookup in best open database 110060089Seric */ 110160089Seric 110260089Seric char * 110360089Seric impl_map_lookup(map, name, av, pstat) 110460089Seric MAP *map; 110560089Seric char *name; 110656822Seric char **av; 110760089Seric int *pstat; 110856822Seric { 110960537Seric if (tTd(38, 20)) 111060089Seric printf("impl_map_lookup(%s)\n", name); 111156822Seric 111260089Seric #ifdef NEWDB 111360207Seric if (bitset(MF_IMPL_HASH, map->map_mflags)) 111460089Seric return db_map_lookup(map, name, av, pstat); 111560089Seric #endif 111660089Seric #ifdef NDBM 111760207Seric if (bitset(MF_IMPL_NDBM, map->map_mflags)) 111860089Seric return ndbm_map_lookup(map, name, av, pstat); 111960089Seric #endif 112060089Seric return stab_map_lookup(map, name, av, pstat); 112160089Seric } 112260089Seric 112360089Seric /* 112460207Seric ** IMPL_MAP_STORE -- store in open databases 112560089Seric */ 112660089Seric 112760089Seric void 112860089Seric impl_map_store(map, lhs, rhs) 112960089Seric MAP *map; 113060089Seric char *lhs; 113160089Seric char *rhs; 113260089Seric { 113360089Seric #ifdef NEWDB 113460207Seric if (bitset(MF_IMPL_HASH, map->map_mflags)) 113560089Seric db_map_store(map, lhs, rhs); 113660089Seric #endif 113760089Seric #ifdef NDBM 113860207Seric if (bitset(MF_IMPL_NDBM, map->map_mflags)) 113960089Seric ndbm_map_store(map, lhs, rhs); 114060089Seric #endif 114160089Seric stab_map_store(map, lhs, rhs); 114260089Seric } 114360089Seric 114460089Seric /* 114560089Seric ** IMPL_MAP_OPEN -- implicit database open 114660089Seric */ 114760089Seric 114860089Seric bool 114960089Seric impl_map_open(map, mode) 115060089Seric MAP *map; 115160089Seric int mode; 115260089Seric { 115360089Seric struct stat stb; 115460089Seric 115560537Seric if (tTd(38, 2)) 115660089Seric printf("impl_map_open(%s)\n", map->map_file); 115760089Seric 115860089Seric if (stat(map->map_file, &stb) < 0) 115956822Seric { 116060089Seric /* no alias file at all */ 116160089Seric return FALSE; 116256822Seric } 116356822Seric 116460089Seric #ifdef NEWDB 116560207Seric map->map_mflags |= MF_IMPL_HASH; 116660089Seric if (hash_map_open(map, mode)) 116756822Seric { 116864250Seric #if defined(NDBM) && defined(NIS) 116960561Seric if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0) 117060207Seric #endif 117160207Seric return TRUE; 117260089Seric } 117360207Seric else 117460207Seric map->map_mflags &= ~MF_IMPL_HASH; 117560089Seric #endif 117660089Seric #ifdef NDBM 117760207Seric map->map_mflags |= MF_IMPL_NDBM; 117860089Seric if (ndbm_map_open(map, mode)) 117960089Seric { 118060089Seric return TRUE; 118160089Seric } 118260207Seric else 118360207Seric map->map_mflags &= ~MF_IMPL_NDBM; 118460089Seric #endif 118556822Seric 118664650Seric #if defined(NEWDB) || defined(NDBM) 118760089Seric if (Verbose) 118860089Seric message("WARNING: cannot open alias database %s", map->map_file); 118960207Seric #endif 119060089Seric 119160207Seric return stab_map_open(map, mode); 119256822Seric } 119360089Seric 119460207Seric 119560089Seric /* 119660207Seric ** IMPL_MAP_CLOSE -- close any open database(s) 119760089Seric */ 119860089Seric 119960089Seric void 120060207Seric impl_map_close(map) 120160089Seric MAP *map; 120260089Seric { 120360089Seric #ifdef NEWDB 120460207Seric if (bitset(MF_IMPL_HASH, map->map_mflags)) 120560089Seric { 120660207Seric db_map_close(map); 120760207Seric map->map_mflags &= ~MF_IMPL_HASH; 120860089Seric } 120960089Seric #endif 121060089Seric 121160089Seric #ifdef NDBM 121260207Seric if (bitset(MF_IMPL_NDBM, map->map_mflags)) 121360089Seric { 121460207Seric ndbm_map_close(map); 121560207Seric map->map_mflags &= ~MF_IMPL_NDBM; 121660089Seric } 121760089Seric #endif 121860089Seric } 121960207Seric /* 122060207Seric ** NULL stubs 122160089Seric */ 122260089Seric 122360207Seric bool 122460207Seric null_map_open(map, mode) 122560089Seric MAP *map; 122660207Seric int mode; 122760089Seric { 122860207Seric return TRUE; 122960089Seric } 123060089Seric 123160207Seric void 123260207Seric null_map_close(map) 123360207Seric MAP *map; 123460089Seric { 123560207Seric return; 123660207Seric } 123760089Seric 123860207Seric void 123960207Seric null_map_store(map, key, val) 124060207Seric MAP *map; 124160207Seric char *key; 124260207Seric char *val; 124360089Seric { 124460207Seric return; 124560089Seric } 1246