summaryrefslogtreecommitdiff
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.c2385
1 files changed, 2193 insertions, 192 deletions
diff --git a/usr.sbin/sendmail/src/map.c b/usr.sbin/sendmail/src/map.c
index a2b3337bb0f0..b8ea903fb3de 100644
--- a/usr.sbin/sendmail/src/map.c
+++ b/usr.sbin/sendmail/src/map.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1992 Eric P. Allman.
+ * Copyright (c) 1992, 1995 Eric P. Allman.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -33,19 +33,25 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)map.c 8.25.1.1 (Berkeley) 2/10/95";
+static char sccsid[] = "@(#)map.c 8.107 (Berkeley) 11/20/95";
#endif /* not lint */
#include "sendmail.h"
#ifdef NDBM
-#include <ndbm.h>
+# include <ndbm.h>
#endif
#ifdef NEWDB
-#include <db.h>
+# ifdef R_FIRST
+ ERROR README: You are running the Berkeley DB version of ndbm.h. See
+ ERROR README: the READ_ME file about tweaking Berkeley DB so it can
+ ERROR README: coexist with NDBM, or delete -DNDBM from the Makefile.
+# endif
+# include <db.h>
#endif
#ifdef NIS
-#include <rpcsvc/ypclnt.h>
+ struct dom_binding; /* forward reference needed on IRIX */
+# include <rpcsvc/ypclnt.h>
#endif
/*
@@ -82,11 +88,24 @@ static char sccsid[] = "@(#)map.c 8.25.1.1 (Berkeley) 2/10/95";
**
** void map_close(MAP *map)
** Close the map.
+**
+** This file also includes the implementation for getcanonname.
+** It is currently implemented in a pretty ad-hoc manner; it ought
+** to be more properly integrated into the map structure.
*/
#define DBMMODE 0644
+#define EX_NOTFOUND EX_NOHOST
+
extern bool aliaswait __P((MAP *, char *, int));
+extern bool extract_canonname __P((char *, char *, char[]));
+
+#if defined(O_EXLOCK) && HASFLOCK
+# define LOCK_ON_OPEN 1 /* we can open/create a locked file */
+#else
+# define LOCK_ON_OPEN 0 /* no such luck -- bend over backwards */
+#endif
/*
** MAP_PARSEARGS -- parse config line arguments for database lookup
**
@@ -141,9 +160,59 @@ map_parseargs(map, ap)
map->map_mflags |= MF_MATCHONLY;
break;
+ case 'A':
+ map->map_mflags |= MF_APPEND;
+ break;
+
+ case 'q':
+ map->map_mflags |= MF_KEEPQUOTES;
+ break;
+
case 'a':
map->map_app = ++p;
break;
+
+ case 'k':
+ while (isascii(*++p) && isspace(*p))
+ continue;
+ map->map_keycolnm = p;
+ break;
+
+ case 'v':
+ while (isascii(*++p) && isspace(*p))
+ continue;
+ map->map_valcolnm = p;
+ break;
+
+ case 'z':
+ if (*++p != '\\')
+ map->map_coldelim = *p;
+ else
+ {
+ switch (*++p)
+ {
+ case 'n':
+ map->map_coldelim = '\n';
+ break;
+
+ case 't':
+ map->map_coldelim = '\t';
+ break;
+
+ default:
+ map->map_coldelim = '\\';
+ }
+ }
+ break;
+#ifdef RESERVED_FOR_SUN
+ case 'd':
+ map->map_mflags |= MF_DOMAIN_WIDE;
+ break;
+
+ case 's':
+ /* info type */
+ break;
+#endif
}
while (*p != '\0' && !(isascii(*p) && isspace(*p)))
p++;
@@ -152,6 +221,10 @@ map_parseargs(map, ap)
}
if (map->map_app != NULL)
map->map_app = newstr(map->map_app);
+ if (map->map_keycolnm != NULL)
+ map->map_keycolnm = newstr(map->map_keycolnm);
+ if (map->map_valcolnm != NULL)
+ map->map_valcolnm = newstr(map->map_valcolnm);
if (*p != '\0')
{
@@ -168,7 +241,8 @@ map_parseargs(map, ap)
if (*p != '\0')
map->map_rebuild = newstr(p);
- if (map->map_file == NULL)
+ if (map->map_file == NULL &&
+ !bitset(MCF_OPTFILE, map->map_class->map_cflags))
{
syserr("No file name for %s map %s",
map->map_class->map_cname, map->map_mname);
@@ -316,13 +390,14 @@ map_rewrite(map, s, slen, av)
** if ~NDBM: reads the aliases into the symbol table.
*/
+void
initmaps(rebuild, e)
bool rebuild;
register ENVELOPE *e;
{
extern void map_init();
-#ifdef XDEBUG
+#if XDEBUG
checkfd012("entering initmaps");
#endif
CurEnv = e;
@@ -335,7 +410,7 @@ initmaps(rebuild, e)
{
stabapply(map_init, 0);
}
-#ifdef XDEBUG
+#if XDEBUG
checkfd012("exiting initmaps");
#endif
}
@@ -356,9 +431,10 @@ map_init(s, rebuild)
return;
if (tTd(38, 2))
- printf("map_init(%s:%s, %d)\n",
+ printf("map_init(%s:%s, %s, %d)\n",
map->map_class->map_cname == NULL ? "NULL" :
map->map_class->map_cname,
+ map->map_mname == NULL ? "NULL" : map->map_mname,
map->map_file == NULL ? "NULL" : map->map_file,
rebuild);
@@ -386,23 +462,241 @@ map_init(s, rebuild)
if (map->map_class->map_open(map, O_RDONLY))
{
if (tTd(38, 4))
- printf("\t%s:%s: valid\n",
+ printf("\t%s:%s %s: valid\n",
map->map_class->map_cname == NULL ? "NULL" :
map->map_class->map_cname,
+ map->map_mname == NULL ? "NULL" :
+ map->map_mname,
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));
+ else
+ {
+ if (tTd(38, 4))
+ printf("\t%s:%s %s: invalid: %s\n",
+ map->map_class->map_cname == NULL ? "NULL" :
+ map->map_class->map_cname,
+ map->map_mname == NULL ? "NULL" :
+ map->map_mname,
+ map->map_file == NULL ? "NULL" :
+ map->map_file,
+ errstring(errno));
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ {
+ extern MAPCLASS BogusMapClass;
+
+ map->map_class = &BogusMapClass;
+ map->map_mflags |= MF_OPEN;
+ }
+ }
}
}
/*
+** GETCANONNAME -- look up name using service switch
+**
+** Parameters:
+** host -- the host name to look up.
+** hbsize -- the size of the host buffer.
+** trymx -- if set, try MX records.
+**
+** Returns:
+** TRUE -- if the host was found.
+** FALSE -- otherwise.
+*/
+
+bool
+getcanonname(host, hbsize, trymx)
+ char *host;
+ int hbsize;
+ bool trymx;
+{
+ int nmaps;
+ int mapno;
+ bool found = FALSE;
+ bool got_tempfail = FALSE;
+ auto int stat;
+ char *maptype[MAXMAPSTACK];
+ short mapreturn[MAXMAPACTIONS];
+
+ nmaps = switch_map_find("hosts", maptype, mapreturn);
+ for (mapno = 0; mapno < nmaps; mapno++)
+ {
+ int i;
+
+ if (tTd(38, 20))
+ printf("getcanonname(%s), trying %s\n",
+ host, maptype[mapno]);
+ if (strcmp("files", maptype[mapno]) == 0)
+ {
+ extern bool text_getcanonname __P((char *, int, int *));
+
+ found = text_getcanonname(host, hbsize, &stat);
+ }
+#ifdef NIS
+ else if (strcmp("nis", maptype[mapno]) == 0)
+ {
+ extern bool nis_getcanonname __P((char *, int, int *));
+
+ found = nis_getcanonname(host, hbsize, &stat);
+ }
+#endif
+#ifdef NISPLUS
+ else if (strcmp("nisplus", maptype[mapno]) == 0)
+ {
+ extern bool nisplus_getcanonname __P((char *, int, int *));
+
+ found = nisplus_getcanonname(host, hbsize, &stat);
+ }
+#endif
+#if NAMED_BIND
+ else if (strcmp("dns", maptype[mapno]) == 0)
+ {
+ extern bool dns_getcanonname __P((char *, int, bool, int *));
+
+ found = dns_getcanonname(host, hbsize, trymx, &stat);
+ }
+#endif
+#if NETINFO
+ else if (strcmp("netinfo", maptype[mapno]) == 0)
+ {
+ extern bool ni_getcanonname __P((char *, int, int *));
+
+ found = ni_getcanonname(host, hbsize, &stat);
+ }
+#endif
+ else
+ {
+ found = FALSE;
+ stat = EX_UNAVAILABLE;
+ }
+
+ /*
+ ** Heuristic: if $m is not set, we are running during system
+ ** startup. In this case, when a name is apparently found
+ ** but has no dot, treat is as not found. This avoids
+ ** problems if /etc/hosts has no FQDN but is listed first
+ ** in the service switch.
+ */
+
+ if (found &&
+ (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
+ break;
+
+ /* see if we should continue */
+ if (stat == EX_TEMPFAIL)
+ {
+ i = MA_TRYAGAIN;
+ got_tempfail = TRUE;
+ }
+ else if (stat == EX_NOTFOUND)
+ i = MA_NOTFOUND;
+ else
+ i = MA_UNAVAIL;
+ if (bitset(1 << mapno, mapreturn[i]))
+ break;
+ }
+
+ if (found)
+ {
+ char *d;
+
+ if (tTd(38, 20))
+ printf("getcanonname(%s), found\n", host);
+
+ /*
+ ** If returned name is still single token, compensate
+ ** by tagging on $m. This is because some sites set
+ ** up their DNS or NIS databases wrong.
+ */
+
+ if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
+ {
+ d = macvalue('m', CurEnv);
+ if (d != NULL &&
+ hbsize > (int) (strlen(host) + strlen(d) + 1))
+ {
+ if (host[strlen(host) - 1] != '.')
+ strcat(host, ".");
+ strcat(host, d);
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+ if (tTd(38, 20))
+ printf("getcanonname(%s), failed, stat=%d\n", host, stat);
+
+#if NAMED_BIND
+ if (stat == EX_NOHOST && !got_tempfail)
+ h_errno = HOST_NOT_FOUND;
+ else
+ h_errno = TRY_AGAIN;
+#endif
+
+ return FALSE;
+}
+ /*
+** EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
+**
+** Parameters:
+** name -- the name against which to match.
+** line -- the /etc/hosts line.
+** cbuf -- the location to store the result.
+**
+** Returns:
+** TRUE -- if the line matched the desired name.
+** FALSE -- otherwise.
+*/
+
+bool
+extract_canonname(name, line, cbuf)
+ char *name;
+ char *line;
+ char cbuf[];
+{
+ int i;
+ char *p;
+ bool found = FALSE;
+ extern char *get_column();
+
+ cbuf[0] = '\0';
+ if (line[0] == '#')
+ return FALSE;
+
+ for (i = 1; ; i++)
+ {
+ char nbuf[MAXNAME + 1];
+
+ p = get_column(line, i, '\0', nbuf);
+ if (p == NULL)
+ break;
+ if (cbuf[0] == '\0' ||
+ (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
+ strcpy(cbuf, p);
+ if (strcasecmp(name, p) == 0)
+ found = TRUE;
+ }
+ if (found && strchr(cbuf, '.') == NULL)
+ {
+ /* try to add a domain on the end of the name */
+ char *domain = macvalue('m', CurEnv);
+
+ if (domain != NULL &&
+ strlen(domain) + strlen(cbuf) + 1 < MAXNAME)
+ {
+ p = &cbuf[strlen(cbuf)];
+ *p++ = '.';
+ strcpy(p, domain);
+ }
+ }
+ return found;
+}
+ /*
** NDBM modules
*/
@@ -419,40 +713,99 @@ ndbm_map_open(map, mode)
{
register DBM *dbm;
struct stat st;
+ int fd;
if (tTd(38, 2))
- printf("ndbm_map_open(%s, %d)\n", map->map_file, mode);
+ printf("ndbm_map_open(%s, %s, %d)\n",
+ map->map_mname, map->map_file, mode);
+#if LOCK_ON_OPEN
+ if (mode == O_RDONLY)
+ mode |= O_SHLOCK;
+ else
+ mode |= O_CREAT|O_TRUNC|O_EXLOCK;
+#else
if (mode == O_RDWR)
+ {
+# ifdef NOFTRUNCATE
+ /*
+ ** Warning: race condition. Try to lock the file as
+ ** quickly as possible after opening it.
+ */
+
mode |= O_CREAT|O_TRUNC;
+# else
+ /*
+ ** This ugly code opens the map without truncating it,
+ ** locks the file, then truncates it. Necessary to
+ ** avoid race conditions.
+ */
+
+ int dirfd;
+ int pagfd;
+ char dirfile[MAXNAME + 1];
+ char pagfile[MAXNAME + 1];
+
+ sprintf(dirfile, "%s.dir", map->map_file);
+ sprintf(pagfile, "%s.pag", map->map_file);
+ dirfd = open(dirfile, mode|O_CREAT, DBMMODE);
+ pagfd = open(pagfile, mode|O_CREAT, DBMMODE);
+
+ if (dirfd < 0 || pagfd < 0)
+ {
+ syserr("ndbm_map_open: cannot create database %s",
+ map->map_file);
+ close(dirfd);
+ close(pagfd);
+ return FALSE;
+ }
+ if (!lockfile(dirfd, map->map_file, ".dir", LOCK_EX))
+ syserr("ndbm_map_open: cannot lock %s.dir",
+ map->map_file);
+ if (ftruncate(dirfd, 0) < 0)
+ syserr("ndbm_map_open: cannot truncate %s.dir",
+ map->map_file);
+ if (ftruncate(pagfd, 0) < 0)
+ syserr("ndbm_map_open: cannot truncate %s.pag",
+ map->map_file);
+
+ /* we can safely unlock because others will wait for @:@ */
+ close(dirfd);
+ close(pagfd);
+# endif
+ }
+#endif
/* open the database */
dbm = dbm_open(map->map_file, mode, DBMMODE);
if (dbm == NULL)
{
-#ifdef MAYBENEXTRELEASE
- if (aliaswait(map, ".pag", FALSE))
+ if (bitset(MF_ALIAS, map->map_mflags) &&
+ 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;
+ fd = dbm_dirfno((DBM *) map->map_db1);
if (mode == O_RDONLY)
{
+#if LOCK_ON_OPEN
+ if (fd >= 0)
+ (void) lockfile(fd, map->map_file, ".pag", LOCK_UN);
+#endif
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 !LOCK_ON_OPEN
if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags) &&
lockfile(fd, map->map_file, ".dir", LOCK_EX))
+#endif
map->map_mflags |= MF_LOCKED;
}
if (fstat(dbm_dirfno((DBM *) map->map_db1), &st) >= 0)
@@ -477,7 +830,8 @@ ndbm_map_lookup(map, name, av, statp)
char keybuf[MAXNAME + 1];
if (tTd(38, 20))
- printf("ndbm_map_lookup(%s)\n", name);
+ printf("ndbm_map_lookup(%s, %s)\n",
+ map->map_mname, name);
key.dptr = name;
key.dsize = strlen(name);
@@ -532,7 +886,8 @@ ndbm_map_store(map, lhs, rhs)
int stat;
if (tTd(38, 12))
- printf("ndbm_map_store(%s, %s)\n", lhs, rhs);
+ printf("ndbm_map_store(%s, %s, %s)\n",
+ map->map_mname, lhs, rhs);
key.dsize = strlen(lhs);
key.dptr = lhs;
@@ -549,7 +904,33 @@ ndbm_map_store(map, lhs, rhs)
stat = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
if (stat > 0)
{
- usrerr("050 Warning: duplicate alias name %s", lhs);
+ if (!bitset(MF_APPEND, map->map_mflags))
+ usrerr("050 Warning: duplicate alias name %s", lhs);
+ else
+ {
+ static char *buf = NULL;
+ static int bufsiz = 0;
+ auto int xstat;
+ datum old;
+
+ old.dptr = ndbm_map_lookup(map, key.dptr, NULL, &xstat);
+ if (old.dptr != NULL && *old.dptr != '\0')
+ {
+ old.dsize = strlen(old.dptr);
+ if (data.dsize + old.dsize + 2 > bufsiz)
+ {
+ if (buf != NULL)
+ (void) free(buf);
+ bufsiz = data.dsize + old.dsize + 2;
+ buf = xalloc(bufsiz);
+ }
+ sprintf(buf, "%s,%s", data.dptr, old.dptr);
+ data.dsize = data.dsize + old.dsize + 1;
+ data.dptr = buf;
+ if (tTd(38, 9))
+ printf("ndbm_map_store append=%s\n", data.dptr);
+ }
+ }
stat = dbm_store((DBM *) map->map_db1, key, data, DBM_REPLACE);
}
if (stat != 0)
@@ -566,7 +947,8 @@ ndbm_map_close(map)
register MAP *map;
{
if (tTd(38, 9))
- printf("ndbm_map_close(%s, %x)\n", map->map_file, map->map_mflags);
+ printf("ndbm_map_close(%s, %s, %x)\n",
+ map->map_mname, map->map_file, map->map_mflags);
if (bitset(MF_WRITABLE, map->map_mflags))
{
@@ -577,11 +959,14 @@ ndbm_map_close(map)
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);
+ if (strstr(map->map_file, "/yp/") != NULL)
+ {
+ (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);
+ (void) gethostname(buf, sizeof buf);
+ ndbm_map_store(map, "YP_MASTER_NAME", buf);
+ }
if (inclnull)
map->map_mflags |= MF_INCLNULL;
@@ -617,143 +1002,111 @@ 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;
+ printf("bt_map_open(%s, %s, %d)\n",
+ map->map_mname, map->map_file, mode);
+ return db_map_open(map, mode, DB_BTREE);
}
-
-/*
-** HASH_MAP_INIT -- HASH-style map initialization
-*/
-
bool
hash_map_open(map, mode)
MAP *map;
int mode;
{
+ if (tTd(38, 2))
+ printf("hash_map_open(%s, %s, %d)\n",
+ map->map_mname, map->map_file, mode);
+ return db_map_open(map, mode, DB_HASH);
+}
+
+bool
+db_map_open(map, mode, dbtype)
+ MAP *map;
+ int mode;
+ DBTYPE dbtype;
+{
DB *db;
int i;
int omode;
int fd;
+ int saveerrno;
struct stat st;
- char buf[MAXNAME];
+ char buf[MAXNAME + 1];
- if (tTd(38, 2))
- printf("hash_map_open(%s, %d)\n", map->map_file, mode);
+ (void) strcpy(buf, map->map_file);
+ i = strlen(buf);
+ if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
+ (void) strcat(buf, ".db");
omode = mode;
- if (omode == O_RDWR)
- {
- omode |= O_CREAT|O_TRUNC;
-#if defined(O_EXLOCK) && HASFLOCK
- omode |= O_EXLOCK;
+
+#if LOCK_ON_OPEN
+ if (mode == O_RDWR)
+ omode |= O_CREAT|O_TRUNC|O_EXLOCK;
# if !OLD_NEWDB
- }
else
- {
omode |= O_SHLOCK;
# endif
-#endif
+#else
+ if (mode == O_RDWR)
+ omode |= O_CREAT;
+
+ /*
+ ** Pre-lock the file to avoid race conditions. In particular,
+ ** since dbopen returns NULL if the file is zero length, we
+ ** must have a locked instance around the dbopen.
+ */
+
+ fd = open(buf, omode, DBMMODE);
+
+ if (fd < 0)
+ {
+ syserr("db_map_open: cannot pre-open database %s",
+ buf);
+ close(fd);
+ return FALSE;
}
+ if (!lockfile(fd, map->map_file, ".db",
+ mode == O_RDONLY ? LOCK_SH : LOCK_EX))
+ syserr("db_map_open: cannot lock %s", buf);
+ if (mode == O_RDWR)
+ omode |= O_TRUNC;
+#endif
+
+ db = dbopen(buf, omode, DBMMODE, dbtype, NULL);
+ saveerrno = errno;
+
+#if !LOCK_ON_OPEN
+ /* we can safely unlock now because others will wait for @:@ */
+ close(fd);
+#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))
+ if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
+ aliaswait(map, ".db", FALSE))
return TRUE;
-#endif
+ errno = saveerrno;
if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("Cannot open HASH database %s", map->map_file);
+ syserr("Cannot open DB database %s", map->map_file);
return FALSE;
}
-#if !OLD_NEWDB && HASFLOCK
+#if !OLD_NEWDB
fd = db->fd(db);
-# if !defined(O_EXLOCK)
+# if LOCK_ON_OPEN
+ if (fd >= 0)
+ {
+ if (mode == O_RDONLY)
+ (void) lockfile(fd, map->map_file, ".db", LOCK_UN);
+ else
+ map->map_mflags |= MF_LOCKED;
+ }
+# else
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
@@ -769,9 +1122,9 @@ hash_map_open(map, mode)
#endif
map->map_db2 = (void *) db;
- if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags))
- if (!aliaswait(map, ".db", TRUE))
- return FALSE;
+ if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
+ !aliaswait(map, ".db", TRUE))
+ return FALSE;
return TRUE;
}
@@ -795,7 +1148,8 @@ db_map_lookup(map, name, av, statp)
char keybuf[MAXNAME + 1];
if (tTd(38, 20))
- printf("db_map_lookup(%s)\n", name);
+ printf("db_map_lookup(%s, %s)\n",
+ map->map_mname, name);
key.size = strlen(name);
if (key.size > sizeof keybuf - 1)
@@ -857,8 +1211,9 @@ db_map_store(map, lhs, rhs)
DBT data;
register DB *db = map->map_db2;
- if (tTd(38, 20))
- printf("db_map_store(%s, %s)\n", lhs, rhs);
+ if (tTd(38, 12))
+ printf("db_map_store(%s, %s, %s)\n",
+ map->map_mname, lhs, rhs);
key.size = strlen(lhs);
key.data = lhs;
@@ -875,7 +1230,32 @@ db_map_store(map, lhs, rhs)
stat = db->put(db, &key, &data, R_NOOVERWRITE);
if (stat > 0)
{
- usrerr("050 Warning: duplicate alias name %s", lhs);
+ if (!bitset(MF_APPEND, map->map_mflags))
+ usrerr("050 Warning: duplicate alias name %s", lhs);
+ else
+ {
+ static char *buf = NULL;
+ static int bufsiz = 0;
+ DBT old;
+
+ old.data = db_map_lookup(map, key.data, NULL, &stat);
+ if (old.data != NULL)
+ {
+ old.size = strlen(old.data);
+ if (data.size + old.size + 2 > bufsiz)
+ {
+ if (buf != NULL)
+ (void) free(buf);
+ bufsiz = data.size + old.size + 2;
+ buf = xalloc(bufsiz);
+ }
+ sprintf(buf, "%s,%s", data.data, old.data);
+ data.size = data.size + old.size + 1;
+ data.data = buf;
+ if (tTd(38, 9))
+ printf("db_map_store append=%s\n", data.data);
+ }
+ }
stat = db->put(db, &key, &data, 0);
}
if (stat != 0)
@@ -894,7 +1274,8 @@ db_map_close(map)
register DB *db = map->map_db2;
if (tTd(38, 9))
- printf("db_map_close(%s, %x)\n", map->map_file, map->map_mflags);
+ printf("db_map_close(%s, %s, %x)\n",
+ map->map_mname, map->map_file, map->map_mflags);
if (bitset(MF_WRITABLE, map->map_mflags))
{
@@ -930,10 +1311,10 @@ nis_map_open(map, mode)
register char *p;
auto char *vp;
auto int vsize;
- char *master;
if (tTd(38, 2))
- printf("nis_map_open(%s)\n", map->map_file);
+ printf("nis_map_open(%s, %s, %d)\n",
+ map->map_mname, map->map_file, mode);
if (mode != O_RDONLY)
{
@@ -967,7 +1348,7 @@ nis_map_open(map, mode)
if (yperr != 0)
{
if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("NIS map %s specified, but NIS not running\n",
+ syserr("421 NIS map %s specified, but NIS not running\n",
map->map_file);
return FALSE;
}
@@ -977,14 +1358,29 @@ nis_map_open(map, mode)
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",
+ 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;
+ {
+ /*
+ ** We ought to be calling aliaswait() here if this is an
+ ** alias file, but powerful HP-UX NIS servers apparently
+ ** don't insert the @:@ token into the alias map when it
+ ** is rebuilt, so aliaswait() just hangs. I hate HP-UX.
+ */
+
+#if 0
+ if (!bitset(MF_ALIAS, map->map_mflags) ||
+ aliaswait(map, NULL, TRUE))
+#endif
+ return TRUE;
+ }
if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("Cannot bind to domain %s: %s", map->map_domain,
- yperr_string(yperr));
+ {
+ syserr("421 Cannot bind to map %s in domain %s: %s",
+ map->map_file, map->map_domain, yperr_string(yperr));
+ }
return FALSE;
}
@@ -1008,7 +1404,8 @@ nis_map_lookup(map, name, av, statp)
char keybuf[MAXNAME + 1];
if (tTd(38, 20))
- printf("nis_map_lookup(%s)\n", name);
+ printf("nis_map_lookup(%s, %s)\n",
+ map->map_mname, name);
buflen = strlen(name);
if (buflen > sizeof keybuf - 1)
@@ -1046,31 +1443,1131 @@ nis_map_lookup(map, name, av, statp)
/*
-** NIS_MAP_STORE
+** NIS_GETCANONNAME -- look up canonical name in NIS
*/
-void
-nis_map_store(map, lhs, rhs)
+bool
+nis_getcanonname(name, hbsize, statp)
+ char *name;
+ int hbsize;
+ int *statp;
+{
+ char *vp;
+ auto int vsize;
+ int keylen;
+ int yperr;
+ static bool try0null = TRUE;
+ static bool try1null = TRUE;
+ static char *yp_domain = NULL;
+ char host_record[MAXLINE];
+ char cbuf[MAXNAME];
+ char nbuf[MAXNAME + 1];
+
+ if (tTd(38, 20))
+ printf("nis_getcanonname(%s)\n", name);
+
+ if (strlen(name) >= sizeof nbuf)
+ {
+ *statp = EX_UNAVAILABLE;
+ return FALSE;
+ }
+ (void) strcpy(nbuf, name);
+ shorten_hostname(nbuf);
+ keylen = strlen(nbuf);
+
+ if (yp_domain == NULL)
+ yp_get_default_domain(&yp_domain);
+ makelower(nbuf);
+ yperr = YPERR_KEY;
+ if (try0null)
+ {
+ yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
+ &vp, &vsize);
+ if (yperr == 0)
+ try1null = FALSE;
+ }
+ if (yperr == YPERR_KEY && try1null)
+ {
+ keylen++;
+ yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
+ &vp, &vsize);
+ if (yperr == 0)
+ try0null = FALSE;
+ }
+ if (yperr != 0)
+ {
+ if (yperr == YPERR_KEY)
+ *statp = EX_NOHOST;
+ else if (yperr == YPERR_BUSY)
+ *statp = EX_TEMPFAIL;
+ else
+ *statp = EX_UNAVAILABLE;
+ return FALSE;
+ }
+ strncpy(host_record, vp, vsize);
+ host_record[vsize] = '\0';
+ if (tTd(38, 44))
+ printf("got record `%s'\n", host_record);
+ if (!extract_canonname(nbuf, host_record, cbuf))
+ {
+ /* this should not happen, but.... */
+ *statp = EX_NOHOST;
+ return FALSE;
+ }
+ if (hbsize < strlen(cbuf))
+ {
+ *statp = EX_UNAVAILABLE;
+ return FALSE;
+ }
+ strcpy(name, cbuf);
+ *statp = EX_OK;
+ return TRUE;
+}
+
+#endif
+ /*
+** NISPLUS Modules
+**
+** This code donated by Sun Microsystems.
+*/
+
+#ifdef NISPLUS
+
+#undef NIS /* symbol conflict in nis.h */
+#include <rpcsvc/nis.h>
+#include <rpcsvc/nislib.h>
+
+#define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
+#define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
+#define COL_MAX(res) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
+#define PARTIAL_NAME(x) ((x)[strlen(x) - 1] != '.')
+
+/*
+** NISPLUS_MAP_OPEN -- open nisplus table
+*/
+
+bool
+nisplus_map_open(map, mode)
MAP *map;
- char *lhs;
- char *rhs;
+ int mode;
{
- /* nothing */
+ register char *p;
+ char qbuf[MAXLINE + NIS_MAXNAMELEN];
+ nis_result *res = NULL;
+ u_int objs_len;
+ nis_object *obj_ptr;
+ int retry_cnt, max_col, i;
+
+ if (tTd(38, 2))
+ printf("nisplus_map_open(%s, %s, %d)\n",
+ map->map_mname, map->map_file, mode);
+
+ if (mode != O_RDONLY)
+ {
+ errno = ENODEV;
+ return FALSE;
+ }
+
+ if (*map->map_file == '\0')
+ map->map_file = "mail_aliases.org_dir";
+
+ if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
+ {
+ /* set default NISPLUS Domain to $m */
+ extern char *nisplus_default_domain();
+
+ map->map_domain = newstr(nisplus_default_domain());
+ if (tTd(38, 2))
+ printf("nisplus_map_open(%s): using domain %s\n",
+ map->map_file, map->map_domain);
+ }
+ if (!PARTIAL_NAME(map->map_file))
+ map->map_domain = newstr("");
+
+ /* check to see if this map actually exists */
+ if (PARTIAL_NAME(map->map_file))
+ sprintf(qbuf, "%s.%s", map->map_file, map->map_domain);
+ else
+ strcpy(qbuf, map->map_file);
+
+ retry_cnt = 0;
+ while (res == NULL || res->status != NIS_SUCCESS)
+ {
+ res = nis_lookup(qbuf, FOLLOW_LINKS);
+ switch (res->status)
+ {
+ case NIS_SUCCESS:
+ break;
+
+ case NIS_TRYAGAIN:
+ case NIS_RPCERROR:
+ case NIS_NAMEUNREACHABLE:
+ if (retry_cnt++ > 4)
+ {
+ errno = EBADR;
+ return FALSE;
+ }
+ /* try not to overwhelm hosed server */
+ sleep(2);
+ break;
+
+ default: /* all other nisplus errors */
+#if 0
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("421 Cannot find table %s.%s: %s",
+ map->map_file, map->map_domain,
+ nis_sperrno(res->status));
+#endif
+ errno = EBADR;
+ return FALSE;
+ }
+ }
+
+ if (NIS_RES_NUMOBJ(res) != 1 ||
+ (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
+ {
+ if (tTd(38, 10))
+ printf("nisplus_map_open: %s is not a table\n", qbuf);
+#if 0
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("421 %s.%s: %s is not a table",
+ map->map_file, map->map_domain,
+ nis_sperrno(res->status));
+#endif
+ errno = EBADR;
+ return FALSE;
+ }
+ /* default key column is column 0 */
+ if (map->map_keycolnm == NULL)
+ map->map_keycolnm = newstr(COL_NAME(res,0));
+
+ max_col = COL_MAX(res);
+
+ /* verify the key column exist */
+ for (i=0; i< max_col; i++)
+ {
+ if (!strcmp(map->map_keycolnm, COL_NAME(res,i)))
+ break;
+ }
+ if (i == max_col)
+ {
+ if (tTd(38, 2))
+ printf("nisplus_map_open(%s): can not find key column %s\n",
+ map->map_file, map->map_keycolnm);
+ errno = EBADR;
+ return FALSE;
+ }
+
+ /* default value column is the last column */
+ if (map->map_valcolnm == NULL)
+ {
+ map->map_valcolno = max_col - 1;
+ return TRUE;
+ }
+
+ for (i=0; i< max_col; i++)
+ {
+ if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
+ {
+ map->map_valcolno = i;
+ return TRUE;
+ }
+ }
+
+ if (tTd(38, 2))
+ printf("nisplus_map_open(%s): can not find column %s\n",
+ map->map_file, map->map_keycolnm);
+ errno = EBADR;
+ return FALSE;
}
/*
-** NIS_MAP_CLOSE
+** NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
*/
-void
-nis_map_close(map)
+char *
+nisplus_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+ char *vp;
+ auto int vsize;
+ int buflen;
+ char search_key[MAXNAME + 1];
+ char qbuf[MAXLINE + NIS_MAXNAMELEN];
+ nis_result *result;
+
+ if (tTd(38, 20))
+ printf("nisplus_map_lookup(%s, %s)\n",
+ map->map_mname, name);
+
+ if (!bitset(MF_OPEN, map->map_mflags))
+ {
+ if (nisplus_map_open(map, O_RDONLY))
+ map->map_mflags |= MF_OPEN;
+ else
+ {
+ *statp = EX_UNAVAILABLE;
+ return NULL;
+ }
+ }
+
+ buflen = strlen(name);
+ if (buflen > sizeof search_key - 1)
+ buflen = sizeof search_key - 1;
+ bcopy(name, search_key, buflen + 1);
+ if (!bitset(MF_NOFOLDCASE, map->map_mflags))
+ makelower(search_key);
+
+ /* construct the query */
+ if (PARTIAL_NAME(map->map_file))
+ sprintf(qbuf, "[%s=%s],%s.%s", map->map_keycolnm,
+ search_key, map->map_file, map->map_domain);
+ else
+ sprintf(qbuf, "[%s=%s],%s", map->map_keycolnm,
+ search_key, map->map_file);
+
+ if (tTd(38, 20))
+ printf("qbuf=%s\n", qbuf);
+ result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+ if (result->status == NIS_SUCCESS)
+ {
+ int count;
+ char *str;
+
+ if ((count = NIS_RES_NUMOBJ(result)) != 1)
+ {
+ if (LogLevel > 10)
+ syslog(LOG_WARNING,
+ "%s: lookup error, expected 1 entry, got %d",
+ map->map_file, count);
+
+ /* ignore second entry */
+ if (tTd(38, 20))
+ printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
+ name, count);
+ }
+
+ vp = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
+ /* set the length of the result */
+ if (vp == NULL)
+ vp = "";
+ vsize = strlen(vp);
+ if (tTd(38, 20))
+ printf("nisplus_map_lookup(%s), found %s\n",
+ name, vp);
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ str = map_rewrite(map, name, strlen(name), NULL);
+ else
+ str = map_rewrite(map, vp, vsize, av);
+ nis_freeresult(result);
+ *statp = EX_OK;
+ return str;
+ }
+ else
+ {
+ if (result->status == NIS_NOTFOUND)
+ *statp = EX_NOTFOUND;
+ else if (result->status == NIS_TRYAGAIN)
+ *statp = EX_TEMPFAIL;
+ else
+ {
+ *statp = EX_UNAVAILABLE;
+ map->map_mflags &= ~(MF_VALID|MF_OPEN);
+ }
+ }
+ if (tTd(38, 20))
+ printf("nisplus_map_lookup(%s), failed\n", name);
+ nis_freeresult(result);
+ return NULL;
+}
+
+
+
+/*
+** NISPLUS_GETCANONNAME -- look up canonical name in NIS+
+*/
+
+bool
+nisplus_getcanonname(name, hbsize, statp)
+ char *name;
+ int hbsize;
+ int *statp;
+{
+ char *vp;
+ auto int vsize;
+ nis_result *result;
+ char *p;
+ char nbuf[MAXNAME + 1];
+ char qbuf[MAXLINE + NIS_MAXNAMELEN];
+
+ if (strlen(name) >= sizeof nbuf)
+ {
+ *statp = EX_UNAVAILABLE;
+ return FALSE;
+ }
+ (void) strcpy(nbuf, name);
+ shorten_hostname(nbuf);
+
+ p = strchr(nbuf, '.');
+ if (p == NULL)
+ {
+ /* single token */
+ sprintf(qbuf, "[name=%s],hosts.org_dir", nbuf);
+ }
+ else if (p[1] != '\0')
+ {
+ /* multi token -- take only first token in nbuf */
+ *p = '\0';
+ sprintf(qbuf, "[name=%s],hosts.org_dir.%s", nbuf, &p[1]);
+ }
+ else
+ {
+ *statp = EX_NOHOST;
+ return FALSE;
+ }
+
+ if (tTd(38, 20))
+ printf("\nnisplus_getcanoname(%s), qbuf=%s\n",
+ name, qbuf);
+
+ result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
+ NULL, NULL);
+
+ if (result->status == NIS_SUCCESS)
+ {
+ int count;
+ char *str;
+ char *domain;
+
+ if ((count = NIS_RES_NUMOBJ(result)) != 1)
+ {
+#ifdef LOG
+ if (LogLevel > 10)
+ syslog(LOG_WARNING,
+ "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
+ count);
+#endif
+
+ /* ignore second entry */
+ if (tTd(38, 20))
+ printf("nisplus_getcanoname(%s), got %d entries, addtional entries ignores\n", name);
+ }
+
+ if (tTd(38, 20))
+ printf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
+ name, (NIS_RES_OBJECT(result))->zo_domain);
+
+
+ vp = ((NIS_RES_OBJECT(result))->EN_col(0));
+ vsize = strlen(vp);
+ if (tTd(38, 20))
+ printf("nisplus_getcanonname(%s), found %s\n",
+ name, vp);
+ if (strchr(vp, '.') != NULL)
+ {
+ domain = "";
+ }
+ else
+ {
+ domain = macvalue('m', CurEnv);
+ if (domain == NULL)
+ domain = "";
+ }
+ if (hbsize > vsize + (int) strlen(domain) + 1)
+ {
+ if (domain[0] == '\0')
+ strcpy(name, vp);
+ else
+ sprintf(name, "%s.%s", vp, domain);
+ *statp = EX_OK;
+ }
+ else
+ *statp = EX_NOHOST;
+ nis_freeresult(result);
+ return TRUE;
+ }
+ else
+ {
+ if (result->status == NIS_NOTFOUND)
+ *statp = EX_NOHOST;
+ else if (result->status == NIS_TRYAGAIN)
+ *statp = EX_TEMPFAIL;
+ else
+ *statp = EX_UNAVAILABLE;
+ }
+ if (tTd(38, 20))
+ printf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
+ name, result->status, *statp);
+ nis_freeresult(result);
+ return FALSE;
+}
+
+
+char *
+nisplus_default_domain()
+{
+ static char default_domain[MAXNAME + 1] = "";
+ char *p;
+
+ if (default_domain[0] != '\0')
+ return(default_domain);
+
+ p = nis_local_directory();
+ strcpy(default_domain, p);
+ return default_domain;
+}
+
+#endif /* NISPLUS */
+ /*
+** HESIOD Modules
+*/
+
+#ifdef HESIOD
+
+#include <hesiod.h>
+
+bool
+hes_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ if (tTd(38, 2))
+ printf("hes_map_open(%s, %s, %d)\n",
+ map->map_mname, map->map_file, mode);
+
+ 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;
+ }
+
+ if (hes_error() == HES_ER_UNINIT)
+ hes_init();
+ switch (hes_error())
+ {
+ case HES_ER_OK:
+ case HES_ER_NOTFOUND:
+ return TRUE;
+ }
+
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("421 cannot initialize Hesiod map (%d)", hes_error());
+
+ return FALSE;
+}
+
+char *
+hes_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+ char **hp;
+
+ if (tTd(38, 20))
+ printf("hes_map_lookup(%s, %s)\n", map->map_file, name);
+
+ if (name[0] == '\\')
+ {
+ char *np;
+ int nl;
+ char nbuf[MAXNAME];
+
+ nl = strlen(name);
+ if (nl < sizeof nbuf - 1)
+ np = nbuf;
+ else
+ np = xalloc(strlen(name) + 2);
+ np[0] = '\\';
+ strcpy(&np[1], name);
+ hp = hes_resolve(np, map->map_file);
+ if (np != nbuf)
+ free(np);
+ }
+ else
+ {
+ hp = hes_resolve(name, map->map_file);
+ }
+ if (hp == NULL || hp[0] == NULL)
+ {
+ switch (hes_error())
+ {
+ case HES_ER_OK:
+ *statp = EX_OK;
+ break;
+
+ case HES_ER_NOTFOUND:
+ *statp = EX_NOTFOUND;
+ break;
+
+ case HES_ER_CONFIG:
+ *statp = EX_UNAVAILABLE;
+ break;
+
+ case HES_ER_NET:
+ *statp = EX_TEMPFAIL;
+ break;
+ }
+ return NULL;
+ }
+
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ return map_rewrite(map, name, strlen(name), NULL);
+ else
+ return map_rewrite(map, hp[0], strlen(hp[0]), av);
+}
+
+#endif
+ /*
+** NeXT NETINFO Modules
+*/
+
+#if NETINFO
+
+# define NETINFO_DEFAULT_DIR "/aliases"
+# define NETINFO_DEFAULT_PROPERTY "members"
+
+extern char *ni_propval __P((char *, char *, char *, char *, int));
+
+
+/*
+** NI_MAP_OPEN -- open NetInfo Aliases
+*/
+
+bool
+ni_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ char *p;
+
+ if (tTd(38, 20))
+ printf("ni_map_open(%s, %s, %d)\n",
+ map->map_mname, map->map_file, mode);
+
+ if (*map->map_file == '\0')
+ map->map_file = NETINFO_DEFAULT_DIR;
+
+ if (map->map_valcolnm == NULL)
+ map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
+
+ if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags))
+ map->map_coldelim = ',';
+
+ return TRUE;
+}
+
+
+/*
+** NI_MAP_LOOKUP -- look up a datum in NetInfo
+*/
+
+char *
+ni_map_lookup(map, name, av, statp)
MAP *map;
+ char *name;
+ char **av;
+ int *statp;
{
- /* nothing */
+ char *res;
+ char *propval;
+
+ if (tTd(38, 20))
+ printf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
+
+ propval = ni_propval(map->map_file, map->map_keycolnm, name,
+ map->map_valcolnm, map->map_coldelim);
+
+ if (propval == NULL)
+ return NULL;
+
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ res = map_rewrite(map, name, strlen(name), NULL);
+ else
+ res = map_rewrite(map, propval, strlen(propval), av);
+ free(propval);
+ return res;
}
-#endif /* NIS */
+
+bool
+ni_getcanonname(name, hbsize, statp)
+ char *name;
+ int hbsize;
+ int *statp;
+{
+ char *vptr;
+ char nbuf[MAXNAME + 1];
+
+ if (tTd(38, 20))
+ printf("ni_getcanonname(%s)\n", name);
+
+ if (strlen(name) >= sizeof nbuf)
+ {
+ *statp = EX_UNAVAILABLE;
+ return FALSE;
+ }
+ (void) strcpy(nbuf, name);
+ shorten_hostname(nbuf);
+
+ /* we only accept single token search key */
+ if (strchr(nbuf, '.'))
+ {
+ *statp = EX_NOHOST;
+ return FALSE;
+ }
+
+ /* Do the search */
+ vptr = ni_propval("/machines", NULL, nbuf, "name", '\0');
+
+ if (vptr == NULL)
+ {
+ *statp = EX_NOHOST;
+ return FALSE;
+ }
+
+ if (hbsize >= strlen(vptr))
+ {
+ strcpy(name, vptr);
+ *statp = EX_OK;
+ return TRUE;
+ }
+ *statp = EX_UNAVAILABLE;
+ free(vptr);
+ return FALSE;
+}
+
+
+/*
+** NI_PROPVAL -- NetInfo property value lookup routine
+**
+** Parameters:
+** keydir -- the NetInfo directory name in which to search
+** for the key.
+** keyprop -- the name of the property in which to find the
+** property we are interested. Defaults to "name".
+** keyval -- the value for which we are really searching.
+** valprop -- the property name for the value in which we
+** are interested.
+** sepchar -- if non-nil, this can be multiple-valued, and
+** we should return a string separated by this
+** character.
+**
+** Returns:
+** NULL -- if:
+** 1. the directory is not found
+** 2. the property name is not found
+** 3. the property contains multiple values
+** 4. some error occured
+** else -- the value of the lookup.
+**
+** Example:
+** To search for an alias value, use:
+** ni_propval("/aliases", "name", aliasname, "members", ',')
+**
+** Notes:
+** Caller should free the return value of ni_proval
+*/
+
+# include <netinfo/ni.h>
+
+# define LOCAL_NETINFO_DOMAIN "."
+# define PARENT_NETINFO_DOMAIN ".."
+# define MAX_NI_LEVELS 256
+
+char *
+ni_propval(keydir, keyprop, keyval, valprop, sepchar)
+ char *keydir;
+ char *keyprop;
+ char *keyval;
+ char *valprop;
+ int sepchar;
+{
+ char *propval = NULL;
+ int i;
+ int j, alen;
+ void *ni = NULL;
+ void *lastni = NULL;
+ ni_status nis;
+ ni_id nid;
+ ni_namelist ninl;
+ register char *p;
+ char keybuf[1024];
+
+ /*
+ ** Create the full key from the two parts.
+ **
+ ** Note that directory can end with, e.g., "name=" to specify
+ ** an alternate search property.
+ */
+
+ i = strlen(keydir) + strlen(keyval) + 2;
+ if (keyprop != NULL)
+ i += strlen(keyprop) + 1;
+ if (i > sizeof keybuf)
+ return NULL;
+ strcpy(keybuf, keydir);
+ strcat(keybuf, "/");
+ if (keyprop != NULL)
+ {
+ strcat(keybuf, keyprop);
+ strcat(keybuf, "=");
+ }
+ strcat(keybuf, keyval);
+
+ /*
+ ** If the passed directory and property name are found
+ ** in one of netinfo domains we need to search (starting
+ ** from the local domain moving all the way back to the
+ ** root domain) set propval to the property's value
+ ** and return it.
+ */
+
+ for (i = 0; i < MAX_NI_LEVELS; ++i)
+ {
+ if (i == 0)
+ {
+ nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
+ }
+ else
+ {
+ if (lastni != NULL)
+ ni_free(lastni);
+ lastni = ni;
+ nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
+ }
+
+ /*
+ ** Don't bother if we didn't get a handle on a
+ ** proper domain. This is not necessarily an error.
+ ** We would get a positive ni_status if, for instance
+ ** we never found the directory or property and tried
+ ** to open the parent of the root domain!
+ */
+
+ if (nis != 0)
+ break;
+
+ /*
+ ** Find the path to the server information.
+ */
+
+ if (ni_pathsearch(ni, &nid, keybuf) != 0)
+ continue;
+
+ /*
+ ** Find associated value information.
+ */
+
+ if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
+ continue;
+
+ /*
+ ** See if we have an acceptable number of values.
+ */
+
+ if (ninl.ni_namelist_len <= 0)
+ continue;
+
+ if (sepchar == '\0' && ninl.ni_namelist_len > 1)
+ {
+ ni_namelist_free(&ninl);
+ continue;
+ }
+
+ /*
+ ** Calculate number of bytes needed and build result
+ */
+
+ alen = 1;
+ for (j = 0; j < ninl.ni_namelist_len; j++)
+ alen += strlen(ninl.ni_namelist_val[j]) + 1;
+ propval = p = xalloc(alen);
+ for (j = 0; j < ninl.ni_namelist_len; j++)
+ {
+ strcpy(p, ninl.ni_namelist_val[j]);
+ p += strlen(p);
+ *p++ = sepchar;
+ }
+ *--p = '\0';
+
+ ni_namelist_free(&ninl);
+ }
+
+ /*
+ ** Clean up.
+ */
+
+ if (ni != NULL)
+ ni_free(ni);
+ if (lastni != NULL && ni != lastni)
+ ni_free(lastni);
+
+ return propval;
+}
+
+#endif
+ /*
+** TEXT (unindexed text file) Modules
+**
+** This code donated by Sun Microsystems.
+*/
+
+
+/*
+** TEXT_MAP_OPEN -- open text table
+*/
+
+bool
+text_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ struct stat sbuf;
+
+ if (tTd(38, 2))
+ printf("text_map_open(%s, %s, %d)\n",
+ map->map_mname, map->map_file, mode);
+
+ if (mode != O_RDONLY)
+ {
+ errno = ENODEV;
+ return FALSE;
+ }
+
+ if (*map->map_file == '\0')
+ {
+ if (tTd(38, 2))
+ printf("text_map_open(%s): file name required\n",
+ map->map_mname);
+ return FALSE;
+ }
+
+ if (map->map_file[0] != '/')
+ {
+ if (tTd(38, 2))
+ printf("text_map_open(%s, %s): file name must be fully qualified\n",
+ map->map_mname, map->map_file);
+ return FALSE;
+ }
+ /* check to see if this map actually accessable */
+ if (access(map->map_file, R_OK) <0)
+ return FALSE;
+
+ /* check to see if this map actually exist */
+ if (stat(map->map_file, &sbuf) <0)
+ {
+ if (tTd(38, 2))
+ printf("text_map_open(%s, %s): cannot stat\n",
+ map->map_mname, map->map_file);
+ return FALSE;
+ }
+
+ if (!S_ISREG(sbuf.st_mode))
+ {
+ if (tTd(38, 2))
+ printf("text_map_open(%s): %s is not a regular file\n",
+ map->map_mname, map->map_file);
+ return FALSE;
+ }
+
+ if (map->map_keycolnm == NULL)
+ map->map_keycolno = 0;
+ else
+ {
+ if (!isdigit(*map->map_keycolnm))
+ {
+ if (tTd(38, 2))
+ printf("text_map_open(%s, %s): -k should specify a number, not %s\n",
+ map->map_mname, map->map_file,
+ map->map_keycolnm);
+ return FALSE;
+ }
+ map->map_keycolno = atoi(map->map_keycolnm);
+ }
+
+ if (map->map_valcolnm == NULL)
+ map->map_valcolno = 0;
+ else
+ {
+ if (!isdigit(*map->map_valcolnm))
+ {
+ if (tTd(38, 2))
+ printf("text_map_open(%s, %s): -v should specify a number, not %s\n",
+ map->map_mname, map->map_file,
+ map->map_valcolnm);
+ return FALSE;
+ }
+ map->map_valcolno = atoi(map->map_valcolnm);
+ }
+
+ if (tTd(38, 2))
+ {
+ printf("text_map_open(%s, %s): delimiter = ",
+ map->map_mname, map->map_file);
+ if (map->map_coldelim == '\0')
+ printf("(white space)\n");
+ else
+ printf("%c\n", map->map_coldelim);
+ }
+
+ return TRUE;
+}
+
+
+/*
+** TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
+*/
+
+char *
+text_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+ char *vp;
+ auto int vsize;
+ int buflen;
+ char search_key[MAXNAME + 1];
+ char linebuf[MAXLINE];
+ FILE *f;
+ char buf[MAXNAME + 1];
+ char delim;
+ int key_idx;
+ bool found_it;
+ extern char *get_column();
+
+
+ found_it = FALSE;
+ if (tTd(38, 20))
+ printf("text_map_lookup(%s, %s)\n", map->map_mname, name);
+
+ buflen = strlen(name);
+ if (buflen > sizeof search_key - 1)
+ buflen = sizeof search_key - 1;
+ bcopy(name, search_key, buflen + 1);
+ if (!bitset(MF_NOFOLDCASE, map->map_mflags))
+ makelower(search_key);
+
+ f = fopen(map->map_file, "r");
+ if (f == NULL)
+ {
+ map->map_mflags &= ~(MF_VALID|MF_OPEN);
+ *statp = EX_UNAVAILABLE;
+ return NULL;
+ }
+ key_idx = map->map_keycolno;
+ delim = map->map_coldelim;
+ while (fgets(linebuf, MAXLINE, f) != NULL)
+ {
+ char *p;
+
+ /* skip comment line */
+ if (linebuf[0] == '#')
+ continue;
+ p = strchr(linebuf, '\n');
+ if (p != NULL)
+ *p = '\0';
+ p = get_column(linebuf, key_idx, delim, buf);
+ if (p != NULL && strcasecmp(search_key, p) == 0)
+ {
+ found_it = TRUE;
+ break;
+ }
+ }
+ fclose(f);
+ if (!found_it)
+ {
+ *statp = EX_NOTFOUND;
+ return NULL;
+ }
+ vp = get_column(linebuf, map->map_valcolno, delim, buf);
+ vsize = strlen(vp);
+ *statp = EX_OK;
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ return map_rewrite(map, name, strlen(name), NULL);
+ else
+ return map_rewrite(map, vp, vsize, av);
+}
+
+
+/*
+** TEXT_GETCANONNAME -- look up canonical name in hosts file
+*/
+
+bool
+text_getcanonname(name, hbsize, statp)
+ char *name;
+ int hbsize;
+ int *statp;
+{
+ int key_idx;
+ bool found;
+ FILE *f;
+ char linebuf[MAXLINE];
+ char cbuf[MAXNAME + 1];
+ char fbuf[MAXNAME + 1];
+ char nbuf[MAXNAME + 1];
+ extern char *get_column();
+
+ if (tTd(38, 20))
+ printf("text_getcanonname(%s)\n", name);
+
+ if (strlen(name) >= sizeof nbuf)
+ {
+ *statp = EX_UNAVAILABLE;
+ return FALSE;
+ }
+ (void) strcpy(nbuf, name);
+ shorten_hostname(nbuf);
+
+ f = fopen(HostsFile, "r");
+ if (f == NULL)
+ {
+ *statp = EX_UNAVAILABLE;
+ return FALSE;
+ }
+ found = FALSE;
+ while (!found && fgets(linebuf, MAXLINE, f) != NULL)
+ {
+ char *p = strpbrk(linebuf, "#\n");
+
+ if (p != NULL)
+ *p = '\0';
+ if (linebuf[0] != '\0')
+ found = extract_canonname(nbuf, linebuf, cbuf);
+ }
+ fclose(f);
+ if (!found)
+ {
+ *statp = EX_NOHOST;
+ return FALSE;
+ }
+
+ if (hbsize >= strlen(cbuf))
+ {
+ strcpy(name, cbuf);
+ *statp = EX_OK;
+ return TRUE;
+ }
+ *statp = EX_UNAVAILABLE;
+ return FALSE;
+}
/*
** STAB (Symbol Table) Modules
*/
@@ -1090,7 +2587,8 @@ stab_map_lookup(map, name, av, pstat)
register STAB *s;
if (tTd(38, 20))
- printf("stab_lookup(%s)\n", name);
+ printf("stab_lookup(%s, %s)\n",
+ map->map_mname, name);
s = stab(name, ST_ALIAS, ST_FIND);
if (s != NULL)
@@ -1134,7 +2632,8 @@ stab_map_open(map, mode)
struct stat st;
if (tTd(38, 2))
- printf("stab_map_open(%s)\n", map->map_file);
+ printf("stab_map_open(%s, %s, %d)\n",
+ map->map_mname, map->map_file, mode);
if (mode != O_RDONLY)
{
@@ -1145,7 +2644,7 @@ stab_map_open(map, mode)
af = fopen(map->map_file, "r");
if (af == NULL)
return FALSE;
- readaliases(map, af, TRUE);
+ readaliases(map, af, FALSE, FALSE);
if (fstat(fileno(af), &st) >= 0)
map->map_mtime = st.st_mtime;
@@ -1153,20 +2652,6 @@ stab_map_open(map, mode)
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
**
@@ -1186,7 +2671,8 @@ impl_map_lookup(map, name, av, pstat)
int *pstat;
{
if (tTd(38, 20))
- printf("impl_map_lookup(%s)\n", name);
+ printf("impl_map_lookup(%s, %s)\n",
+ map->map_mname, name);
#ifdef NEWDB
if (bitset(MF_IMPL_HASH, map->map_mflags))
@@ -1209,6 +2695,9 @@ impl_map_store(map, lhs, rhs)
char *lhs;
char *rhs;
{
+ if (tTd(38, 12))
+ printf("impl_map_store(%s, %s, %s)\n",
+ map->map_mname, lhs, rhs);
#ifdef NEWDB
if (bitset(MF_IMPL_HASH, map->map_mflags))
db_map_store(map, lhs, rhs);
@@ -1229,25 +2718,16 @@ 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;
- }
+ printf("impl_map_open(%s, %s, %d)\n",
+ map->map_mname, map->map_file, mode);
#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)
+ if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
#endif
return TRUE;
}
@@ -1284,6 +2764,9 @@ void
impl_map_close(map)
MAP *map;
{
+ if (tTd(38, 9))
+ printf("impl_map_close(%s, %s, %x)\n",
+ map->map_mname, map->map_file, map->map_mflags);
#ifdef NEWDB
if (bitset(MF_IMPL_HASH, map->map_mflags))
{
@@ -1301,6 +2784,490 @@ impl_map_close(map)
#endif
}
/*
+** User map class.
+**
+** Provides access to the system password file.
+*/
+
+/*
+** USER_MAP_OPEN -- open user map
+**
+** Really just binds field names to field numbers.
+*/
+
+bool
+user_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ if (tTd(38, 2))
+ printf("user_map_open(%s, %d)\n",
+ map->map_mname, mode);
+
+ 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;
+ }
+ if (map->map_valcolnm == NULL)
+ /* nothing */ ;
+ else if (strcasecmp(map->map_valcolnm, "name") == 0)
+ map->map_valcolno = 1;
+ else if (strcasecmp(map->map_valcolnm, "passwd") == 0)
+ map->map_valcolno = 2;
+ else if (strcasecmp(map->map_valcolnm, "uid") == 0)
+ map->map_valcolno = 3;
+ else if (strcasecmp(map->map_valcolnm, "gid") == 0)
+ map->map_valcolno = 4;
+ else if (strcasecmp(map->map_valcolnm, "gecos") == 0)
+ map->map_valcolno = 5;
+ else if (strcasecmp(map->map_valcolnm, "dir") == 0)
+ map->map_valcolno = 6;
+ else if (strcasecmp(map->map_valcolnm, "shell") == 0)
+ map->map_valcolno = 7;
+ else
+ {
+ syserr("User map %s: unknown column name %s",
+ map->map_mname, map->map_valcolnm);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/*
+** USER_MAP_LOOKUP -- look up a user in the passwd file.
+*/
+
+char *
+user_map_lookup(map, key, av, statp)
+ MAP *map;
+ char *key;
+ char **av;
+ int *statp;
+{
+ struct passwd *pw;
+
+ if (tTd(38, 20))
+ printf("user_map_lookup(%s, %s)\n",
+ map->map_mname, key);
+
+ pw = sm_getpwnam(key);
+ if (pw == NULL)
+ return NULL;
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ return map_rewrite(map, key, strlen(key), NULL);
+ else
+ {
+ char *rwval = NULL;
+ char buf[30];
+
+ switch (map->map_valcolno)
+ {
+ case 0:
+ case 1:
+ rwval = pw->pw_name;
+ break;
+
+ case 2:
+ rwval = pw->pw_passwd;
+ break;
+
+ case 3:
+ sprintf(buf, "%d", pw->pw_uid);
+ rwval = buf;
+ break;
+
+ case 4:
+ sprintf(buf, "%d", pw->pw_gid);
+ rwval = buf;
+ break;
+
+ case 5:
+ rwval = pw->pw_gecos;
+ break;
+
+ case 6:
+ rwval = pw->pw_dir;
+ break;
+
+ case 7:
+ rwval = pw->pw_shell;
+ break;
+ }
+ return map_rewrite(map, rwval, strlen(rwval), av);
+ }
+}
+ /*
+** Program map type.
+**
+** This provides access to arbitrary programs. It should be used
+** only very sparingly, since there is no way to bound the cost
+** of invoking an arbitrary program.
+*/
+
+char *
+prog_map_lookup(map, name, av, statp)
+ MAP *map;
+ char *name;
+ char **av;
+ int *statp;
+{
+ int i;
+ register char *p;
+ int fd;
+ auto pid_t pid;
+ char *rval;
+ int stat;
+ char *argv[MAXPV + 1];
+ char buf[MAXLINE];
+
+ if (tTd(38, 20))
+ printf("prog_map_lookup(%s, %s) %s\n",
+ map->map_mname, name, map->map_file);
+
+ i = 0;
+ argv[i++] = map->map_file;
+ if (map->map_rebuild != NULL)
+ {
+ strcpy(buf, map->map_rebuild);
+ for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
+ {
+ if (i >= MAXPV - 1)
+ break;
+ argv[i++] = p;
+ }
+ }
+ argv[i++] = name;
+ argv[i] = NULL;
+ if (tTd(38, 21))
+ {
+ printf("prog_open:");
+ for (i = 0; argv[i] != NULL; i++)
+ printf(" %s", argv[i]);
+ printf("\n");
+ }
+ pid = prog_open(argv, &fd, CurEnv);
+ if (pid < 0)
+ {
+ if (!bitset(MF_OPTIONAL, map->map_mflags))
+ syserr("prog_map_lookup(%s) failed (%s) -- closing",
+ map->map_mname, errstring(errno));
+ else if (tTd(38, 9))
+ printf("prog_map_lookup(%s) failed (%s) -- closing",
+ map->map_mname, errstring(errno));
+ map->map_mflags &= ~(MF_VALID|MF_OPEN);
+ *statp = EX_OSFILE;
+ return NULL;
+ }
+ i = read(fd, buf, sizeof buf - 1);
+ if (i < 0)
+ {
+ syserr("prog_map_lookup(%s): read error %s\n",
+ map->map_mname, errstring(errno));
+ rval = NULL;
+ }
+ else if (i == 0 && tTd(38, 20))
+ {
+ printf("prog_map_lookup(%s): empty answer\n",
+ map->map_mname);
+ rval = NULL;
+ }
+ if (i > 0)
+ {
+ buf[i] = '\0';
+ p = strchr(buf, '\n');
+ if (p != NULL)
+ *p = '\0';
+
+ /* collect the return value */
+ if (bitset(MF_MATCHONLY, map->map_mflags))
+ rval = map_rewrite(map, name, strlen(name), NULL);
+ else
+ rval = map_rewrite(map, buf, strlen(buf), NULL);
+
+ /* now flush any additional output */
+ while ((i = read(fd, buf, sizeof buf)) > 0)
+ continue;
+ }
+
+ /* wait for the process to terminate */
+ close(fd);
+ stat = waitfor(pid);
+
+ if (stat == -1)
+ {
+ syserr("prog_map_lookup(%s): wait error %s\n",
+ map->map_mname, errstring(errno));
+ *statp = EX_SOFTWARE;
+ rval = NULL;
+ }
+ else if (WIFEXITED(stat))
+ {
+ if ((*statp = WEXITSTATUS(stat)) != EX_OK)
+ rval = NULL;
+ }
+ else
+ {
+ syserr("prog_map_lookup(%s): child died on signal %d",
+ map->map_mname, stat);
+ *statp = EX_UNAVAILABLE;
+ rval = NULL;
+ }
+ return rval;
+}
+ /*
+** Sequenced map type.
+**
+** Tries each map in order until something matches, much like
+** implicit. Stores go to the first map in the list that can
+** support storing.
+**
+** This is slightly unusual in that there are two interfaces.
+** The "sequence" interface lets you stack maps arbitrarily.
+** The "switch" interface builds a sequence map by looking
+** at a system-dependent configuration file such as
+** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
+**
+** We don't need an explicit open, since all maps are
+** opened during startup, including underlying maps.
+*/
+
+/*
+** SEQ_MAP_PARSE -- Sequenced map parsing
+*/
+
+bool
+seq_map_parse(map, ap)
+ MAP *map;
+ char *ap;
+{
+ int maxmap;
+
+ if (tTd(38, 2))
+ printf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
+ maxmap = 0;
+ while (*ap != '\0')
+ {
+ register char *p;
+ STAB *s;
+
+ /* find beginning of map name */
+ while (isascii(*ap) && isspace(*ap))
+ ap++;
+ for (p = ap; isascii(*p) && isalnum(*p); p++)
+ continue;
+ if (*p != '\0')
+ *p++ = '\0';
+ while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
+ p++;
+ if (*ap == '\0')
+ {
+ ap = p;
+ continue;
+ }
+ s = stab(ap, ST_MAP, ST_FIND);
+ if (s == NULL)
+ {
+ syserr("Sequence map %s: unknown member map %s",
+ map->map_mname, ap);
+ }
+ else if (maxmap == MAXMAPSTACK)
+ {
+ syserr("Sequence map %s: too many member maps (%d max)",
+ map->map_mname, MAXMAPSTACK);
+ maxmap++;
+ }
+ else if (maxmap < MAXMAPSTACK)
+ {
+ map->map_stack[maxmap++] = &s->s_map;
+ }
+ ap = p;
+ }
+ return TRUE;
+}
+
+
+/*
+** SWITCH_MAP_OPEN -- open a switched map
+**
+** This looks at the system-dependent configuration and builds
+** a sequence map that does the same thing.
+**
+** Every system must define a switch_map_find routine in conf.c
+** that will return the list of service types associated with a
+** given service class.
+*/
+
+bool
+switch_map_open(map, mode)
+ MAP *map;
+ int mode;
+{
+ int mapno;
+ int nmaps;
+ char *maptype[MAXMAPSTACK];
+
+ if (tTd(38, 2))
+ printf("switch_map_open(%s, %s, %d)\n",
+ map->map_mname, map->map_file, mode);
+
+ nmaps = switch_map_find(map->map_file, maptype, map->map_return);
+ if (tTd(38, 19))
+ {
+ printf("\tswitch_map_find => %d\n", nmaps);
+ for (mapno = 0; mapno < nmaps; mapno++)
+ printf("\t\t%s\n", maptype[mapno]);
+ }
+ if (nmaps <= 0 || nmaps > MAXMAPSTACK)
+ return FALSE;
+
+ for (mapno = 0; mapno < nmaps; mapno++)
+ {
+ register STAB *s;
+ char nbuf[MAXNAME + 1];
+
+ if (maptype[mapno] == NULL)
+ continue;
+ (void) sprintf(nbuf, "%s.%s", map->map_mname, maptype[mapno]);
+ s = stab(nbuf, ST_MAP, ST_FIND);
+ if (s == NULL)
+ {
+ syserr("Switch map %s: unknown member map %s",
+ map->map_mname, nbuf);
+ }
+ else
+ {
+ map->map_stack[mapno] = &s->s_map;
+ if (tTd(38, 4))
+ printf("\tmap_stack[%d] = %s:%s\n",
+ mapno, s->s_map.map_class->map_cname,
+ nbuf);
+ }
+ }
+ return TRUE;
+}
+
+
+/*
+** SEQ_MAP_CLOSE -- close all underlying maps
+*/
+
+void
+seq_map_close(map)
+ MAP *map;
+{
+ int mapno;
+
+ if (tTd(38, 9))
+ printf("seq_map_close(%s)\n", map->map_mname);
+
+ for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
+ {
+ MAP *mm = map->map_stack[mapno];
+
+ if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
+ continue;
+ mm->map_class->map_close(mm);
+ mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
+ }
+}
+
+
+/*
+** SEQ_MAP_LOOKUP -- sequenced map lookup
+*/
+
+char *
+seq_map_lookup(map, key, args, pstat)
+ MAP *map;
+ char *key;
+ char **args;
+ int *pstat;
+{
+ int mapno;
+ int mapbit = 0x01;
+ bool tempfail = FALSE;
+
+ if (tTd(38, 20))
+ printf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
+
+ for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
+ {
+ MAP *mm = map->map_stack[mapno];
+ char *rv;
+
+ if (mm == NULL)
+ continue;
+ if (!bitset(MF_OPEN, mm->map_mflags))
+ {
+ if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
+ {
+ *pstat = EX_UNAVAILABLE;
+ return NULL;
+ }
+ continue;
+ }
+ *pstat = EX_OK;
+ rv = mm->map_class->map_lookup(mm, key, args, pstat);
+ if (rv != NULL)
+ return rv;
+ if (*pstat == EX_TEMPFAIL)
+ {
+ if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
+ return NULL;
+ tempfail = TRUE;
+ }
+ else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
+ break;
+ }
+ if (tempfail)
+ *pstat = EX_TEMPFAIL;
+ else if (*pstat == EX_OK)
+ *pstat = EX_NOTFOUND;
+ return NULL;
+}
+
+
+/*
+** SEQ_MAP_STORE -- sequenced map store
+*/
+
+void
+seq_map_store(map, key, val)
+ MAP *map;
+ char *key;
+ char *val;
+{
+ int mapno;
+
+ if (tTd(38, 12))
+ printf("seq_map_store(%s, %s, %s)\n",
+ map->map_mname, key, val);
+
+ for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
+ {
+ MAP *mm = map->map_stack[mapno];
+
+ if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
+ continue;
+
+ mm->map_class->map_store(mm, key, val);
+ return;
+ }
+ syserr("seq_map_store(%s, %s, %s): no writable map",
+ map->map_mname, key, val);
+}
+ /*
** NULL stubs
*/
@@ -1319,6 +3286,17 @@ null_map_close(map)
return;
}
+char *
+null_map_lookup(map, key, args, pstat)
+ MAP *map;
+ char *key;
+ char **args;
+ int *pstat;
+{
+ *pstat = EX_NOTFOUND;
+ return NULL;
+}
+
void
null_map_store(map, key, val)
MAP *map;
@@ -1327,3 +3305,26 @@ null_map_store(map, key, val)
{
return;
}
+
+
+/*
+** BOGUS stubs
+*/
+
+char *
+bogus_map_lookup(map, key, args, pstat)
+ MAP *map;
+ char *key;
+ char **args;
+ int *pstat;
+{
+ *pstat = EX_TEMPFAIL;
+ return NULL;
+}
+
+MAPCLASS BogusMapClass =
+{
+ "bogus-map", NULL, 0,
+ NULL, bogus_map_lookup, null_map_store,
+ null_map_open, null_map_close,
+};