summaryrefslogtreecommitdiffstats
path: root/usr.sbin/sendmail/src/map.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/sendmail/src/map.c')
-rw-r--r--usr.sbin/sendmail/src/map.c1339
1 files changed, 1339 insertions, 0 deletions
diff --git a/usr.sbin/sendmail/src/map.c b/usr.sbin/sendmail/src/map.c
new file mode 100644
index 0000000..01ba411
--- /dev/null
+++ b/usr.sbin/sendmail/src/map.c
@@ -0,0 +1,1339 @@
+/*
+ * Copyright (c) 1992 Eric P. Allman.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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
+static char sccsid[] = "@(#)map.c 8.25 (Berkeley) 4/17/94";
+#endif /* not lint */
+
+#include "sendmail.h"
+
+#ifdef NDBM
+#include <ndbm.h>
+#endif
+#ifdef NEWDB
+#include <db.h>
+#endif
+#ifdef NIS
+#include <rpcsvc/ypclnt.h>
+#endif
+
+/*
+** 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
+
+extern bool aliaswait __P((MAP *, char *, int));
+ /*
+** MAP_PARSEARGS -- parse config line arguments for database lookup
+**
+** This is a generic version of the map_parse method.
+**
+** Parameters:
+** map -- the map being initialized.
+** ap -- a pointer to the args on the config line.
+**
+** Returns:
+** TRUE -- if everything parsed OK.
+** FALSE -- otherwise.
+**
+** Side Effects:
+** null terminates the filename; stores it in map
+*/
+
+bool
+map_parseargs(map, ap)
+ MAP *map;
+ char *ap;
+{
+ register char *p = ap;
+
+ map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
+ for (;;)
+ {
+ while (isascii(*p) && isspace(*p))
+ p++;
+ if (*p != '-')
+ break;
+ switch (*++p)
+ {
+ case 'N':
+ map->map_mflags |= MF_INCLNULL;
+ map->map_mflags &= ~MF_TRY0NULL;
+ break;
+
+ case 'O':
+ map->map_mflags &= ~MF_TRY1NULL;
+ 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);
+
+ if (map->map_file == NULL)
+ {
+ syserr("No file name for %s map %s",
+ map->map_class->map_cname, map->map_mname);
+ return FALSE;
+ }
+ return TRUE;
+}
+ /*
+** 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:
+** 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:
+** 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;
+ 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;
+ }
+ 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;
+}
+ /*
+** 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();
+
+#ifdef XDEBUG
+ checkfd012("entering initmaps");
+#endif
+ CurEnv = e;
+ if (rebuild)
+ {
+ stabapply(map_init, 1);
+ stabapply(map_init, 2);
+ }
+ else
+ {
+ stabapply(map_init, 0);
+ }
+#ifdef XDEBUG
+ checkfd012("exiting initmaps");
+#endif
+}
+
+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, %d)\n",
+ map->map_class->map_cname == NULL ? "NULL" :
+ map->map_class->map_cname,
+ map->map_file == NULL ? "NULL" : map->map_file,
+ rebuild);
+
+ if (rebuild == (bitset(MF_ALIAS, map->map_mflags) &&
+ bitset(MCF_REBUILDABLE, map->map_class->map_cflags) ? 1 : 2))
+ {
+ if (tTd(38, 3))
+ printf("\twrong pass\n");
+ return;
+ }
+
+ /* 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 == 2)
+ {
+ rebuildaliases(map, FALSE);
+ }
+ else
+ {
+ if (map->map_class->map_open(map, O_RDONLY))
+ {
+ if (tTd(38, 4))
+ printf("\t%s:%s: valid\n",
+ map->map_class->map_cname == NULL ? "NULL" :
+ map->map_class->map_cname,
+ map->map_file == NULL ? "NULL" :
+ map->map_file);
+ map->map_mflags |= MF_OPEN;
+ }
+ else if (tTd(38, 4))
+ printf("\t%s:%s: invalid: %s\n",
+ map->map_class->map_cname == NULL ? "NULL" :
+ map->map_class->map_cname,
+ map->map_file == NULL ? "NULL" :
+ map->map_file,
+ errstring(errno));
+ }
+}
+ /*
+** NDBM modules
+*/
+
+#ifdef NDBM
+
+/*
+** DBM_MAP_OPEN -- DBM-style map open
+*/
+
+bool
+ndbm_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ register DBM *dbm;
+ struct stat st;
+
+ 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)
+ {
+#ifdef MAYBENEXTRELEASE
+ if (aliaswait(map, ".pag", FALSE))
+ return TRUE;
+#endif
+ 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)
+ {
+ if (bitset(MF_ALIAS, map->map_mflags) &&
+ !aliaswait(map, ".pag", TRUE))
+ return FALSE;
+ }
+ else
+ {
+ int fd;
+
+ /* exclusive lock for duration of rebuild */
+ fd = dbm_dirfno((DBM *) map->map_db1);
+ if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) &&
+ lockfile(fd, map->map_file, ".dir", LOCK_EX))
+ map->map_mflags |= MF_LOCKED;
+ }
+ if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0)
+ map->map_mtime = st.st_mtime;
+ return TRUE;
+}
+
+
+/*
+** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
+*/
+
+char *
+ndbm_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+ datum key, val;
+ int fd;
+ char keybuf[MAXNAME + 1];
+
+ if (tTd(38, 20))
+ printf("ndbm_map_lookup(%s)\n", name);
+
+ 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;
+ }
+ fd = dbm_dirfno((DBM *) map->map_db1);
+ if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
+ (void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
+ val.dptr = NULL;
+ if (bitset(MF_TRY0NULL, map->map_mflags))
+ {
+ val = dbm_fetch((DBM *) map->map_db1, key);
+ if (val.dptr != NULL)
+ map->map_mflags &= ~MF_TRY1NULL;
+ }
+ if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
+ {
+ key.dsize++;
+ val = dbm_fetch((DBM *) map->map_db1, key);
+ if (val.dptr != NULL)
+ map->map_mflags &= ~MF_TRY0NULL;
+ }
+ if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
+ (void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
+ if (val.dptr == NULL)
+ return NULL;
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ return map_rewrite(map, name, strlen(name), NULL);
+ else
+ return map_rewrite(map, val.dptr, val.dsize, av);
+}
+
+
+/*
+** 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 (tTd(38, 9))
+ printf("ndbm_map_close(%s, %x)\n", map->map_file, map->map_mflags);
+
+ if (bitset(MF_WRITABLE, map->map_mflags))
+ {
+#ifdef NIS
+ bool inclnull;
+ char buf[200];
+
+ inclnull = bitset(MF_INCLNULL, map->map_mflags);
+ map->map_mflags &= ~MF_INCLNULL;
+
+ (void) sprintf(buf, "%010ld", curtime());
+ ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
+
+ (void) gethostname(buf, sizeof buf);
+ ndbm_map_store(map, "YP_MASTER_NAME", buf);
+
+ if (inclnull)
+ map->map_mflags |= MF_INCLNULL;
+#endif
+
+ /* write out the distinguished alias */
+ ndbm_map_store(map, "@", "@");
+ }
+ dbm_close((DBM *) map->map_db1);
+}
+
+#endif
+ /*
+** NEWDB (Hash and BTree) Modules
+*/
+
+#ifdef NEWDB
+
+/*
+** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
+**
+** 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
+bt_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ DB *db;
+ int i;
+ int omode;
+ int fd;
+ struct stat st;
+ char buf[MAXNAME];
+
+ 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) && HASFLOCK
+ omode |= O_EXLOCK;
+# if !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)
+ {
+#ifdef MAYBENEXTRELEASE
+ if (aliaswait(map, ".db", FALSE))
+ return TRUE;
+#endif
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("Cannot open BTREE database %s", map->map_file);
+ return FALSE;
+ }
+#if !OLD_NEWDB && HASFLOCK
+ fd = db->fd(db);
+# if !defined(O_EXLOCK)
+ if (mode == O_RDWR && fd >= 0)
+ {
+ if (lockfile(fd, map->map_file, ".db", LOCK_EX))
+ map->map_mflags |= MF_LOCKED;
+ }
+# else
+ if (mode == O_RDONLY && fd >= 0)
+ (void) lockfile(fd, map->map_file, ".db", LOCK_UN);
+ else
+ map->map_mflags |= MF_LOCKED;
+# endif
+#endif
+
+ /* try to make sure that at least the database header is on disk */
+ if (mode == O_RDWR)
+#if OLD_NEWDB
+ (void) db->sync(db);
+#else
+ (void) db->sync(db, 0);
+
+ if (fd >= 0 && fstat(fd, &st) >= 0)
+ map->map_mtime = st.st_mtime;
+#endif
+
+ map->map_db2 = (void *) db;
+ if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
+ if (!aliaswait(map, ".db", TRUE))
+ return FALSE;
+ return TRUE;
+}
+
+
+/*
+** HASH_MAP_INIT -- HASH-style map initialization
+*/
+
+bool
+hash_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ DB *db;
+ int i;
+ int omode;
+ int fd;
+ struct stat st;
+ char buf[MAXNAME];
+
+ 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) && HASFLOCK
+ omode |= O_EXLOCK;
+# if !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)
+ {
+#ifdef MAYBENEXTRELEASE
+ if (aliaswait(map, ".db", FALSE))
+ return TRUE;
+#endif
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("Cannot open HASH database %s", map->map_file);
+ return FALSE;
+ }
+#if !OLD_NEWDB && HASFLOCK
+ fd = db->fd(db);
+# if !defined(O_EXLOCK)
+ if (mode == O_RDWR && fd >= 0)
+ {
+ if (lockfile(fd, map->map_file, ".db", LOCK_EX))
+ map->map_mflags |= MF_LOCKED;
+ }
+# else
+ if (mode == O_RDONLY && fd >= 0)
+ (void) lockfile(fd, map->map_file, ".db", LOCK_UN);
+ else
+ map->map_mflags |= MF_LOCKED;
+# endif
+#endif
+
+ /* try to make sure that at least the database header is on disk */
+ if (mode == O_RDWR)
+#if OLD_NEWDB
+ (void) db->sync(db);
+#else
+ (void) db->sync(db, 0);
+
+ if (fd >= 0 && fstat(fd, &st) >= 0)
+ map->map_mtime = st.st_mtime;
+#endif
+
+ map->map_db2 = (void *) db;
+ if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
+ if (!aliaswait(map, ".db", TRUE))
+ return FALSE;
+ return TRUE;
+}
+
+
+/*
+** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
+*/
+
+char *
+db_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+ DBT key, val;
+ register DB *db = (DB *) map->map_db2;
+ int st;
+ int saveerrno;
+ int fd;
+ char keybuf[MAXNAME + 1];
+
+ if (tTd(38, 20))
+ printf("db_map_lookup(%s)\n", name);
+
+ 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 !OLD_NEWDB
+ fd = db->fd(db);
+ if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
+ (void) lockfile(db->fd(db), map->map_file, ".db", LOCK_SH);
+#endif
+ st = 1;
+ if (bitset(MF_TRY0NULL, map->map_mflags))
+ {
+ st = db->get(db, &key, &val, 0);
+ if (st == 0)
+ map->map_mflags &= ~MF_TRY1NULL;
+ }
+ if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
+ {
+ key.size++;
+ st = db->get(db, &key, &val, 0);
+ if (st == 0)
+ map->map_mflags &= ~MF_TRY0NULL;
+ }
+ saveerrno = errno;
+#if !OLD_NEWDB
+ if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
+ (void) lockfile(fd, map->map_file, ".db", LOCK_UN);
+#endif
+ if (st != 0)
+ {
+ errno = saveerrno;
+ if (st < 0)
+ syserr("db_map_lookup: get (%s)", name);
+ return NULL;
+ }
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ return map_rewrite(map, name, strlen(name), NULL);
+ else
+ return map_rewrite(map, val.data, val.size, av);
+}
+
+
+/*
+** 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
+*/
+
+void
+db_map_close(map)
+ MAP *map;
+{
+ register DB *db = map->map_db2;
+
+ if (tTd(38, 9))
+ printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags);
+
+ if (bitset(MF_WRITABLE, map->map_mflags))
+ {
+ /* write out the distinguished alias */
+ db_map_store(map, "@", "@");
+ }
+
+ if (db->close(db) != 0)
+ syserr("readaliases: db close failure");
+}
+
+#endif
+ /*
+** NIS Modules
+*/
+
+# ifdef NIS
+
+# ifndef YPERR_BUSY
+# define YPERR_BUSY 16
+# endif
+
+/*
+** 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)
+ {
+ /* issue a pseudo-error message */
+#ifdef ENOSYS
+ errno = ENOSYS;
+#else
+# ifdef EFTYPE
+ errno = EFTYPE;
+# else
+ errno = ENXIO;
+# endif
+#endif
+ return FALSE;
+ }
+
+ p = strchr(map->map_file, '@');
+ if (p != NULL)
+ {
+ *p++ = '\0';
+ if (*p != '\0')
+ map->map_domain = p;
+ }
+
+ if (*map->map_file == '\0')
+ map->map_file = "mail.aliases";
+
+ if (map->map_domain == NULL)
+ {
+ yperr = yp_get_default_domain(&map->map_domain);
+ if (yperr != 0)
+ {
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("NIS map %s specified, but NIS not running\n",
+ map->map_file);
+ return FALSE;
+ }
+ }
+
+ /* 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);
+ yperr = YPERR_KEY;
+ if (bitset(MF_TRY0NULL, map->map_mflags))
+ {
+ yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
+ &vp, &vsize);
+ if (yperr == 0)
+ map->map_mflags &= ~MF_TRY1NULL;
+ }
+ if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
+ {
+ buflen++;
+ yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
+ &vp, &vsize);
+ if (yperr == 0)
+ map->map_mflags &= ~MF_TRY0NULL;
+ }
+ if (yperr != 0)
+ {
+ if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
+ map->map_mflags &= ~(MF_VALID|MF_OPEN);
+ return NULL;
+ }
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ return map_rewrite(map, name, strlen(name), NULL);
+ else
+ 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 */
+ /*
+** 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)
+**
+** 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;
+{
+ FILE *af;
+ struct stat st;
+
+ if (tTd(38, 2))
+ printf("stab_map_open(%s)\n", map->map_file);
+
+ if (mode != O_RDONLY)
+ {
+ errno = ENODEV;
+ return FALSE;
+ }
+
+ af = fopen(map->map_file, "r");
+ if (af == NULL)
+ return FALSE;
+ readaliases(map, af, TRUE);
+
+ if (fstat(fileno(af), &st) >= 0)
+ map->map_mtime = st.st_mtime;
+ fclose(af);
+
+ return TRUE;
+}
+
+
+/*
+** STAB_MAP_CLOSE -- close symbol table.
+**
+** Since this is in memory, there is nothing to do.
+*/
+
+void
+stab_map_close(map)
+ MAP *map;
+{
+ /* ignore it */
+}
+ /*
+** Implicit Modules
+**
+** Tries several types. For back compatibility of aliases.
+*/
+
+
+/*
+** IMPL_MAP_LOOKUP -- lookup in best open database
+*/
+
+char *
+impl_map_lookup(map, name, av, pstat)
+ MAP *map;
+ char *name;
+ char **av;
+ int *pstat;
+{
+ 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, %d)\n", map->map_file, mode);
+
+ if (stat(map->map_file, &stb) < 0)
+ {
+ /* no alias file at all */
+ if (tTd(38, 3))
+ printf("no map file\n");
+ return FALSE;
+ }
+
+#ifdef NEWDB
+ map->map_mflags |= MF_IMPL_HASH;
+ if (hash_map_open(map, mode))
+ {
+#if defined(NDBM) && defined(NIS)
+ if (mode == O_RDONLY || access("/var/yp/Makefile", R_OK) != 0)
+#endif
+ return TRUE;
+ }
+ 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);
+#else
+ if (mode != O_RDONLY)
+ usrerr("Cannot rebuild aliases: no database format defined");
+#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
+}
+ /*
+** 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;
+}
OpenPOWER on IntegriCloud