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*64373Seric static char sccsid[] = "@(#)map.c 8.11 (Berkeley) 08/30/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 30760537Seric CurEnv = e; 30860537Seric stabapply(map_init, rebuild); 30960537Seric } 31060537Seric 31160537Seric void 31260537Seric map_init(s, rebuild) 31360537Seric register STAB *s; 31460537Seric int rebuild; 31560537Seric { 31660537Seric register MAP *map; 31760537Seric 31860537Seric /* has to be a map */ 31960537Seric if (s->s_type != ST_MAP) 32060537Seric return; 32160537Seric 32260537Seric map = &s->s_map; 32360537Seric if (!bitset(MF_VALID, map->map_mflags)) 32460537Seric return; 32560537Seric 32660537Seric if (tTd(38, 2)) 32760537Seric printf("map_init(%s:%s)\n", 32860537Seric map->map_class->map_cname, map->map_file); 32960537Seric 33060537Seric /* if already open, close it (for nested open) */ 33160537Seric if (bitset(MF_OPEN, map->map_mflags)) 33260537Seric { 33360537Seric map->map_class->map_close(map); 33460537Seric map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 33560537Seric } 33660537Seric 33760537Seric if (rebuild) 33860537Seric { 33960926Seric if (bitset(MF_ALIAS, map->map_mflags) && 34060926Seric bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 34160537Seric rebuildaliases(map, FALSE); 34260537Seric } 34360537Seric else 34460537Seric { 34560537Seric if (map->map_class->map_open(map, O_RDONLY)) 34660537Seric { 34760537Seric if (tTd(38, 4)) 34860537Seric printf("%s:%s: valid\n", 34960537Seric map->map_class->map_cname, 35060537Seric map->map_file); 35160537Seric map->map_mflags |= MF_OPEN; 35260537Seric } 35360537Seric else if (tTd(38, 4)) 35460537Seric printf("%s:%s: invalid: %s\n", 35560537Seric map->map_class->map_cname, 35660537Seric map->map_file, 35760537Seric errstring(errno)); 35860537Seric } 35960537Seric } 36060537Seric /* 36160089Seric ** NDBM modules 36260089Seric */ 36360089Seric 36460089Seric #ifdef NDBM 36560089Seric 36660089Seric /* 36760089Seric ** DBM_MAP_OPEN -- DBM-style map open 36860089Seric */ 36960089Seric 37060089Seric bool 37160089Seric ndbm_map_open(map, mode) 37260089Seric MAP *map; 37360089Seric int mode; 37460089Seric { 37564284Seric register DBM *dbm; 37664284Seric struct stat st; 37760089Seric 37860537Seric if (tTd(38, 2)) 37960089Seric printf("ndbm_map_open(%s, %d)\n", map->map_file, mode); 38060089Seric 38160207Seric if (mode == O_RDWR) 38260207Seric mode |= O_CREAT|O_TRUNC; 38360207Seric 38460089Seric /* open the database */ 38560089Seric dbm = dbm_open(map->map_file, mode, DBMMODE); 38656822Seric if (dbm == NULL) 38756822Seric { 38860207Seric if (!bitset(MF_OPTIONAL, map->map_mflags)) 38956836Seric syserr("Cannot open DBM database %s", map->map_file); 39056822Seric return FALSE; 39156822Seric } 39260089Seric map->map_db1 = (void *) dbm; 39360207Seric if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 39460604Seric aliaswait(map, ".pag"); 39564284Seric if (fstat(dbm_dirfno(dbm), &st) >= 0) 39664284Seric map->map_mtime = st.st_mtime; 39756822Seric return TRUE; 39856822Seric } 39960089Seric 40060089Seric 40160089Seric /* 40256822Seric ** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map 40356822Seric */ 40456822Seric 40556822Seric char * 40660089Seric ndbm_map_lookup(map, name, av, statp) 40756822Seric MAP *map; 40860089Seric char *name; 40956822Seric char **av; 41059084Seric int *statp; 41156822Seric { 41256822Seric datum key, val; 413*64373Seric int fd; 41460089Seric char keybuf[MAXNAME + 1]; 41556822Seric 41660537Seric if (tTd(38, 20)) 41760089Seric printf("ndbm_map_lookup(%s)\n", name); 41860089Seric 41960089Seric key.dptr = name; 42060089Seric key.dsize = strlen(name); 42160207Seric if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 42257014Seric { 42360089Seric if (key.dsize > sizeof keybuf - 1) 42460089Seric key.dsize = sizeof keybuf - 1; 42560089Seric bcopy(key.dptr, keybuf, key.dsize + 1); 42660089Seric makelower(keybuf); 42760089Seric key.dptr = keybuf; 42857014Seric } 429*64373Seric fd = dbm_dirfno((DBM *) map->map_db1); 430*64373Seric if (fd >= 0) 431*64373Seric (void) lockfile(fd, map->map_file, ".dir", LOCK_SH); 43263753Seric val.dptr = NULL; 43363753Seric if (bitset(MF_TRY0NULL, map->map_mflags)) 43463753Seric { 43563753Seric val = dbm_fetch((DBM *) map->map_db1, key); 43663753Seric if (val.dptr != NULL) 43763753Seric map->map_mflags &= ~MF_TRY1NULL; 43863753Seric } 43963753Seric if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags)) 44063753Seric { 44156822Seric key.dsize++; 44263753Seric val = dbm_fetch((DBM *) map->map_db1, key); 44363753Seric if (val.dptr != NULL) 44463753Seric map->map_mflags &= ~MF_TRY0NULL; 44563753Seric } 446*64373Seric if (fd >= 0) 447*64373Seric (void) lockfile(fd, map->map_file, ".dir", LOCK_UN); 44856822Seric if (val.dptr == NULL) 44956822Seric return NULL; 45060207Seric if (bitset(MF_MATCHONLY, map->map_mflags)) 45163753Seric return map_rewrite(map, name, strlen(name), NULL); 45263753Seric else 45363753Seric return map_rewrite(map, val.dptr, val.dsize, av); 45456822Seric } 45556822Seric 45656822Seric 45756822Seric /* 45860089Seric ** DBM_MAP_STORE -- store a datum in the database 45956822Seric */ 46056822Seric 46160089Seric void 46260089Seric ndbm_map_store(map, lhs, rhs) 46360089Seric register MAP *map; 46460089Seric char *lhs; 46560089Seric char *rhs; 46660089Seric { 46760089Seric datum key; 46860089Seric datum data; 46960089Seric int stat; 47060089Seric 47160537Seric if (tTd(38, 12)) 47260089Seric printf("ndbm_map_store(%s, %s)\n", lhs, rhs); 47360089Seric 47460089Seric key.dsize = strlen(lhs); 47560089Seric key.dptr = lhs; 47660089Seric 47760089Seric data.dsize = strlen(rhs); 47860089Seric data.dptr = rhs; 47960089Seric 48060207Seric if (bitset(MF_INCLNULL, map->map_mflags)) 48160089Seric { 48260089Seric key.dsize++; 48360089Seric data.dsize++; 48460089Seric } 48560089Seric 48660089Seric stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT); 48760089Seric if (stat > 0) 48860089Seric { 48960089Seric usrerr("050 Warning: duplicate alias name %s", lhs); 49060089Seric stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE); 49160089Seric } 49260089Seric if (stat != 0) 49360089Seric syserr("readaliases: dbm put (%s)", lhs); 49460089Seric } 49560089Seric 49660089Seric 49760089Seric /* 49860207Seric ** NDBM_MAP_CLOSE -- close the database 49960089Seric */ 50060089Seric 50160089Seric void 50260089Seric ndbm_map_close(map) 50360089Seric register MAP *map; 50460089Seric { 50560207Seric if (bitset(MF_WRITABLE, map->map_mflags)) 50660089Seric { 50764250Seric #ifdef NIS 50864075Seric bool inclnull; 50960089Seric char buf[200]; 51060089Seric 51164075Seric inclnull = bitset(MF_INCLNULL, map->map_mflags); 51264075Seric map->map_mflags &= ~MF_INCLNULL; 51364075Seric 51460089Seric (void) sprintf(buf, "%010ld", curtime()); 51560089Seric ndbm_map_store(map, "YP_LAST_MODIFIED", buf); 51660089Seric 51760089Seric (void) myhostname(buf, sizeof buf); 51860089Seric ndbm_map_store(map, "YP_MASTER_NAME", buf); 51964075Seric 52064075Seric if (inclnull) 52164075Seric map->map_mflags |= MF_INCLNULL; 52260089Seric #endif 52360089Seric 52460089Seric /* write out the distinguished alias */ 52560089Seric ndbm_map_store(map, "@", "@"); 52660089Seric } 52760089Seric dbm_close((DBM *) map->map_db1); 52860089Seric } 52960089Seric 53060089Seric #endif 53160089Seric /* 53260582Seric ** NEWDB (Hash and BTree) Modules 53360089Seric */ 53460089Seric 53560089Seric #ifdef NEWDB 53660089Seric 53760089Seric /* 53860582Seric ** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives. 53960582Seric ** 54060582Seric ** These do rather bizarre locking. If you can lock on open, 54160582Seric ** do that to avoid the condition of opening a database that 54260582Seric ** is being rebuilt. If you don't, we'll try to fake it, but 54360582Seric ** there will be a race condition. If opening for read-only, 54460582Seric ** we immediately release the lock to avoid freezing things up. 54560582Seric ** We really ought to hold the lock, but guarantee that we won't 54660582Seric ** be pokey about it. That's hard to do. 54760089Seric */ 54860089Seric 54956822Seric bool 55060089Seric bt_map_open(map, mode) 55156822Seric MAP *map; 55260089Seric int mode; 55356822Seric { 55456822Seric DB *db; 55560228Seric int i; 55660582Seric int omode; 557*64373Seric int fd; 55864284Seric struct stat st; 55960089Seric char buf[MAXNAME]; 56056822Seric 56160537Seric if (tTd(38, 2)) 56260089Seric printf("bt_map_open(%s, %d)\n", map->map_file, mode); 56360089Seric 56460582Seric omode = mode; 56560582Seric if (omode == O_RDWR) 56660582Seric { 56760582Seric omode |= O_CREAT|O_TRUNC; 56864035Seric #if defined(O_EXLOCK) && defined(HASFLOCK) 56960582Seric omode |= O_EXLOCK; 57060582Seric # if !defined(OLD_NEWDB) 57160582Seric } 57260582Seric else 57360582Seric { 57460582Seric omode |= O_SHLOCK; 57560582Seric # endif 57660582Seric #endif 57760582Seric } 57860207Seric 57960228Seric (void) strcpy(buf, map->map_file); 58060228Seric i = strlen(buf); 58160228Seric if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 58260228Seric (void) strcat(buf, ".db"); 58360582Seric db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL); 58456822Seric if (db == NULL) 58556822Seric { 58660207Seric if (!bitset(MF_OPTIONAL, map->map_mflags)) 58756836Seric syserr("Cannot open BTREE database %s", map->map_file); 58856822Seric return FALSE; 58956822Seric } 59064035Seric #if !defined(OLD_NEWDB) && defined(HASFLOCK) 591*64373Seric fd = db->fd(db); 59260582Seric # if !defined(O_EXLOCK) 593*64373Seric if (mode == O_RDWR && fd >= 0) 594*64373Seric (void) lockfile(fd, map->map_file, ".db", LOCK_EX); 59560582Seric # else 596*64373Seric if (mode == O_RDONLY && fd >= 0) 597*64373Seric (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 59860582Seric # endif 59960582Seric #endif 60060585Seric 60160585Seric /* try to make sure that at least the database header is on disk */ 60260585Seric if (mode == O_RDWR) 603*64373Seric #ifdef OLD_NEWDB 604*64373Seric (void) db->sync(db); 605*64373Seric #else 60660585Seric (void) db->sync(db, 0); 60760585Seric 608*64373Seric if (fd >= 0 && fstat(fd, &st) >= 0) 60964284Seric map->map_mtime = st.st_mtime; 61064284Seric #endif 61164284Seric 61260089Seric map->map_db2 = (void *) db; 61360207Seric if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 61460207Seric aliaswait(map, ".db"); 61556822Seric return TRUE; 61656822Seric } 61756822Seric 61856822Seric 61956822Seric /* 62056822Seric ** HASH_MAP_INIT -- HASH-style map initialization 62156822Seric */ 62256822Seric 62356822Seric bool 62460089Seric hash_map_open(map, mode) 62556822Seric MAP *map; 62660089Seric int mode; 62756822Seric { 62856822Seric DB *db; 62960228Seric int i; 63060582Seric int omode; 631*64373Seric int fd; 63264284Seric struct stat st; 63360089Seric char buf[MAXNAME]; 63456822Seric 63560537Seric if (tTd(38, 2)) 63660089Seric printf("hash_map_open(%s, %d)\n", map->map_file, mode); 63760089Seric 63860582Seric omode = mode; 63960582Seric if (omode == O_RDWR) 64060582Seric { 64160582Seric omode |= O_CREAT|O_TRUNC; 64264035Seric #if defined(O_EXLOCK) && defined(HASFLOCK) 64360582Seric omode |= O_EXLOCK; 64460582Seric # if !defined(OLD_NEWDB) 64560582Seric } 64660582Seric else 64760582Seric { 64860582Seric omode |= O_SHLOCK; 64960582Seric # endif 65060582Seric #endif 65160582Seric } 65260207Seric 65360228Seric (void) strcpy(buf, map->map_file); 65460228Seric i = strlen(buf); 65560228Seric if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 65660228Seric (void) strcat(buf, ".db"); 65760582Seric db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL); 65856822Seric if (db == NULL) 65956822Seric { 66060207Seric if (!bitset(MF_OPTIONAL, map->map_mflags)) 66156836Seric syserr("Cannot open HASH database %s", map->map_file); 66256822Seric return FALSE; 66356822Seric } 66464035Seric #if !defined(OLD_NEWDB) && defined(HASFLOCK) 665*64373Seric fd = db->fd(db); 66660582Seric # if !defined(O_EXLOCK) 667*64373Seric if (mode == O_RDWR && fd >= 0) 668*64373Seric (void) lockfile(fd, map->map_file, ".db", LOCK_EX); 66960582Seric # else 670*64373Seric if (mode == O_RDONLY && fd >= 0) 671*64373Seric (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 67260582Seric # endif 67360582Seric #endif 67460585Seric 67560585Seric /* try to make sure that at least the database header is on disk */ 67660585Seric if (mode == O_RDWR) 677*64373Seric #ifdef OLD_NEWDB 678*64373Seric (void) db->sync(db); 679*64373Seric #else 68060585Seric (void) db->sync(db, 0); 68160585Seric 682*64373Seric if (fd >= 0 && fstat(fd, &st) >= 0) 68364284Seric map->map_mtime = st.st_mtime; 68464284Seric #endif 68564284Seric 68660089Seric map->map_db2 = (void *) db; 68760207Seric if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags)) 68860207Seric aliaswait(map, ".db"); 68956822Seric return TRUE; 69056822Seric } 69156822Seric 69256822Seric 69356822Seric /* 69456822Seric ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 69556822Seric */ 69656822Seric 69756822Seric char * 69860089Seric db_map_lookup(map, name, av, statp) 69956822Seric MAP *map; 70060089Seric char *name; 70156822Seric char **av; 70259084Seric int *statp; 70356822Seric { 70456822Seric DBT key, val; 70560422Seric register DB *db = (DB *) map->map_db2; 70660422Seric int st; 70760422Seric int saveerrno; 708*64373Seric int fd; 70960089Seric char keybuf[MAXNAME + 1]; 71056822Seric 71160537Seric if (tTd(38, 20)) 71260089Seric printf("db_map_lookup(%s)\n", name); 71360089Seric 71460089Seric key.size = strlen(name); 71560089Seric if (key.size > sizeof keybuf - 1) 71660089Seric key.size = sizeof keybuf - 1; 71760089Seric key.data = keybuf; 71860089Seric bcopy(name, keybuf, key.size + 1); 71960207Seric if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 72060089Seric makelower(keybuf); 72160422Seric #ifndef OLD_NEWDB 72264335Seric (void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH); 72360422Seric #endif 72463753Seric st = 1; 72563753Seric if (bitset(MF_TRY0NULL, map->map_mflags)) 72663753Seric { 72763753Seric st = db->get(db, &key, &val, 0); 72863753Seric if (st == 0) 72963753Seric map->map_mflags &= ~MF_TRY1NULL; 73063753Seric } 73163753Seric if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags)) 73263753Seric { 73363753Seric key.size++; 73463753Seric st = db->get(db, &key, &val, 0); 73563753Seric if (st == 0) 73663753Seric map->map_mflags &= ~MF_TRY0NULL; 73763753Seric } 73860422Seric saveerrno = errno; 73960422Seric #ifndef OLD_NEWDB 740*64373Seric fd = db->fd(db); 741*64373Seric if (fd >= 0) 742*64373Seric (void) lockfile(fd, map->map_file, ".db", LOCK_UN); 74360422Seric #endif 74460422Seric if (st != 0) 74560422Seric { 74660422Seric errno = saveerrno; 74760422Seric if (st < 0) 74860422Seric syserr("db_map_lookup: get (%s)", name); 74956822Seric return NULL; 75060422Seric } 75160207Seric if (bitset(MF_MATCHONLY, map->map_mflags)) 75263753Seric return map_rewrite(map, name, strlen(name), NULL); 75363753Seric else 75463753Seric return map_rewrite(map, val.data, val.size, av); 75556822Seric } 75656822Seric 75760089Seric 75860089Seric /* 75960089Seric ** DB_MAP_STORE -- store a datum in the NEWDB database 76056822Seric */ 76156822Seric 76260089Seric void 76360089Seric db_map_store(map, lhs, rhs) 76460089Seric register MAP *map; 76560089Seric char *lhs; 76660089Seric char *rhs; 76756822Seric { 76860089Seric int stat; 76960089Seric DBT key; 77060089Seric DBT data; 77160089Seric register DB *db = map->map_db2; 77256822Seric 77360537Seric if (tTd(38, 20)) 77460089Seric printf("db_map_store(%s, %s)\n", lhs, rhs); 77560089Seric 77660089Seric key.size = strlen(lhs); 77760089Seric key.data = lhs; 77860089Seric 77960089Seric data.size = strlen(rhs); 78060089Seric data.data = rhs; 78160089Seric 78260207Seric if (bitset(MF_INCLNULL, map->map_mflags)) 78356822Seric { 78460089Seric key.size++; 78560089Seric data.size++; 78660089Seric } 78756836Seric 78860089Seric stat = db->put(db, &key, &data, R_NOOVERWRITE); 78960089Seric if (stat > 0) 79060089Seric { 79160089Seric usrerr("050 Warning: duplicate alias name %s", lhs); 79260089Seric stat = db->put(db, &key, &data, 0); 79360089Seric } 79460089Seric if (stat != 0) 79560089Seric syserr("readaliases: db put (%s)", lhs); 79660089Seric } 79756836Seric 79856847Seric 79960089Seric /* 80060089Seric ** DB_MAP_CLOSE -- add distinguished entries and close the database 80160089Seric */ 80260089Seric 80360089Seric void 80460089Seric db_map_close(map) 80560089Seric MAP *map; 80660089Seric { 80760089Seric register DB *db = map->map_db2; 80860089Seric 80960537Seric if (tTd(38, 9)) 81060207Seric printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags); 81160089Seric 81260207Seric if (bitset(MF_WRITABLE, map->map_mflags)) 81358804Seric { 81460089Seric /* write out the distinguished alias */ 81560089Seric db_map_store(map, "@", "@"); 81658804Seric } 81758963Seric 81860089Seric if (db->close(db) != 0) 81960089Seric syserr("readaliases: db close failure"); 82056822Seric } 82157208Seric 82260089Seric #endif 82360089Seric /* 82460089Seric ** NIS Modules 82560089Seric */ 82660089Seric 82760089Seric # ifdef NIS 82860089Seric 82964369Seric # ifndef YPERR_BUSY 83064369Seric # define YPERR_BUSY 16 83164369Seric # endif 83264369Seric 83357208Seric /* 83460089Seric ** NIS_MAP_OPEN -- open DBM map 83557208Seric */ 83657208Seric 83757208Seric bool 83860089Seric nis_map_open(map, mode) 83957208Seric MAP *map; 84060089Seric int mode; 84157208Seric { 84257216Seric int yperr; 84360215Seric register char *p; 84460215Seric auto char *vp; 84560215Seric auto int vsize; 84657216Seric char *master; 84757216Seric 84860537Seric if (tTd(38, 2)) 84960089Seric printf("nis_map_open(%s)\n", map->map_file); 85060089Seric 85160207Seric if (mode != O_RDONLY) 85260207Seric { 85360207Seric errno = ENODEV; 85460207Seric return FALSE; 85560207Seric } 85660207Seric 85760089Seric p = strchr(map->map_file, '@'); 85860089Seric if (p != NULL) 85960089Seric { 86060089Seric *p++ = '\0'; 86160089Seric if (*p != '\0') 86260089Seric map->map_domain = p; 86360089Seric } 86460215Seric 86560089Seric if (map->map_domain == NULL) 86660089Seric yp_get_default_domain(&map->map_domain); 86760089Seric 86860089Seric if (*map->map_file == '\0') 86960089Seric map->map_file = "mail.aliases"; 87060089Seric 87160215Seric /* check to see if this map actually exists */ 87260089Seric yperr = yp_match(map->map_domain, map->map_file, "@", 1, 87360089Seric &vp, &vsize); 87460537Seric if (tTd(38, 10)) 87560089Seric printf("nis_map_open: yp_match(%s, %s) => %s\n", 87660089Seric map->map_domain, map->map_file, yperr_string(yperr)); 87760089Seric if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) 87860089Seric return TRUE; 87960215Seric 88060215Seric if (!bitset(MF_OPTIONAL, map->map_mflags)) 88160215Seric syserr("Cannot bind to domain %s: %s", map->map_domain, 88260215Seric yperr_string(yperr)); 88360215Seric 88460089Seric return FALSE; 88560089Seric } 88660089Seric 88760089Seric 88860089Seric /* 88957208Seric ** NIS_MAP_LOOKUP -- look up a datum in a NIS map 89057208Seric */ 89157208Seric 89257208Seric char * 89360089Seric nis_map_lookup(map, name, av, statp) 89457208Seric MAP *map; 89560089Seric char *name; 89657208Seric char **av; 89759084Seric int *statp; 89857208Seric { 89957208Seric char *vp; 90057642Seric auto int vsize; 90159274Seric int buflen; 90260215Seric int yperr; 90360089Seric char keybuf[MAXNAME + 1]; 90457208Seric 90560537Seric if (tTd(38, 20)) 90660089Seric printf("nis_map_lookup(%s)\n", name); 90760089Seric 90860089Seric buflen = strlen(name); 90960089Seric if (buflen > sizeof keybuf - 1) 91060089Seric buflen = sizeof keybuf - 1; 91160089Seric bcopy(name, keybuf, buflen + 1); 91260207Seric if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 91360089Seric makelower(keybuf); 91463753Seric yperr = YPERR_KEY; 91563753Seric if (bitset(MF_TRY0NULL, map->map_mflags)) 91663753Seric { 91763753Seric yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 91863753Seric &vp, &vsize); 91963753Seric if (yperr == 0) 92063753Seric map->map_mflags &= ~MF_TRY1NULL; 92163753Seric } 92263753Seric if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags)) 92363753Seric { 92459274Seric buflen++; 92563753Seric yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 92663753Seric &vp, &vsize); 92763753Seric if (yperr == 0) 92863753Seric map->map_mflags &= ~MF_TRY0NULL; 92963753Seric } 93060089Seric if (yperr != 0) 93160089Seric { 93260089Seric if (yperr != YPERR_KEY && yperr != YPERR_BUSY) 93360215Seric map->map_mflags &= ~(MF_VALID|MF_OPEN); 93457208Seric return NULL; 93560089Seric } 93660207Seric if (bitset(MF_MATCHONLY, map->map_mflags)) 93763753Seric return map_rewrite(map, name, strlen(name), NULL); 93863753Seric else 93963753Seric return map_rewrite(map, vp, vsize, av); 94057208Seric } 94157208Seric 94260089Seric 94360089Seric /* 94460207Seric ** NIS_MAP_STORE 94560089Seric */ 94660089Seric 94760089Seric void 94860089Seric nis_map_store(map, lhs, rhs) 94960089Seric MAP *map; 95060089Seric char *lhs; 95160089Seric char *rhs; 95260089Seric { 95360089Seric /* nothing */ 95460089Seric } 95560089Seric 95660089Seric 95760089Seric /* 95860207Seric ** NIS_MAP_CLOSE 95960089Seric */ 96060089Seric 96160089Seric void 96260089Seric nis_map_close(map) 96360089Seric MAP *map; 96460089Seric { 96560089Seric /* nothing */ 96660089Seric } 96760089Seric 96860089Seric #endif /* NIS */ 96957208Seric /* 97060089Seric ** STAB (Symbol Table) Modules 97160089Seric */ 97260089Seric 97360089Seric 97460089Seric /* 97560207Seric ** STAB_MAP_LOOKUP -- look up alias in symbol table 97660089Seric */ 97760089Seric 97860089Seric char * 97961707Seric stab_map_lookup(map, name, av, pstat) 98060089Seric register MAP *map; 98160089Seric char *name; 98261707Seric char **av; 98361707Seric int *pstat; 98460089Seric { 98560089Seric register STAB *s; 98660089Seric 98760537Seric if (tTd(38, 20)) 98860089Seric printf("stab_lookup(%s)\n", name); 98960089Seric 99060089Seric s = stab(name, ST_ALIAS, ST_FIND); 99160089Seric if (s != NULL) 99260089Seric return (s->s_alias); 99360089Seric return (NULL); 99460089Seric } 99560089Seric 99660089Seric 99760089Seric /* 99860207Seric ** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild) 99960089Seric */ 100060089Seric 100160089Seric void 100260089Seric stab_map_store(map, lhs, rhs) 100360089Seric register MAP *map; 100460089Seric char *lhs; 100560089Seric char *rhs; 100660089Seric { 100760089Seric register STAB *s; 100860089Seric 100960089Seric s = stab(lhs, ST_ALIAS, ST_ENTER); 101060089Seric s->s_alias = newstr(rhs); 101160089Seric } 101260089Seric 101360089Seric 101460089Seric /* 101560207Seric ** STAB_MAP_OPEN -- initialize (reads data file) 101660207Seric ** 101760207Seric ** This is a wierd case -- it is only intended as a fallback for 101860207Seric ** aliases. For this reason, opens for write (only during a 101960207Seric ** "newaliases") always fails, and opens for read open the 102060207Seric ** actual underlying text file instead of the database. 102160089Seric */ 102260089Seric 102360089Seric bool 102460089Seric stab_map_open(map, mode) 102560089Seric register MAP *map; 102660089Seric int mode; 102760089Seric { 102863835Seric FILE *af; 102964284Seric struct stat st; 103063835Seric 103160537Seric if (tTd(38, 2)) 103260089Seric printf("stab_map_open(%s)\n", map->map_file); 103360089Seric 103460089Seric if (mode != O_RDONLY) 103560207Seric { 103660207Seric errno = ENODEV; 103760089Seric return FALSE; 103860207Seric } 103960089Seric 104063835Seric af = fopen(map->map_file, "r"); 104163835Seric if (af == NULL) 104263835Seric return FALSE; 104363835Seric readaliases(map, af, TRUE); 104464284Seric 104564284Seric if (fstat(fileno(af), &st) >= 0) 104664284Seric map->map_mtime = st.st_mtime; 104763835Seric fclose(af); 104863835Seric 104960089Seric return TRUE; 105060089Seric } 105160089Seric 105260089Seric 105360089Seric /* 105460207Seric ** STAB_MAP_CLOSE -- close symbol table (???) 105560089Seric */ 105660089Seric 105760089Seric void 105860089Seric stab_map_close(map) 105960089Seric MAP *map; 106060089Seric { 106160089Seric /* ignore it */ 106260089Seric } 106360089Seric /* 106460089Seric ** Implicit Modules 106556822Seric ** 106660089Seric ** Tries several types. For back compatibility of aliases. 106756822Seric */ 106856822Seric 106960089Seric 107060089Seric /* 107160207Seric ** IMPL_MAP_LOOKUP -- lookup in best open database 107260089Seric */ 107360089Seric 107460089Seric char * 107560089Seric impl_map_lookup(map, name, av, pstat) 107660089Seric MAP *map; 107760089Seric char *name; 107856822Seric char **av; 107960089Seric int *pstat; 108056822Seric { 108160537Seric if (tTd(38, 20)) 108260089Seric printf("impl_map_lookup(%s)\n", name); 108356822Seric 108460089Seric #ifdef NEWDB 108560207Seric if (bitset(MF_IMPL_HASH, map->map_mflags)) 108660089Seric return db_map_lookup(map, name, av, pstat); 108760089Seric #endif 108860089Seric #ifdef NDBM 108960207Seric if (bitset(MF_IMPL_NDBM, map->map_mflags)) 109060089Seric return ndbm_map_lookup(map, name, av, pstat); 109160089Seric #endif 109260089Seric return stab_map_lookup(map, name, av, pstat); 109360089Seric } 109460089Seric 109560089Seric /* 109660207Seric ** IMPL_MAP_STORE -- store in open databases 109760089Seric */ 109860089Seric 109960089Seric void 110060089Seric impl_map_store(map, lhs, rhs) 110160089Seric MAP *map; 110260089Seric char *lhs; 110360089Seric char *rhs; 110460089Seric { 110560089Seric #ifdef NEWDB 110660207Seric if (bitset(MF_IMPL_HASH, map->map_mflags)) 110760089Seric db_map_store(map, lhs, rhs); 110860089Seric #endif 110960089Seric #ifdef NDBM 111060207Seric if (bitset(MF_IMPL_NDBM, map->map_mflags)) 111160089Seric ndbm_map_store(map, lhs, rhs); 111260089Seric #endif 111360089Seric stab_map_store(map, lhs, rhs); 111460089Seric } 111560089Seric 111660089Seric /* 111760089Seric ** IMPL_MAP_OPEN -- implicit database open 111860089Seric */ 111960089Seric 112060089Seric bool 112160089Seric impl_map_open(map, mode) 112260089Seric MAP *map; 112360089Seric int mode; 112460089Seric { 112560089Seric struct stat stb; 112660089Seric 112760537Seric if (tTd(38, 2)) 112860089Seric printf("impl_map_open(%s)\n", map->map_file); 112960089Seric 113060089Seric if (stat(map->map_file, &stb) < 0) 113156822Seric { 113260089Seric /* no alias file at all */ 113360089Seric return FALSE; 113456822Seric } 113556822Seric 113660089Seric #ifdef NEWDB 113760207Seric map->map_mflags |= MF_IMPL_HASH; 113860089Seric if (hash_map_open(map, mode)) 113956822Seric { 114064250Seric #if defined(NDBM) && defined(NIS) 114160561Seric if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0) 114260207Seric #endif 114360207Seric return TRUE; 114460089Seric } 114560207Seric else 114660207Seric map->map_mflags &= ~MF_IMPL_HASH; 114760089Seric #endif 114860089Seric #ifdef NDBM 114960207Seric map->map_mflags |= MF_IMPL_NDBM; 115060089Seric if (ndbm_map_open(map, mode)) 115160089Seric { 115260089Seric return TRUE; 115360089Seric } 115460207Seric else 115560207Seric map->map_mflags &= ~MF_IMPL_NDBM; 115660089Seric #endif 115756822Seric 115860207Seric #if !defined(NEWDB) && !defined(NDBM) 115960089Seric if (Verbose) 116060089Seric message("WARNING: cannot open alias database %s", map->map_file); 116160207Seric #endif 116260089Seric 116360207Seric return stab_map_open(map, mode); 116456822Seric } 116560089Seric 116660207Seric 116760089Seric /* 116860207Seric ** IMPL_MAP_CLOSE -- close any open database(s) 116960089Seric */ 117060089Seric 117160089Seric void 117260207Seric impl_map_close(map) 117360089Seric MAP *map; 117460089Seric { 117560089Seric #ifdef NEWDB 117660207Seric if (bitset(MF_IMPL_HASH, map->map_mflags)) 117760089Seric { 117860207Seric db_map_close(map); 117960207Seric map->map_mflags &= ~MF_IMPL_HASH; 118060089Seric } 118160089Seric #endif 118260089Seric 118360089Seric #ifdef NDBM 118460207Seric if (bitset(MF_IMPL_NDBM, map->map_mflags)) 118560089Seric { 118660207Seric ndbm_map_close(map); 118760207Seric map->map_mflags &= ~MF_IMPL_NDBM; 118860089Seric } 118960089Seric #endif 119060089Seric } 119160207Seric /* 119260207Seric ** NULL stubs 119360089Seric */ 119460089Seric 119560207Seric bool 119660207Seric null_map_open(map, mode) 119760089Seric MAP *map; 119860207Seric int mode; 119960089Seric { 120060207Seric return TRUE; 120160089Seric } 120260089Seric 120360207Seric void 120460207Seric null_map_close(map) 120560207Seric MAP *map; 120660089Seric { 120760207Seric return; 120860207Seric } 120960089Seric 121060207Seric void 121160207Seric null_map_store(map, key, val) 121260207Seric MAP *map; 121360207Seric char *key; 121460207Seric char *val; 121560089Seric { 121660207Seric return; 121760089Seric } 1218