BSD 4_4 release
[unix-history] / usr / src / usr.sbin / sendmail / src / map.c
index 396905a..ef53f23 100644 (file)
 /*
  * Copyright (c) 1992 Eric P. Allman.
 /*
  * Copyright (c) 1992 Eric P. Allman.
- * Copyright (c) 1992 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)map.c      5.3 (Berkeley) %G%";
+static char sccsid[] = "@(#)map.c      8.1 (Berkeley) 6/7/93";
 #endif /* not lint */
 
 #include "sendmail.h"
 #endif /* not lint */
 
 #include "sendmail.h"
-#include <sys/file.h>
 
 
-#ifdef DBM_MAP
+#ifdef NDBM
 #include <ndbm.h>
 #endif
 #include <ndbm.h>
 #endif
-#if defined(HASH_MAP) || defined(BTREE_MAP)
+#ifdef NEWDB
 #include <db.h>
 #endif
 #include <db.h>
 #endif
-
-
-#ifdef DBM_MAP
+#ifdef NIS
+#include <rpcsvc/ypclnt.h>
+#endif
 
 /*
 
 /*
-**  DBM_MAP_INIT -- DBM-style map initialization
+**  MAP.C -- implementations for various map classes.
+**
+**     Each map class implements a series of functions:
+**
+**     bool map_parse(MAP *map, char *args)
+**             Parse the arguments from the config file.  Return TRUE
+**             if they were ok, FALSE otherwise.  Fill in map with the
+**             values.
+**
+**     char *map_lookup(MAP *map, char *key, char **args, int *pstat)
+**             Look up the key in the given map.  If found, do any
+**             rewriting the map wants (including "args" if desired)
+**             and return the value.  Set *pstat to the appropriate status
+**             on error and return NULL.  Args will be NULL if called
+**             from the alias routines, although this should probably
+**             not be relied upon.  It is suggested you call map_rewrite
+**             to return the results -- it takes care of null termination
+**             and uses a dynamically expanded buffer as needed.
+**
+**     void map_store(MAP *map, char *key, char *value)
+**             Store the key:value pair in the map.
+**
+**     bool map_open(MAP *map, int mode)
+**             Open the map for the indicated mode.  Mode should
+**             be either O_RDONLY or O_RDWR.  Return TRUE if it
+**             was opened successfully, FALSE otherwise.  If the open
+**             failed an the MF_OPTIONAL flag is not set, it should
+**             also print an error.  If the MF_ALIAS bit is set
+**             and this map class understands the @:@ convention, it
+**             should call aliaswait() before returning.
+**
+**     void map_close(MAP *map)
+**             Close the map.
+*/
+
+#define DBMMODE                0644
+\f/*
+**  MAP_PARSEARGS -- parse config line arguments for database lookup
+**
+**     This is a generic version of the map_parse method.
 **
 **     Parameters:
 **
 **     Parameters:
-**             map -- the pointer to the actual map
-**             mapname -- the name of the map (for error messages)
-**             args -- a pointer to the config file line arguments
+**             map -- the map being initialized.
+**             ap -- a pointer to the args on the config line.
 **
 **     Returns:
 **
 **     Returns:
-**             TRUE -- if it could successfully open the map.
+**             TRUE -- if everything parsed OK.
 **             FALSE -- otherwise.
 **
 **     Side Effects:
 **             FALSE -- otherwise.
 **
 **     Side Effects:
-**             Gives an error if it can't open the map.
+**             null terminates the filename; stores it in map
 */
 
 bool
 */
 
 bool
-dbm_map_init(map, mapname, args)
+map_parseargs(map, ap)
        MAP *map;
        MAP *map;
-       char *mapname;
-       char *args;
+       char *ap;
 {
 {
-       DBM *dbm;
+       register char *p = ap;
+
+       for (;;)
+       {
+               while (isascii(*p) && isspace(*p))
+                       p++;
+               if (*p != '-')
+                       break;
+               switch (*++p)
+               {
+                 case 'N':
+                       map->map_mflags |= MF_INCLNULL;
+                       break;
+
+                 case 'o':
+                       map->map_mflags |= MF_OPTIONAL;
+                       break;
+
+                 case 'f':
+                       map->map_mflags |= MF_NOFOLDCASE;
+                       break;
+
+                 case 'm':
+                       map->map_mflags |= MF_MATCHONLY;
+                       break;
+
+                 case 'a':
+                       map->map_app = ++p;
+                       break;
+               }
+               while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+                       p++;
+               if (*p != '\0')
+                       *p++ = '\0';
+       }
+       if (map->map_app != NULL)
+               map->map_app = newstr(map->map_app);
+
+       if (*p != '\0')
+       {
+               map->map_file = p;
+               while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+                       p++;
+               if (*p != '\0')
+                       *p++ = '\0';
+               map->map_file = newstr(map->map_file);
+       }
+
+       while (*p != '\0' && isascii(*p) && isspace(*p))
+               p++;
+       if (*p != '\0')
+               map->map_rebuild = newstr(p);
 
 
-       map_parseargs(map, &args, mapname);
        if (map->map_file == NULL)
        if (map->map_file == NULL)
-               return FALSE;
-       dbm = dbm_open(map->map_file, O_RDONLY, 0644);
-       if (dbm == NULL)
        {
        {
-               if (!bitset(MF_OPTIONAL, map->map_flags))
-                       syserr("Cannot open DBM database %s", map->map_file);
+               syserr("No file name for %s map %s",
+                       map->map_class->map_cname, map->map_mname);
                return FALSE;
        }
                return FALSE;
        }
-       map->map_db = (void *) dbm;
        return TRUE;
 }
 \f/*
        return TRUE;
 }
 \f/*
-**  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
+**  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
+**
+**     It also adds the map_app string.  It can be used as a utility
+**     in the map_lookup method.
 **
 **     Parameters:
 **
 **     Parameters:
-**             map -- the map to look up in.
-**             buf -- a pointer to to the buffer containing the key.
-**                     This is a null terminated string.
-**             bufsiz -- the size of buf -- note that this is in general
-**                     larger that strlen(buf), and buf can be changed
-**                     in place if desired.
-**             av -- arguments from the config file (can be interpolated
-**                     into the final result).
+**             map -- the map that causes this.
+**             s -- the string to rewrite, NOT necessarily null terminated.
+**             slen -- the length of s.
+**             av -- arguments to interpolate into buf.
 **
 **     Returns:
 **
 **     Returns:
-**             A pointer to the rewritten result.
-**             NULL if not found in the map.
+**             Pointer to rewritten result.
+**
+**     Side Effects:
+**             none.
+*/
+
+struct rwbuf
+{
+       int     rwb_len;        /* size of buffer */
+       char    *rwb_buf;       /* ptr to buffer */
+};
+
+struct rwbuf   RwBufs[2];      /* buffers for rewriting output */
+
+char *
+map_rewrite(map, s, slen, av)
+       register MAP *map;
+       register char *s;
+       int slen;
+       char **av;
+{
+       register char *bp;
+       register char c;
+       char **avp;
+       register char *ap;
+       register struct rwbuf *rwb;
+       int i;
+       int len;
+
+       if (tTd(39, 1))
+       {
+               printf("map_rewrite(%.*s), av =", slen, s);
+               if (av == NULL)
+                       printf(" (nullv)");
+               else
+               {
+                       for (avp = av; *avp != NULL; avp++)
+                               printf("\n\t%s", *avp);
+               }
+               printf("\n");
+       }
+
+       rwb = RwBufs;
+       if (av == NULL)
+               rwb++;
+
+       /* count expected size of output (can safely overestimate) */
+       i = len = slen;
+       if (av != NULL)
+       {
+               bp = s;
+               for (i = slen; --i >= 0 && (c = *bp++) != 0; )
+               {
+                       if (c != '%')
+                               continue;
+                       if (--i < 0)
+                               break;
+                       c = *bp++;
+                       if (!(isascii(c) && isdigit(c)))
+                               continue;
+                       c -= 0;
+                       for (avp = av; --c >= 0 && *avp != NULL; avp++)
+                               continue;
+                       if (*avp == NULL)
+                               continue;
+                       len += strlen(*avp);
+               }
+       }
+       if (map->map_app != NULL)
+               len += strlen(map->map_app);
+       if (rwb->rwb_len < ++len)
+       {
+               /* need to malloc additional space */
+               rwb->rwb_len = len;
+               if (rwb->rwb_buf != NULL)
+                       free(rwb->rwb_buf);
+               rwb->rwb_buf = xalloc(rwb->rwb_len);
+       }
+
+       bp = rwb->rwb_buf;
+       if (av == NULL)
+       {
+               bcopy(s, bp, slen);
+               bp += slen;
+       }
+       else
+       {
+               while (--slen >= 0 && (c = *s++) != '\0')
+               {
+                       if (c != '%')
+                       {
+  pushc:
+                               *bp++ = c;
+                               continue;
+                       }
+                       if (--slen < 0 || (c = *s++) == '\0')
+                               c = '%';
+                       if (c == '%')
+                               goto pushc;
+                       if (!(isascii(c) && isdigit(c)))
+                       {
+                               *bp++ = '%';
+                               goto pushc;
+                       }
+                       c -= '0';
+                       for (avp = av; --c >= 0 && *avp != NULL; avp++)
+                               continue;
+                       if (*avp == NULL)
+                               continue;
+
+                       /* transliterate argument into output string */
+                       for (ap = *avp; (c = *ap++) != '\0'; )
+                               *bp++ = c;
+               }
+       }
+       if (map->map_app != NULL)
+               strcpy(bp, map->map_app);
+       else
+               *bp = '\0';
+       if (tTd(39, 1))
+               printf("map_rewrite => %s\n", rwb->rwb_buf);
+       return rwb->rwb_buf;
+}
+\f/*
+**  INITMAPS -- initialize for aliasing
+**
+**     Parameters:
+**             rebuild -- if TRUE, this rebuilds the cached versions.
+**             e -- current envelope.
+**
+**     Returns:
+**             none.
+**
+**     Side Effects:
+**             initializes aliases:
+**             if NDBM:  opens the database.
+**             if ~NDBM: reads the aliases into the symbol table.
+*/
+
+initmaps(rebuild, e)
+       bool rebuild;
+       register ENVELOPE *e;
+{
+       extern void map_init();
+
+       CurEnv = e;
+       stabapply(map_init, rebuild);
+}
+
+void
+map_init(s, rebuild)
+       register STAB *s;
+       int rebuild;
+{
+       register MAP *map;
+
+       /* has to be a map */
+       if (s->s_type != ST_MAP)
+               return;
+
+       map = &s->s_map;
+       if (!bitset(MF_VALID, map->map_mflags))
+               return;
+
+       if (tTd(38, 2))
+               printf("map_init(%s:%s)\n",
+                       map->map_class->map_cname, map->map_file);
+
+       /* if already open, close it (for nested open) */
+       if (bitset(MF_OPEN, map->map_mflags))
+       {
+               map->map_class->map_close(map);
+               map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
+       }
+
+       if (rebuild)
+       {
+               if (bitset(MF_ALIAS, map->map_mflags) &&
+                   bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
+                       rebuildaliases(map, FALSE);
+       }
+       else
+       {
+               if (map->map_class->map_open(map, O_RDONLY))
+               {
+                       if (tTd(38, 4))
+                               printf("%s:%s: valid\n",
+                                       map->map_class->map_cname,
+                                       map->map_file);
+                       map->map_mflags |= MF_OPEN;
+               }
+               else if (tTd(38, 4))
+                       printf("%s:%s: invalid: %s\n",
+                               map->map_class->map_cname,
+                               map->map_file,
+                               errstring(errno));
+       }
+}
+\f/*
+**  NDBM modules
+*/
+
+#ifdef NDBM
+
+/*
+**  DBM_MAP_OPEN -- DBM-style map open
+*/
+
+bool
+ndbm_map_open(map, mode)
+       MAP *map;
+       int mode;
+{
+       DBM *dbm;
+
+       if (tTd(38, 2))
+               printf("ndbm_map_open(%s, %d)\n", map->map_file, mode);
+
+       if (mode == O_RDWR)
+               mode |= O_CREAT|O_TRUNC;
+
+       /* open the database */
+       dbm = dbm_open(map->map_file, mode, DBMMODE);
+       if (dbm == NULL)
+       {
+               if (!bitset(MF_OPTIONAL, map->map_mflags))
+                       syserr("Cannot open DBM database %s", map->map_file);
+               return FALSE;
+       }
+       map->map_db1 = (void *) dbm;
+       if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
+               aliaswait(map, ".pag");
+       return TRUE;
+}
+
+
+/*
+**  DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
 */
 
 char *
 */
 
 char *
-dbm_map_lookup(map, buf, bufsiz, av)
+ndbm_map_lookup(map, name, av, statp)
        MAP *map;
        MAP *map;
-       char buf[];
-       int bufsiz;
+       char *name;
        char **av;
        char **av;
+       int *statp;
 {
        datum key, val;
 {
        datum key, val;
+       char keybuf[MAXNAME + 1];
+
+       if (tTd(38, 20))
+               printf("ndbm_map_lookup(%s)\n", name);
 
 
-       key.dptr = buf;
-       key.dsize = strlen(buf);
-       if (bitset(MF_INCLNULL, map->map_flags))
+       key.dptr = name;
+       key.dsize = strlen(name);
+       if (!bitset(MF_NOFOLDCASE, map->map_mflags))
+       {
+               if (key.dsize > sizeof keybuf - 1)
+                       key.dsize = sizeof keybuf - 1;
+               bcopy(key.dptr, keybuf, key.dsize + 1);
+               makelower(keybuf);
+               key.dptr = keybuf;
+       }
+       if (bitset(MF_INCLNULL, map->map_mflags))
                key.dsize++;
                key.dsize++;
-       val = dbm_fetch(map->map_db, key);
+       (void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file, LOCK_SH);
+       val = dbm_fetch((DBM *) map->map_db1, key);
+       (void) lockfile(dbm_dirfno((DBM *) map->map_db1), map->map_file, LOCK_UN);
        if (val.dptr == NULL)
                return NULL;
        if (val.dptr == NULL)
                return NULL;
-       map_rewrite(val.dptr, val.dsize, buf, bufsiz, av);
-       return buf;
+       if (bitset(MF_MATCHONLY, map->map_mflags))
+               av = NULL;
+       return map_rewrite(map, val.dptr, val.dsize, av);
 }
 
 }
 
-#endif /* DBM_MAP */
-\f
-#ifdef BTREE_MAP
 
 /*
 
 /*
-**  BTREE_MAP_INIT -- BTREE-style map initialization
-**
-**     Parameters:
-**             map -- the pointer to the actual map
-**             mapname -- the name of the map (for error messages)
-**             args -- a pointer to the config file line arguments
-**
-**     Returns:
-**             TRUE -- if it could successfully open the map.
-**             FALSE -- otherwise.
+**  DBM_MAP_STORE -- store a datum in the database
+*/
+
+void
+ndbm_map_store(map, lhs, rhs)
+       register MAP *map;
+       char *lhs;
+       char *rhs;
+{
+       datum key;
+       datum data;
+       int stat;
+
+       if (tTd(38, 12))
+               printf("ndbm_map_store(%s, %s)\n", lhs, rhs);
+
+       key.dsize = strlen(lhs);
+       key.dptr = lhs;
+
+       data.dsize = strlen(rhs);
+       data.dptr = rhs;
+
+       if (bitset(MF_INCLNULL, map->map_mflags))
+       {
+               key.dsize++;
+               data.dsize++;
+       }
+
+       stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
+       if (stat > 0)
+       {
+               usrerr("050 Warning: duplicate alias name %s", lhs);
+               stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
+       }
+       if (stat != 0)
+               syserr("readaliases: dbm put (%s)", lhs);
+}
+
+
+/*
+**  NDBM_MAP_CLOSE -- close the database
+*/
+
+void
+ndbm_map_close(map)
+       register MAP  *map;
+{
+       if (bitset(MF_WRITABLE, map->map_mflags))
+       {
+#ifdef YPCOMPAT
+               char buf[200];
+
+               (void) sprintf(buf, "%010ld", curtime());
+               ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
+
+               (void) myhostname(buf, sizeof buf);
+               ndbm_map_store(map, "YP_MASTER_NAME", buf);
+#endif
+
+               /* write out the distinguished alias */
+               ndbm_map_store(map, "@", "@");
+       }
+       dbm_close((DBM *) map->map_db1);
+}
+
+#endif
+\f/*
+**  NEWDB (Hash and BTree) Modules
+*/
+
+#ifdef NEWDB
+
+/*
+**  BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
 **
 **
-**     Side Effects:
-**             Gives an error if it can't open the map.
+**     These do rather bizarre locking.  If you can lock on open,
+**     do that to avoid the condition of opening a database that
+**     is being rebuilt.  If you don't, we'll try to fake it, but
+**     there will be a race condition.  If opening for read-only,
+**     we immediately release the lock to avoid freezing things up.
+**     We really ought to hold the lock, but guarantee that we won't
+**     be pokey about it.  That's hard to do.
 */
 
 bool
 */
 
 bool
-bt_map_init(map, mapname, args)
+bt_map_open(map, mode)
        MAP *map;
        MAP *map;
-       char *mapname;
-       char *args;
+       int mode;
 {
        DB *db;
 {
        DB *db;
+       int i;
+       int omode;
+       char buf[MAXNAME];
 
 
-       map_parseargs(map, &args, mapname);
-       if (map->map_file == NULL)
-               return FALSE;
-       db = dbopen(map->map_file, O_RDONLY, 0644, DB_BTREE, NULL);
+       if (tTd(38, 2))
+               printf("bt_map_open(%s, %d)\n", map->map_file, mode);
+
+       omode = mode;
+       if (omode == O_RDWR)
+       {
+               omode |= O_CREAT|O_TRUNC;
+#if defined(O_EXLOCK) && !defined(LOCKF)
+               omode |= O_EXLOCK;
+# if !defined(OLD_NEWDB)
+       }
+       else
+       {
+               omode |= O_SHLOCK;
+# endif
+#endif
+       }
+
+       (void) strcpy(buf, map->map_file);
+       i = strlen(buf);
+       if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
+               (void) strcat(buf, ".db");
+       db = dbopen(buf, omode, DBMMODE, DB_BTREE, NULL);
        if (db == NULL)
        {
        if (db == NULL)
        {
-               if (!bitset(MF_OPTIONAL, map->map_flags))
+               if (!bitset(MF_OPTIONAL, map->map_mflags))
                        syserr("Cannot open BTREE database %s", map->map_file);
                return FALSE;
        }
                        syserr("Cannot open BTREE database %s", map->map_file);
                return FALSE;
        }
-       map->map_db = (void *) db;
+#if !defined(OLD_NEWDB) && !defined(LOCKF)
+# if !defined(O_EXLOCK)
+       if (mode == O_RDWR)
+               (void) lockfile(db->fd(db), map->map_file, LOCK_EX);
+# else
+       if (mode == O_RDONLY)
+               (void) lockfile(db->fd(db), map->map_file, LOCK_UN);
+# endif
+#endif
+
+       /* try to make sure that at least the database header is on disk */
+       if (mode == O_RDWR)
+               (void) db->sync(db, 0);
+
+       map->map_db2 = (void *) db;
+       if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
+               aliaswait(map, ".db");
        return TRUE;
 }
 
        return TRUE;
 }
 
-#endif /* BTREE_MAP */
-\f
-#ifdef HASH_MAP
 
 /*
 **  HASH_MAP_INIT -- HASH-style map initialization
 
 /*
 **  HASH_MAP_INIT -- HASH-style map initialization
-**
-**     Parameters:
-**             map -- the pointer to the actual map
-**             mapname -- the name of the map (for error messages)
-**             args -- a pointer to the config file line arguments
-**
-**     Returns:
-**             TRUE -- if it could successfully open the map.
-**             FALSE -- otherwise.
-**
-**     Side Effects:
-**             Gives an error if it can't open the map.
 */
 
 bool
 */
 
 bool
-hash_map_init(map, mapname, args)
+hash_map_open(map, mode)
        MAP *map;
        MAP *map;
-       char *mapname;
-       char *args;
+       int mode;
 {
        DB *db;
 {
        DB *db;
+       int i;
+       int omode;
+       char buf[MAXNAME];
 
 
-       map_parseargs(map, &args, mapname);
-       if (map->map_file == NULL)
-               return FALSE;
-       db = dbopen(map->map_file, O_RDONLY, 0644, DB_HASH, NULL);
+       if (tTd(38, 2))
+               printf("hash_map_open(%s, %d)\n", map->map_file, mode);
+
+       omode = mode;
+       if (omode == O_RDWR)
+       {
+               omode |= O_CREAT|O_TRUNC;
+#if defined(O_EXLOCK) && !defined(LOCKF)
+               omode |= O_EXLOCK;
+# if !defined(OLD_NEWDB)
+       }
+       else
+       {
+               omode |= O_SHLOCK;
+# endif
+#endif
+       }
+
+       (void) strcpy(buf, map->map_file);
+       i = strlen(buf);
+       if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
+               (void) strcat(buf, ".db");
+       db = dbopen(buf, omode, DBMMODE, DB_HASH, NULL);
        if (db == NULL)
        {
        if (db == NULL)
        {
-               if (!bitset(MF_OPTIONAL, map->map_flags))
+               if (!bitset(MF_OPTIONAL, map->map_mflags))
                        syserr("Cannot open HASH database %s", map->map_file);
                return FALSE;
        }
                        syserr("Cannot open HASH database %s", map->map_file);
                return FALSE;
        }
-       map->map_db = (void *) db;
+#if !defined(OLD_NEWDB) && !defined(LOCKF)
+# if !defined(O_EXLOCK)
+       if (mode == O_RDWR)
+               (void) lockfile(db->fd(db), map->map_file, LOCK_EX);
+# else
+       if (mode == O_RDONLY)
+               (void) lockfile(db->fd(db), map->map_file, LOCK_UN);
+# endif
+#endif
+
+       /* try to make sure that at least the database header is on disk */
+       if (mode == O_RDWR)
+               (void) db->sync(db, 0);
+
+       map->map_db2 = (void *) db;
+       if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
+               aliaswait(map, ".db");
        return TRUE;
 }
 
        return TRUE;
 }
 
-#endif /* HASH_MAP */
-\f
-#if defined(BTREE_MAP) || defined(HASH_MAP)
 
 /*
 **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
 
 /*
 **  DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
-**
-**     Parameters:
-**             map -- the map to look up in.
-**             buf -- a pointer to to the buffer containing the key.
-**                     This is a null terminated string.
-**             bufsiz -- the size of buf -- note that this is in general
-**                     larger that strlen(buf), and buf can be changed
-**                     in place if desired.
-**             av -- arguments from the config file (can be interpolated
-**                     into the final result).
-**
-**     Returns:
-**             A pointer to the rewritten result.
-**             NULL if not found in the map.
 */
 
 char *
 */
 
 char *
-db_map_lookup(map, buf, bufsiz, av)
+db_map_lookup(map, name, av, statp)
        MAP *map;
        MAP *map;
-       char buf[];
-       int bufsiz;
+       char *name;
        char **av;
        char **av;
+       int *statp;
 {
        DBT key, val;
 {
        DBT key, val;
+       register DB *db = (DB *) map->map_db2;
+       int st;
+       int saveerrno;
+       char keybuf[MAXNAME + 1];
 
 
-       key.data = buf;
-       key.size = strlen(buf);
-       if (bitset(MF_FOLDCASE, map->map_flags))
-       {
-               register char *p;
+       if (tTd(38, 20))
+               printf("db_map_lookup(%s)\n", name);
 
 
-               for (p = buf; *p != '\0'; p++)
-                       if (isupper(*p))
-                               *p = tolower(*p);
-       }
-       if (bitset(MF_INCLNULL, map->map_flags))
+       key.size = strlen(name);
+       if (key.size > sizeof keybuf - 1)
+               key.size = sizeof keybuf - 1;
+       key.data = keybuf;
+       bcopy(name, keybuf, key.size + 1);
+       if (!bitset(MF_NOFOLDCASE, map->map_mflags))
+               makelower(keybuf);
+       if (bitset(MF_INCLNULL, map->map_mflags))
                key.size++;
                key.size++;
-       if (((DB *) map->map_db)->get((DB *) map->map_db, &key, &val, 0) != 0)
+#ifndef OLD_NEWDB
+       (void) lockfile(db->fd(db), map->map_file, LOCK_SH);
+#endif
+       st = db->get(db, &key, &val, 0);
+       saveerrno = errno;
+#ifndef OLD_NEWDB
+       (void) lockfile(db->fd(db), map->map_file, LOCK_UN);
+#endif
+       if (st != 0)
+       {
+               errno = saveerrno;
+               if (st < 0)
+                       syserr("db_map_lookup: get (%s)", name);
                return NULL;
                return NULL;
-       map_rewrite(val.data, val.size, buf, bufsiz, av);
-       return buf;
+       }
+       if (bitset(MF_MATCHONLY, map->map_mflags))
+               av = NULL;
+       return map_rewrite(map, val.data, val.size, av);
 }
 
 }
 
-#endif /* BTREE_MAP || HASH_MAP */
-\f/*
-**  MAP_PARSEARGS -- parse config line arguments for database lookup
-**
-**     Parameters:
-**             map -- the map being initialized.
-**             pp -- an indirect pointer to the config line.  It will
-**                     be replaced with a pointer to the next field
-**                     on the line.
-**             mapname -- the name of the map (for errors).
-**
-**     Returns:
-**             none
-**
-**     Side Effects:
-**             null terminates the filename; stores it in map
+
+/*
+**  DB_MAP_STORE -- store a datum in the NEWDB database
+*/
+
+void
+db_map_store(map, lhs, rhs)
+       register MAP *map;
+       char *lhs;
+       char *rhs;
+{
+       int stat;
+       DBT key;
+       DBT data;
+       register DB *db = map->map_db2;
+
+       if (tTd(38, 20))
+               printf("db_map_store(%s, %s)\n", lhs, rhs);
+
+       key.size = strlen(lhs);
+       key.data = lhs;
+
+       data.size = strlen(rhs);
+       data.data = rhs;
+
+       if (bitset(MF_INCLNULL, map->map_mflags))
+       {
+               key.size++;
+               data.size++;
+       }
+
+       stat = db->put(db, &key, &data, R_NOOVERWRITE);
+       if (stat > 0)
+       {
+               usrerr("050 Warning: duplicate alias name %s", lhs);
+               stat = db->put(db, &key, &data, 0);
+       }
+       if (stat != 0)
+               syserr("readaliases: db put (%s)", lhs);
+}
+
+
+/*
+**  DB_MAP_CLOSE -- add distinguished entries and close the database
 */
 
 */
 
-map_parseargs(map, pp, mapname)
+void
+db_map_close(map)
        MAP *map;
        MAP *map;
-       char **pp;
-       char *mapname;
 {
 {
-       register char *p = *pp;
+       register DB *db = map->map_db2;
 
 
-       for (;;)
+       if (tTd(38, 9))
+               printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags);
+
+       if (bitset(MF_WRITABLE, map->map_mflags))
        {
        {
-               while (isspace(*p))
-                       p++;
-               if (*p != '-')
-                       break;
-               switch (*++p)
-               {
-                 case 'N':
-                       map->map_flags |= MF_INCLNULL;
-                       break;
+               /* write out the distinguished alias */
+               db_map_store(map, "@", "@");
+       }
 
 
-                 case 'o':
-                       map->map_flags |= MF_OPTIONAL;
-                       break;
+       if (db->close(db) != 0)
+               syserr("readaliases: db close failure");
+}
 
 
-                 case 'f':
-                       map->map_flags |= MF_FOLDCASE;
-                       break;
+#endif
+\f/*
+**  NIS Modules
+*/
 
 
-                 case 'a':
-                       map->map_app = ++p;
-                       break;
-               }
-               while (*p != '\0' && !isspace(*p))
-                       p++;
+# ifdef NIS
+
+/*
+**  NIS_MAP_OPEN -- open DBM map
+*/
+
+bool
+nis_map_open(map, mode)
+       MAP *map;
+       int mode;
+{
+       int yperr;
+       register char *p;
+       auto char *vp;
+       auto int vsize;
+       char *master;
+
+       if (tTd(38, 2))
+               printf("nis_map_open(%s)\n", map->map_file);
+
+       if (mode != O_RDONLY)
+       {
+               errno = ENODEV;
+               return FALSE;
+       }
+
+       p = strchr(map->map_file, '@');
+       if (p != NULL)
+       {
+               *p++ = '\0';
                if (*p != '\0')
                if (*p != '\0')
-                       *p++ = 0;
+                       map->map_domain = p;
        }
        }
-       if (map->map_app != NULL)
-               map->map_app = newstr(map->map_app);
 
 
-       if (*p == '\0')
+       if (map->map_domain == NULL)
+               yp_get_default_domain(&map->map_domain);
+
+       if (*map->map_file == '\0')
+               map->map_file = "mail.aliases";
+
+       /* check to see if this map actually exists */
+       yperr = yp_match(map->map_domain, map->map_file, "@", 1,
+                       &vp, &vsize);
+       if (tTd(38, 10))
+               printf("nis_map_open: yp_match(%s, %s) => %s\n",
+                       map->map_domain, map->map_file, yperr_string(yperr));
+       if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
+               return TRUE;
+
+       if (!bitset(MF_OPTIONAL, map->map_mflags))
+               syserr("Cannot bind to domain %s: %s", map->map_domain,
+                       yperr_string(yperr));
+
+       return FALSE;
+}
+
+
+/*
+**  NIS_MAP_LOOKUP -- look up a datum in a NIS map
+*/
+
+char *
+nis_map_lookup(map, name, av, statp)
+       MAP *map;
+       char *name;
+       char **av;
+       int *statp;
+{
+       char *vp;
+       auto int vsize;
+       int buflen;
+       int yperr;
+       char keybuf[MAXNAME + 1];
+
+       if (tTd(38, 20))
+               printf("nis_map_lookup(%s)\n", name);
+
+       buflen = strlen(name);
+       if (buflen > sizeof keybuf - 1)
+               buflen = sizeof keybuf - 1;
+       bcopy(name, keybuf, buflen + 1);
+       if (!bitset(MF_NOFOLDCASE, map->map_mflags))
+               makelower(keybuf);
+       if (bitset(MF_INCLNULL, map->map_mflags))
+               buflen++;
+       yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
+                    &vp, &vsize);
+       if (yperr != 0)
        {
        {
-               syserr("No file name for map %s", mapname);
+               if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
+                       map->map_mflags &= ~(MF_VALID|MF_OPEN);
                return NULL;
        }
                return NULL;
        }
-       map->map_file = p;
-       while (*p != '\0' && !isspace(*p))
-               p++;
-       if (*p != '\0')
-               *p++ = '\0';
-       map->map_file = newstr(map->map_file);
-       *pp = p;
+       if (bitset(MF_MATCHONLY, map->map_mflags))
+               av = NULL;
+       return map_rewrite(map, vp, vsize, av);
 }
 }
+
+
+/*
+**  NIS_MAP_STORE
+*/
+
+void
+nis_map_store(map, lhs, rhs)
+       MAP *map;
+       char *lhs;
+       char *rhs;
+{
+       /* nothing */
+}
+
+
+/*
+**  NIS_MAP_CLOSE
+*/
+
+void
+nis_map_close(map)
+       MAP *map;
+{
+       /* nothing */
+}
+
+#endif /* NIS */
 \f/*
 \f/*
-**  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
-**
-**     Parameters:
-**             s -- the string to rewrite, NOT necessarily null terminated.
-**             slen -- the length of s.
-**             buf -- the place to write it.
-**             buflen -- the length of buf.
-**             av -- arguments to interpolate into buf.
+**  STAB (Symbol Table) Modules
+*/
+
+
+/*
+**  STAB_MAP_LOOKUP -- look up alias in symbol table
+*/
+
+char *
+stab_map_lookup(map, name, av, pstat)
+       register MAP *map;
+       char *name;
+       char **av;
+       int *pstat;
+{
+       register STAB *s;
+
+       if (tTd(38, 20))
+               printf("stab_lookup(%s)\n", name);
+
+       s = stab(name, ST_ALIAS, ST_FIND);
+       if (s != NULL)
+               return (s->s_alias);
+       return (NULL);
+}
+
+
+/*
+**  STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
+*/
+
+void
+stab_map_store(map, lhs, rhs)
+       register MAP *map;
+       char *lhs;
+       char *rhs;
+{
+       register STAB *s;
+
+       s = stab(lhs, ST_ALIAS, ST_ENTER);
+       s->s_alias = newstr(rhs);
+}
+
+
+/*
+**  STAB_MAP_OPEN -- initialize (reads data file)
 **
 **
-**     Returns:
-**             none.
+**     This is a wierd case -- it is only intended as a fallback for
+**     aliases.  For this reason, opens for write (only during a
+**     "newaliases") always fails, and opens for read open the
+**     actual underlying text file instead of the database.
+*/
+
+bool
+stab_map_open(map, mode)
+       register MAP *map;
+       int mode;
+{
+       if (tTd(38, 2))
+               printf("stab_map_open(%s)\n", map->map_file);
+
+       if (mode != O_RDONLY)
+       {
+               errno = ENODEV;
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+
+/*
+**  STAB_MAP_CLOSE -- close symbol table (???)
+*/
+
+void
+stab_map_close(map)
+       MAP *map;
+{
+       /* ignore it */
+}
+\f/*
+**  Implicit Modules
 **
 **
-**     Side Effects:
-**             none.
+**     Tries several types.  For back compatibility of aliases.
 */
 
 */
 
-map_rewrite(s, slen, buf, buflen, av)
-       register char *s;
-       int slen;
-       char buf[];
-       int buflen;
+
+/*
+**  IMPL_MAP_LOOKUP -- lookup in best open database
+*/
+
+char *
+impl_map_lookup(map, name, av, pstat)
+       MAP *map;
+       char *name;
        char **av;
        char **av;
+       int *pstat;
 {
 {
-       register char *bp;
-       char *buflim;
-       register char c;
-       char **avp;
-       register char *ap;
+       if (tTd(38, 20))
+               printf("impl_map_lookup(%s)\n", name);
+
+#ifdef NEWDB
+       if (bitset(MF_IMPL_HASH, map->map_mflags))
+               return db_map_lookup(map, name, av, pstat);
+#endif
+#ifdef NDBM
+       if (bitset(MF_IMPL_NDBM, map->map_mflags))
+               return ndbm_map_lookup(map, name, av, pstat);
+#endif
+       return stab_map_lookup(map, name, av, pstat);
+}
+
+/*
+**  IMPL_MAP_STORE -- store in open databases
+*/
+
+void
+impl_map_store(map, lhs, rhs)
+       MAP *map;
+       char *lhs;
+       char *rhs;
+{
+#ifdef NEWDB
+       if (bitset(MF_IMPL_HASH, map->map_mflags))
+               db_map_store(map, lhs, rhs);
+#endif
+#ifdef NDBM
+       if (bitset(MF_IMPL_NDBM, map->map_mflags))
+               ndbm_map_store(map, lhs, rhs);
+#endif
+       stab_map_store(map, lhs, rhs);
+}
+
+/*
+**  IMPL_MAP_OPEN -- implicit database open
+*/
+
+bool
+impl_map_open(map, mode)
+       MAP *map;
+       int mode;
+{
+       struct stat stb;
+
+       if (tTd(38, 2))
+               printf("impl_map_open(%s)\n", map->map_file);
 
 
-       if (tTd(23, 1))
+       if (stat(map->map_file, &stb) < 0)
        {
        {
-               printf("map_rewrite(%.*s), av =\n", slen, s);
-               for (avp = av; *avp != NULL; avp++)
-                       printf("\t%s\n", *avp);
+               /* no alias file at all */
+               return FALSE;
        }
 
        }
 
-       bp = buf;
-       buflim = &buf[buflen - 2];
-       while (--slen >= 0 && (c = *s++) != '\0')
+#ifdef NEWDB
+       map->map_mflags |= MF_IMPL_HASH;
+       if (hash_map_open(map, mode))
        {
        {
-               if (c != '%')
-               {
-  pushc:
-                       if (bp < buflim)
-                               *bp++ = c;
-                       continue;
-               }
-               if (--slen < 0 || (c = *s++) == '\0')
-                       c = '%';
-               if (c == '%')
-                       goto pushc;
-               if (!isdigit(c))
-               {
-                       *bp++ = '%';
-                       goto pushc;
-               }
-               c -= '0';
-               for (avp = av; --c >= 0 && *avp != NULL; avp++)
-                       continue;
-               if (*avp == NULL)
-                       continue;
-
-               /* transliterate argument into output string */
-               for (ap = *avp; (c = *ap++) != '\0'; )
-               {
-                       if (bp < buflim)
-                               *bp++ = c;
-               }
+#if defined(NDBM) && defined(YPCOMPAT)
+               if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0)
+#endif
+                       return TRUE;
        }
        }
-       *bp++ = '\0';
-       if (tTd(23, 1))
-               printf("map_rewrite => %s\n", buf);
+       else
+               map->map_mflags &= ~MF_IMPL_HASH;
+#endif
+#ifdef NDBM
+       map->map_mflags |= MF_IMPL_NDBM;
+       if (ndbm_map_open(map, mode))
+       {
+               return TRUE;
+       }
+       else
+               map->map_mflags &= ~MF_IMPL_NDBM;
+#endif
+
+#if !defined(NEWDB) && !defined(NDBM)
+       if (Verbose)
+               message("WARNING: cannot open alias database %s", map->map_file);
+#endif
+
+       return stab_map_open(map, mode);
+}
+
+
+/*
+**  IMPL_MAP_CLOSE -- close any open database(s)
+*/
+
+void
+impl_map_close(map)
+       MAP *map;
+{
+#ifdef NEWDB
+       if (bitset(MF_IMPL_HASH, map->map_mflags))
+       {
+               db_map_close(map);
+               map->map_mflags &= ~MF_IMPL_HASH;
+       }
+#endif
+
+#ifdef NDBM
+       if (bitset(MF_IMPL_NDBM, map->map_mflags))
+       {
+               ndbm_map_close(map);
+               map->map_mflags &= ~MF_IMPL_NDBM;
+       }
+#endif
+}
+\f/*
+**  NULL stubs
+*/
+
+bool
+null_map_open(map, mode)
+       MAP *map;
+       int mode;
+{
+       return TRUE;
+}
+
+void
+null_map_close(map)
+       MAP *map;
+{
+       return;
+}
+
+void
+null_map_store(map, key, val)
+       MAP *map;
+       char *key;
+       char *val;
+{
+       return;
 }
 }