From 03f996bd8a0d6391518979cdab3dbe38cba0bf83 Mon Sep 17 00:00:00 2001
From: mdw <mdw>
Date: Mon, 4 Aug 1997 10:24:26 +0000
Subject: [PATCH] Sources placed under CVS control.

---
 acconfig.h          |   4 +-
 aclocal.m4          |   4 +-
 configure.in        |  58 ++++---
 manual/become.tex   |   9 +-
 mkinstalldirs       |   2 +-
 src/Makefile.am     |   4 +-
 src/become.c        | 401 ++++++++++++++++++++++++++++++++++++++--------
 src/blowfish-sbox.h |   7 +-
 src/blowfish.c      |   7 +-
 src/blowfish.h      |   7 +-
 src/check.c         | 450 ++++++++++++++++++++++++++++++++++++++++------------
 src/check.h         |  13 +-
 src/class.c         | 105 ++++++------
 src/class.h         |  16 +-
 src/crypt.c         | 276 ++++++++++++--------------------
 src/crypt.h         |  24 +--
 src/daemon.c        |  56 +++++--
 src/daemon.h        |  13 +-
 src/dbutils.h       |   7 +-
 src/icrypt.c        |  18 ++-
 src/icrypt.h        |  13 +-
 src/idea.c          |  14 +-
 src/idea.h          |  13 +-
 src/keygen.c        |  19 ++-
 src/lexer.h         |  13 +-
 src/lexer.l         |  13 +-
 src/md5.c           |  13 +-
 src/md5.h           |  13 +-
 src/mdwopt.c        |  17 +-
 src/mdwopt.h        |  15 +-
 src/name.c          | 162 ++++++++++++-------
 src/name.h          |  17 +-
 src/parser.h        |  13 +-
 src/parser.y        |  13 +-
 src/rule.c          |  91 +++++++++--
 src/rule.h          |  24 ++-
 src/set.c           |  13 +-
 src/set.h           |  13 +-
 src/sym.c           |  34 +++-
 src/sym.h           |  13 +-
 src/tx.c            |  13 +-
 src/tx.h            |  13 +-
 src/userdb.c        | 310 ++++++++++++++++++++----------------
 src/userdb.h        |  11 +-
 src/utils.c         | 144 ++++++++++++++++-
 src/utils.h         | 106 ++++++++++++-
 46 files changed, 1783 insertions(+), 831 deletions(-)

diff --git a/acconfig.h b/acconfig.h
index d108f96..6cb2ced 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: acconfig.h,v 1.1 1997/08/04 10:22:09 mdw Exp $
+ * $Id: acconfig.h,v 1.2 1997/08/04 10:24:19 mdw Exp $
  *
  * Default settings for `become' config.h
  *
@@ -29,7 +29,7 @@
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: acconfig.h,v $
- * Revision 1.1  1997/08/04 10:22:09  mdw
+ * Revision 1.2  1997/08/04 10:24:19  mdw
  * Sources placed under CVS control.
  *
  * Revision 1.1  1997/07/21  13:47:52  mdw
diff --git a/aclocal.m4 b/aclocal.m4
index 16a9ca8..ae47bf2 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -1,6 +1,6 @@
 dnl -*-fundamental-*-
 dnl
-dnl $Id: aclocal.m4,v 1.1 1997/08/04 10:22:10 mdw Exp $
+dnl $Id: aclocal.m4,v 1.2 1997/08/04 10:24:19 mdw Exp $
 dnl
 dnl Configuration macros for `become'
 dnl
@@ -28,7 +28,7 @@ dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 dnl----- Revision history ---------------------------------------------------
 dnl
 dnl $Log: aclocal.m4,v $
-dnl Revision 1.1  1997/08/04 10:22:10  mdw
+dnl Revision 1.2  1997/08/04 10:24:19  mdw
 dnl Sources placed under CVS control.
 dnl
 
diff --git a/configure.in b/configure.in
index 7dc5995..9bbf801 100644
--- a/configure.in
+++ b/configure.in
@@ -1,13 +1,13 @@
 dnl -*-fundamental-*-
 dnl
-dnl $Id: configure.in,v 1.1 1997/07/21 13:47:51 mdw Exp $
+dnl $Id: configure.in,v 1.2 1997/08/04 10:24:21 mdw Exp $
 dnl
 dnl Source for auto configuration for `become'
 dnl
 dnl (c) 1997 Mark Wooding
 dnl
 
-dnl----- Licencing notice ---------------------------------------------------
+dnl----- Licensing notice ---------------------------------------------------
 dnl 
 dnl This file is part of `become'
 dnl 
@@ -22,20 +22,25 @@ dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 dnl GNU General Public License for more details.
 dnl 
 dnl You should have received a copy of the GNU General Public License
-dnl along with `become'; if not, write to the Free Software
-dnl Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+dnl along with `become'; if not, write to the Free Software Foundation,
+dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 dnl----- Revision history ---------------------------------------------------
 dnl
 dnl $Log: configure.in,v $
-dnl Revision 1.1  1997/07/21 13:47:51  mdw
-dnl Initial revision
+dnl Revision 1.2  1997/08/04 10:24:21  mdw
+dnl Sources placed under CVS control.
 dnl
+# Revision 1.1  1997/07/21  13:47:51  mdw
+# Initial revision
+#
 
 AC_INIT(icrypt.c)
 AC_CONFIG_HEADER(config.h)
-VERSION=1.1 AC_SUBST(VERSION)
-AC_DEFINE(VERSION, "1.1 (22 February 1997)")
+PACKAGE=become VERSION=1.2-pre
+AC_SUBST(PACKAGE)
+AC_SUBST(VERSION)
+AC_DEFINE(VERSION, "1.2-pre (24 July 1997)")
 
 dnl --- Check for compilers and things ---
 
@@ -45,54 +50,59 @@ AC_PROG_LEX
 AC_CHECK_PROG(AR, ar, ar)
 AC_PROG_RANLIB
 AC_PROG_YACC
+AC_ARG_PROGRAM
 if test "$ac_cv_prog_gcc" = "yes"; then
   CFLAGS="$CFLAGS -pedantic -Wall"
 fi
 
 dnl --- Libraries ---
 
-AC_CHECK_LIB(socket, socket)
-MDW_LIB_RESOLVER
+MDW_CHECK_MANYLIBS(socket, socket,,
+  AC_MSG_ERROR([Socket library not found]))
+
+MDW_CHECK_MANYLIBS(gethostbyname, resolv nsl,,
+  AC_MSG_ERROR([Resolver library not found]))
+
+MDW_CHECK_MANYLIBS(yp_all, nsl, AC_DEFINE(HAVE_YP))
 
 dnl --- Types ---
 
 AC_TYPE_PID_T
 AC_TYPE_UID_T
-
-dnl --- Check on endianness ---
-
-AC_C_BIGENDIAN(yes)
+AC_CHECK_TYPE(ssize_t, int)
 
 dnl --- Check on type sizes ---
 
-AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(int, 2)
 
 dnl --- Set the path separator ---
 
 AC_DEFINE(PATHSEP, '/')
 
+dnl --- Check for some useful functions ---
+
+AC_CHECK_FUNCS(getrusage vtimes)
+
 dnl --- Debugging stuff ---
 
 AC_ARG_ENABLE(debugging,
-  [--enable-debugging	  spews vast swathes of useless information],
+[  --enable-debugging	  spews vast swathes of useless information],
   [if test "$enableval" = "no"; then
     AC_DEFINE(NDEBUG, 1)
   fi],
   AC_DEFINE(NDEBUG, 1))
 
-dnl --- Yell^H^H^H^HNetwork Information System ---
-
-AC_ARG_ENABLE(yp,
-  [--enable-yp		  read user names using ypcat],
-  [if test "$enableval" != "no"; then
-    AC_DEFINE(HAVE_YP, 1)
+AC_ARG_ENABLE(tracing,
+[  --enable-tracing	  enable output of tracing information],
+  [if test "$enableval" = "yes"; then
+    AC_DEFINE(TRACING)
   fi],
-  MDW_CHECK_YP)
+  AC_DEFINE(TRACING))
 
 dnl --- Define where things get put ---
 
 mdw_save_prefix="$prefix"
-test "x$prefix" = "xNONE" && prefix="$ac_default_prefix"
+test "$prefix" = "NONE" && prefix="$ac_default_prefix"
 AC_DEFINE_UNQUOTED(ETCDIR, "`eval echo ${sysconfdir}`")
 prefix="$mdw_save_prefix"
 
diff --git a/manual/become.tex b/manual/become.tex
index b3cc061..16785b5 100644
--- a/manual/become.tex
+++ b/manual/become.tex
@@ -1,6 +1,6 @@
 %%% -*-LaTeX-*-
 %%%
-%%% $Id: become.tex,v 1.1 1997/07/21 13:47:54 mdw Exp $
+%%% $Id: become.tex,v 1.2 1997/08/04 10:24:20 mdw Exp $
 %%%
 %%% Documentation for `become'
 %%%
@@ -28,9 +28,12 @@
 %%%----- Revision history ---------------------------------------------------
 %%%
 %%% $Log: become.tex,v $
-%%% Revision 1.1  1997/07/21 13:47:54  mdw
-%%% Initial revision
+%%% Revision 1.2  1997/08/04 10:24:20  mdw
+%%% Sources placed under CVS control.
 %%%
+% Revision 1.1  1997/07/21  13:47:54  mdw
+% Initial revision
+%
 
 %%%----- Document preamble --------------------------------------------------
 
diff --git a/mkinstalldirs b/mkinstalldirs
index d41f6c0..57a53d5 100755
--- a/mkinstalldirs
+++ b/mkinstalldirs
@@ -4,7 +4,7 @@
 # Created: 1993-05-16
 # Public domain
 
-# $Id: mkinstalldirs,v 1.1 1997/08/04 10:22:10 mdw Exp $
+# $Id: mkinstalldirs,v 1.2 1997/08/04 10:24:24 mdw Exp $
 
 errstatus=0
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 88434ec..af41625 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,7 @@
 ## Process this file with `automake' to generate `Makefile.in'
 ## -*-makefile-*-
 ##
-## $Id: Makefile.am,v 1.1 1997/08/04 10:22:09 mdw Exp $
+## $Id: Makefile.am,v 1.2 1997/08/04 10:24:19 mdw Exp $
 ##
 ## Makefile for `become'
 ##
@@ -29,7 +29,7 @@
 ##----- Revision history ----------------------------------------------------
 ##
 ## $Log: Makefile.am,v $
-## Revision 1.1  1997/08/04 10:22:09  mdw
+## Revision 1.2  1997/08/04 10:24:19  mdw
 ## Sources placed under CVS control.
 ##
 
diff --git a/src/become.c b/src/become.c
index c2d8bcf..627eda5 100644
--- a/src/become.c
+++ b/src/become.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: become.c,v 1.1 1997/07/21 13:47:54 mdw Exp $
+ * $Id: become.c,v 1.2 1997/08/04 10:24:20 mdw Exp $
  *
  * Main code for `become'
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: become.c,v $
- * Revision 1.1  1997/07/21 13:47:54  mdw
+ * Revision 1.2  1997/08/04 10:24:20  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:54  mdw
  * Initial revision
  *
  */
@@ -43,6 +46,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 
 /* --- Unix headers --- */
 
@@ -60,6 +64,8 @@
 #include <syslog.h>
 #include <unistd.h>
 
+extern char **environ;
+
 /* --- Local headers --- */
 
 #include "become.h"
@@ -72,6 +78,7 @@
 #include "parser.h"
 #include "rule.h"
 #include "utils.h"
+#include "userdb.h"
 
 /*----- Main code ---------------------------------------------------------*/
 
@@ -143,6 +150,24 @@ static void bc__usage(FILE *fp)
 	    "	$ -d [-p <port>] [-f <config-file>]\n");
 }
 
+/* --- @bc__makeEnv@ --- *
+ *
+ * Arguments:	@const char *var@ = name of an environment variable
+ *		@const char *value@ = value of the variable
+ *
+ * Returns:	A pointer to an allocated block assigning the value to the
+ *		name.
+ *
+ * Use:		Constructs environment mappings.
+ */
+
+static char *bc__makeEnv(const char *var, const char *value)
+{
+  char *p = xmalloc(strlen(var) + strlen(value) + 2);
+  sprintf(p, "%s=%s", var, value);
+  return (p);
+}
+
 /* --- @bc__help@ --- *
  *
  * Arguments:	@FILE *fp@ = stream to write on
@@ -174,11 +199,17 @@ static void bc__help(FILE *fp)
 "\n"
 "-h, --help		Display this help text\n"
 "-v, --version		Display the version number of this copy of $\n"
+"-l, --login		Really log in as the user\n"
 "-c, --command=CMD	Run the (Bourne) shell command CMD\n"
 "-d, --daemon		Start up a daemon, to accept requests from clients\n"
 "-p, --port=PORT		In daemon mode, listen on PORT\n"
 "-f, --config-file=FILE	In daemon mode, read config from FILE\n"
-"--yacc-debug		Dump lots of parser diagnostics (boring)\n");
+#ifdef TRACING
+"--impersonate=USER	Claim to be USER when asking the server\n"
+"--trace=FILE		Dump trace information to FILE (boring)\n"
+"--trace-level=OPTS	Set level of tracing information\n"
+#endif
+);
 }
 
 /* --- @main@ --- *
@@ -193,45 +224,89 @@ static void bc__help(FILE *fp)
 
 int main(int argc, char *argv[])
 {
-  char *cmd = 0;
-  static char *shell[] = { "/bin/sh", "-c", 0, 0 };
-  char **todo;
-  request rq;
-  char buff[CMDLEN_MAX];
-  char *conffile = file_RULES;
-  int port = -1;
+  /* --- Request block setup parameters --- */
 
-  enum {
-    f_daemon = 1,
-    f_duff = 2
+  request rq;				/* Request buffer to build */
+  char *cmd = 0;			/* Shell command to execute */
+  char *binary = "/bin/sh";		/* Default binary to execute */
+  char **env = environ;			/* Default environment to pass */
+  char **todo;				/* Pointer to argument list */
+  struct passwd *from_pw = 0;		/* User we are right now */
+  struct passwd *to_pw = 0;		/* User we want to become */
+
+  /* --- Become server setup parameters --- */
+
+  char *conffile = file_RULES;		/* Default config file for daemon */
+  int port = -1;			/* Default port for daemon */
+
+  /* --- Miscellanous shared variables --- */
+
+  unsigned flags = 0;			/* Various useful flags */
+
+  /* --- Default argument list executes a shell command --- */
+
+  static char *shell[] = {
+    "/bin/sh",				/* Bourne shell */
+    "-c",				/* Read from command line */
+    0,					/* Pointer to shell command */
+    0					/* Terminator */
   };
 
-  unsigned flags = 0;
+  /* --- Login request replaces the environment with this --- */
+
+  static char *mangled_env[] = {
+    "PATH=/bin:/usr/bin",		/* Default `clean' path*/
+    0,					/* User's name (`USER') */
+    0,					/* User's name (`LOGNAME') */
+    0,					/* Home directory (`HOME') */
+    0					/* Terminator */
+  };
+
+  /* --- Definitions for the various flags --- */
+
+  enum {
+    f_daemon = 1,			/* Start up in daemon mode */
+    f_duff = 2,				/* Fault in arguments */
+    f_login = 4,			/* Execute as a login shell */
+    f_dummy = 8,			/* Don't actually do anything */
+    f_setuid = 16			/* We're running setuid */
+  };
 
   /* --- Set up the program name --- */
 
   ego(argv[0]);
+  clock();
+  if (getuid() != geteuid())
+    flags |= f_setuid;
 
   /* --- Parse some command line arguments --- */
 
   for (;;) {
     int i;
-    struct option opts[] = {
+    static struct option opts[] = {
       { "help",		0,		0,	'h' },
       { "version",	0,		0,	'v' },
+      { "login",	0,		0,	'l' },
       { "command",	gFlag_argReq,	0,	'c' },
       { "daemon",	0,		0,	'd' },
       { "port",		gFlag_argReq,	0,	'p' },
       { "config-file",	gFlag_argReq,	0,	'f' },
-      { "yacc-debug",	0,		0,	'Y' },
+#ifdef TRACING
+      { "impersonate",	gFlag_argReq,	0,	'I' },
+      { "trace",	gFlag_argOpt,	0,	'T' },
+      { "trace-level",	gFlag_argOpt,	0,	'L' },
+#endif
       { 0,		0,		0,	0 }
     };
 
-    i = mdwopt(argc, argv, "hvc:p:df:", opts, 0, 0, 0);
+    i = mdwopt(argc, argv, "+hvlc:p:df:", opts, 0, 0, 0);
     if (i < 0)
       break;
 
     switch (i) {
+
+      /* --- Standard help and version options --- */
+
       case 'h':
 	bc__help(stdout);
 	exit(0);
@@ -240,6 +315,12 @@ int main(int argc, char *argv[])
 	bc__banner(stdout);
 	exit(0);
 	break;
+
+      /* --- Various simple options --- */
+
+      case 'l':
+	flags |= f_login;
+	break;
       case 'c':
 	cmd = optarg;
 	break;
@@ -252,12 +333,143 @@ int main(int argc, char *argv[])
       case 'f':
 	conffile = optarg;
 	break;
-      case 'Y':
-	if (getuid() == geteuid())
-	  yydebug = 1;
-	else
-	  moan("won't set debugging mode when running setuid");
+
+      /* --- Pretend to be a different user --- *
+       *
+       * There are all sorts of nasty implications for this option.  Don't
+       * allow it if we're running setuid.  Disable the actual login anyway.
+       */
+
+#ifdef TRACING
+      case 'I':
+	if (flags & f_setuid)
+	  moan("shan't allow impersonation while running setuid");
+	else {
+	  struct passwd *pw;
+	  if (isdigit((unsigned char)optarg[0]))
+	    pw = getpwuid(atoi(optarg));
+	  else
+	    pw = getpwnam(optarg);
+	  if (!pw)
+	    die("can't impersonate unknown user `%s'", optarg);
+	  from_pw = userdb_copyUser(pw);
+	  rq.from = from_pw->pw_uid;
+	  flags |= f_dummy;
+	}
 	break;
+#endif
+
+      /* --- Tracing support --- *
+       *
+       * Be careful not to zap a file I wouldn't normally be allowed to write
+       * to!
+       */
+
+#ifdef TRACING
+
+      case 'T': {
+	FILE *fp;
+
+	if (optarg == 0 || strcmp(optarg, "-") == 0)
+	  fp = stdout;
+	else {
+	  if ((flags & f_setuid) && access(optarg, W_OK)) {
+	    die("no write permission for trace file file `%s': %s",
+		optarg, strerror(errno));
+	  }
+	  if ((fp = fopen(optarg, "w")) == 0) {
+	    die("couldn't open trace file `%s' for writing: %s",
+		optarg, strerror(errno));
+	  }
+	}
+	traceon(fp, TRACE_DFL);
+	trace(TRACE_MISC, "become: tracing enabled");
+      } break;
+
+#endif
+
+      /* --- Setting trace levels --- */
+
+#ifdef TRACING
+
+      case 'L': {
+	int sense = 1;
+	unsigned int lvl = 0, l;
+	const char *p = optarg;
+
+	/* --- Table of tracing facilities --- */
+
+	typedef struct tr {
+	  char ch;
+	  unsigned int l;
+	  const char *help;
+	} tr;
+
+	static tr lvltbl[] = {
+	  { 'm', TRACE_MISC,	"miscellaneous messages" },
+	  { 's', TRACE_SETUP,	"building the request block" },
+	  { 'd', TRACE_DAEMON,	"server process" },
+	  { 'r', TRACE_RULE,	"ruleset scanning" },
+	  { 'c', TRACE_CHECK,	"request checking" },
+	  { 'l', TRACE_CLIENT,	"client process" },
+	  { 'R', TRACE_RAND,	"random number generator" },
+	  { 'C', TRACE_CRYPTO,	"cryptographic processing of requests" },
+	  { 'y', TRACE_YACC,	"parsing configuration file" },
+	  { 'D', TRACE_DFL,	"default tracing options" },
+	  { 'A', TRACE_ALL,	"all tracing options" },
+	  { 0,   0,		0 }
+	};
+	tr *tp;
+
+	/* --- Output some help if there's no arguemnt --- */
+
+	if (!optarg) {
+	  bc__banner(stdout);
+	  bc__write(stdout,
+		    "\n"
+		    "Tracing options:\n"
+		    "\n");
+	  for (tp = lvltbl; tp->l; tp++) {
+	    if ((flags & f_setuid) == 0 || tp->l & ~TRACE_PRIV)
+	      printf("%c -- %s\n", tp->ch, tp->help);
+	  }
+	  bc__write(stdout,
+"\n"
+"Also, `+' and `-' options are recognised to turn on and off vavrious\n"
+"tracing options.  For example, `A-r' enables everything except ruleset\n"
+"tracing, and `A-D+c' is everything except the defaults, but with request\n"
+"check tracing.\n"
+);
+	  exit(0);
+	}
+
+	while (*p) {
+	  if (*p == '+')
+	    sense = 1;
+	  else if (*p == '-')
+	    sense = 0;
+	  else {
+	    for (tp = lvltbl; tp->l && *p != tp->ch; tp++)
+	      ;
+	    l = tp->l;
+	    if (flags & f_setuid)
+	      l &= ~TRACE_PRIV;
+	    if (l)
+	      lvl = sense ? (lvl | l) : (lvl & ~l);
+	    else
+	      moan("unknown trace option `%c'", *p);
+	  }
+	  p++;
+	}
+
+	tracesetlvl(lvl);
+	yydebug = ((lvl & TRACE_YACC) != 0);
+      } break;
+
+#endif
+
+      /* --- Something I didn't understand has occurred --- */
+
       case '?':
 	flags |= f_duff;
 	break;
@@ -271,6 +483,7 @@ int main(int argc, char *argv[])
   /* --- Switch to daemon mode if requested --- */
 
   if (flags & f_daemon) {
+    T( trace(TRACE_MISC, "become: daemon mode requested"); )
     daemon_init(conffile, port);
     exit(0);
   }
@@ -284,22 +497,34 @@ int main(int argc, char *argv[])
   {
     const char *u;
     struct passwd *pw;
+
     if (optind >= argc) {
       bc__usage(stderr);
       exit(1);
     }
     u = argv[optind++];
-    pw = getpwnam(u);
-    if (!pw && isdigit(u[0]))
+
+    if (isdigit((unsigned char)u[0]))
       pw = getpwuid(atoi(u));
+    else
+      pw = getpwnam(u);
     if (!pw)
       die("unknown user `%s'", u);
+    to_pw = userdb_copyUser(pw);
     rq.to = pw->pw_uid;
   }
 
   /* --- Fill in the easy bits of the request --- */
 
-  rq.from = getuid();
+  if (!from_pw) {
+    struct passwd *pw;
+
+    rq.from = getuid();
+    pw = getpwuid(rq.from);
+    if (!pw)
+      die("who are you? (can't find user %li)", (long)rq.from);
+    from_pw = userdb_copyUser(pw);
+  }
 
   /* --- Find the local host address --- */
 
@@ -312,46 +537,89 @@ int main(int argc, char *argv[])
     memcpy(&rq.host, he->h_addr, sizeof(struct in_addr));
   }
 
-  /* --- Figure out what command to use --- */
+  /* --- Shell commands are easy --- */
 
   if (cmd) {
     shell[2] = cmd;
     todo = shell;
-  } else if (optind < argc) {
+  }
+
+  /* --- A command given on the command line isn't too hard --- */
+
+  else if (optind < argc) {
     todo = argv + optind;
-  } else {
-    struct passwd *pw = getpwuid(rq.from);
-    if (!pw)
-      die("who are you? (can't find uid %li in database)", (long)rq.from);
-    shell[0] = pw->pw_shell;
+    binary = todo[0];
+  }
+
+  /* --- A login request needs a little bit of work --- */
+
+  else if (flags & f_login) {
+    const char *p = strrchr(to_pw->pw_shell, '/');
+    if (p)
+      p++;
+    else
+      p = to_pw->pw_shell;
+    shell[0] = xmalloc(strlen(p) + 2);
+    shell[0][0] = '-';
+    strcpy(shell[0] + 1, p);
     shell[1] = 0;
     todo = shell;
+    binary = to_pw->pw_shell;
   }
 
+  /* --- An unadorned becoming requires little work --- */
+
+  else {
+    shell[0] = from_pw->pw_shell;
+    shell[1] = 0;
+    todo = shell;
+    binary = todo[0];
+  }
+
+  /* --- Mangle the environment if login flag given --- */
+
+  if (flags & f_login) {
+    env = mangled_env;
+    env[1] = bc__makeEnv("USER", to_pw->pw_name);
+    env[2] = bc__makeEnv("LOGNAME", to_pw->pw_name);
+    env[3] = bc__makeEnv("HOME", to_pw->pw_dir);
+  }
+
+  /* --- Trace the command --- */
+
+  IF_TRACING(TRACE_SETUP, {
+    int i;
+
+    trace(TRACE_SETUP, "setup: from user %s to user %s",
+	  from_pw->pw_name, to_pw->pw_name);
+    trace(TRACE_SETUP, "setup: binary == `%s'", binary);
+    for (i = 0; todo[i]; i++)
+      trace(TRACE_SETUP, "setup: arg %i == `%s'", i, todo[i]);
+    for (i = 0; env[i]; i++)
+      trace(TRACE_SETUP, "setup: env %i == `%s'", i, env[i]);
+  })
+
   /* --- If necessary, resolve the path to the command --- */
 
-  if (!strchr(todo[0], '/')) {
-    char *path;
-    char *p;
+  if (!strchr(binary, '/')) {
+    char *path, *p;
     struct stat st;
-    size_t sz;
 
     if ((p = getenv("PATH")) == 0)
       p = "/bin:/usr/bin";
-    sz = strlen(p) + 1;
-    memcpy(path = xmalloc(sz), p, sz);
+    path = xstrdup(p);
 
     for (p = strtok(path, ":"); (p = strtok(0, ":")) != 0; ) {
 
       /* --- SECURITY: check length of string before copying --- */
 
-      if (strlen(p) + strlen(todo[0]) + 2 > sizeof(buff))
+      if (strlen(p) + strlen(binary) + 2 > sizeof(rq.cmd))
 	continue;
 
       /* --- Now build the pathname and check it --- */
 
-      sprintf(buff, "%s/%s", p, todo[0]);
-      if (stat(buff, &st) == 0 &&	/* Check it exists */
+      sprintf(rq.cmd, "%s/%s", p, todo[0]);
+      if (stat(rq.cmd, &st) == 0 &&	/* Check it exists */
 	  st.st_mode & 0111 &&		/* Check it's executable */
 	  (st.st_mode & S_IFMT) == S_IFREG) /* Check it's a file */
 	break;
@@ -359,9 +627,10 @@ int main(int argc, char *argv[])
 
     if (!p)
       die("couldn't find `%s' in path", todo[0]);
-    todo[0] = buff;
+    binary = rq.cmd;
     free(path);
   }
+  T( trace(TRACE_SETUP, "setup: resolve binary to `%s'", binary); )
 
   /* --- Canonicalise the path string, if necessary --- */
 
@@ -373,7 +642,7 @@ int main(int argc, char *argv[])
     /* --- Insert current directory name if path not absolute --- */
 
     p = b;
-    q = todo[0];
+    q = binary;
     if (*q != '/') {
       if (!getcwd(b, sizeof(b)))
 	die("couldn't read current directory: %s", strerror(errno));
@@ -392,7 +661,7 @@ int main(int argc, char *argv[])
        */
 
       if (p >= b + sizeof(b) - 1)
-	die("buffer overflow -- bad things happened");
+	die("internal error: buffer overflow while canonifying path");
 
       /* --- Reduce multiple slashes to just one --- */
 
@@ -437,27 +706,17 @@ int main(int argc, char *argv[])
     *p++ = 0;
     strcpy(rq.cmd, b);
   }
+  T( trace(TRACE_SETUP, "setup: canonify binary to `%s'", rq.cmd); )
 
   /* --- Run the check --- */
 
   {
     int a = check(&rq);
-    char from[16], to[16];
-    struct passwd *pw;
-
-    if ((pw = getpwuid(rq.from)) != 0)
-      sprintf(from, "%.15s", pw->pw_name);
-    else
-      sprintf(from, "user %lu", (unsigned long)rq.from);
-
-    if ((pw = getpwuid(rq.to)) != 0)
-      sprintf(to, "%.15s", pw->pw_name);
-    else
-      sprintf(to, "user %lu", (unsigned long)rq.to);
 
     syslog(LOG_INFO,
 	   "permission %s for %s to become %s to run `%s'",
-	   a ? "granted" : "denied", from, to, rq.cmd);
+	   a ? "granted" : "denied", from_pw->pw_name, to_pw->pw_name,
+	   rq.cmd);
 
     if (!a)
       die("permission denied");
@@ -465,16 +724,18 @@ int main(int argc, char *argv[])
 
   /* --- Now do the job --- */
 
-#ifdef TEST_RIG
-  printf("ok\n");
-  return (0);
-#else
-  if (setuid(rq.to) == -1 || seteuid(rq.to) == -1)
-    die("couldn't set uid: %s", strerror(errno));
-  execv(rq.cmd, todo);
-  die("couldn't exec `%s': %s", rq.cmd, strerror(errno));
-  return (127);
-#endif
+  T( trace(TRACE_MISC, "become: permission granted"); )
+
+  if (flags & f_dummy) {
+    puts("permission granted");
+    return (0);
+  } else {
+    if (setuid(rq.to) == -1 || seteuid(rq.to) == -1)
+      die("couldn't set uid: %s", strerror(errno));
+    execve(rq.cmd, todo, env);
+    die("couldn't exec `%s': %s", rq.cmd, strerror(errno));
+    return (127);
+  }
 }
 
 /*----- That's all, folks -------------------------------------------------*/
diff --git a/src/blowfish-sbox.h b/src/blowfish-sbox.h
index 0baf11c..42099b3 100644
--- a/src/blowfish-sbox.h
+++ b/src/blowfish-sbox.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: blowfish-sbox.h,v 1.1 1997/07/21 13:47:54 mdw Exp $
+ * $Id: blowfish-sbox.h,v 1.2 1997/08/04 10:24:20 mdw Exp $
  *
  * Blowfish encryption routines
  *
@@ -29,7 +29,10 @@
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: blowfish-sbox.h,v $
- * Revision 1.1  1997/07/21 13:47:54  mdw
+ * Revision 1.2  1997/08/04 10:24:20  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:54  mdw
  * Initial revision
  *
  */
diff --git a/src/blowfish.c b/src/blowfish.c
index ddf7b26..8cc302d 100644
--- a/src/blowfish.c
+++ b/src/blowfish.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: blowfish.c,v 1.1 1997/07/21 13:47:53 mdw Exp $
+ * $Id: blowfish.c,v 1.2 1997/08/04 10:24:20 mdw Exp $
  *
  * Blowfish encryption routines
  *
@@ -29,7 +29,10 @@
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: blowfish.c,v $
- * Revision 1.1  1997/07/21 13:47:53  mdw
+ * Revision 1.2  1997/08/04 10:24:20  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:53  mdw
  * Initial revision
  *
  */
diff --git a/src/blowfish.h b/src/blowfish.h
index 23519a6..46eb0ef 100644
--- a/src/blowfish.h
+++ b/src/blowfish.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: blowfish.h,v 1.1 1997/07/21 13:47:53 mdw Exp $
+ * $Id: blowfish.h,v 1.2 1997/08/04 10:24:20 mdw Exp $
  *
  * Blowfish encryption routines
  *
@@ -29,7 +29,10 @@
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: blowfish.h,v $
- * Revision 1.1  1997/07/21 13:47:53  mdw
+ * Revision 1.2  1997/08/04 10:24:20  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:53  mdw
  * Initial revision
  *
  */
diff --git a/src/check.c b/src/check.c
index 9ed0b6f..1d1eba8 100644
--- a/src/check.c
+++ b/src/check.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: check.c,v 1.1 1997/07/21 13:47:53 mdw Exp $
+ * $Id: check.c,v 1.2 1997/08/04 10:24:20 mdw Exp $
  *
  * Check validity of requests
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: check.c,v $
- * Revision 1.1  1997/07/21 13:47:53  mdw
+ * Revision 1.2  1997/08/04 10:24:20  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:53  mdw
  * Initial revision
  *
  */
@@ -69,114 +72,160 @@
 #include "rule.h"
 #include "parser.h"
 #include "tx.h"
+#include "userdb.h"
 #include "utils.h"
 
 /*----- Main code ---------------------------------------------------------*/
 
-/* --- @check__client@ --- *
+/* --- @check__send@ --- *
+ *
+ * Arguments:	@unsigned char *crq@ = pointer to encrypted request
+ *		@int fd@ = socket to send from
+ *		@struct sockaddr_in *serv@ = pointer to table of servers
+ *		@size_t n_serv@ = number of servers
+ *
+ * Returns:	---
+ *
+ * Use:		Sends the request packet to the list of servers.  If the
+ *		message couldn't be sent to any of them, an error is
+ *		reported.
+ */
+
+static void check__send(unsigned char *crq, int fd,
+			struct sockaddr_in *serv, size_t n_serv)
+{
+  size_t i;
+  int ok = 0;
+  int err = 0;
+
+  for (i = 0; i < n_serv; i++) {
+    if (sendto(fd, (char *)crq, crq_size, 0,
+	       (struct sockaddr *)(serv + i), sizeof(serv[i])) < 0) {
+      T( trace(TRACE_CLIENT, "client: send to %s failed: %s",
+	       inet_ntoa(serv[i].sin_addr), strerror(errno)); )
+      err = errno;
+    } else
+      ok = 1;
+  }
+
+  if (!ok)
+    die("couldn't send request to server: %s", strerror(err));
+}
+
+/* --- @check__ask@ --- *
  *
  * Arguments:	@request *rq@ = pointer to request buffer
- *		@const char *serv@ = pointer to the server
- *		@int port@ = port number to use
+ *		@struct sockaddr_in *serv@ = pointer to table of servers
+ *		@size_t n_serv@ = number of servers
  *
  * Returns:	Nonzero if OK, zero if forbidden
  *
- * Use:		Contacts a server to decide whether the request is OK.
+ * Use:		Contacts a number of servers to decide whether the request
+ *		is OK.
  */
 
-static int check__client(request *rq, const char *serv, int port)
+static int check__ask(request *rq, struct sockaddr_in *serv, size_t n_serv)
 {
   int fd;
-  struct sockaddr_in ssin;
   unsigned char crq[crq_size];
-  unsigned char k[IDEA_KEYSIZE];
   unsigned char sk[IDEA_KEYSIZE];
   time_t t;
   pid_t pid;
 
-  /* --- Create my socket --- */
+  /* --- First, build the encrypted request packet --- */
 
-  if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
-    die("couldn't create socket: %s", strerror(errno));
+  {
+    unsigned char k[IDEA_KEYSIZE];
+    FILE *fp;
 
-  /* --- Bind myself to some address --- */
+    /* --- Read in the encryption key --- */
 
-  {
-    struct sockaddr_in sin;
+    if ((fp = fopen(file_KEY, "r")) == 0) {
+      die("couldn't open key file `%s': %s", file_KEY,
+	  strerror(errno));
+    }
+    tx_getBits(k, 128, fp);
 
-    sin.sin_family = AF_INET;
-    sin.sin_port = 0;
-    sin.sin_addr.s_addr = htonl(INADDR_ANY);
+    /* --- Now build a request packet --- */
 
-    if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
-      die("couldn't bind socket to address: %s", strerror(errno));
+    t = time(0);
+    pid = getpid();
+    crypt_packRequest(rq, crq, t, pid, k, sk);
+    burn(k);
+    T( trace(TRACE_CLIENT, "client: encrypted request packet"); )
   }
 
-  /* --- Find the server's address --- */
+  /* --- Create my socket --- */
 
   {
-    struct hostent *he;
+    struct sockaddr_in sin;
 
-    /* --- Resolve the server's name --- */
+    if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
+      die("couldn't create socket: %s", strerror(errno));
 
-    if ((he = gethostbyname(serv)) == 0)
-      die("couldn't find server host `%s'", serv);
+    /* --- Bind myself to some address --- */
 
-    /* --- Build the address block --- */
+    sin.sin_family = AF_INET;
+    sin.sin_port = 0;
+    sin.sin_addr.s_addr = htonl(INADDR_ANY);
 
-    ssin.sin_family = AF_INET;
-    ssin.sin_port = htons(port);
-    memcpy(&ssin.sin_addr, he->h_addr, sizeof(struct in_addr));
+    if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
+      die("couldn't bind socket to address: %s", strerror(errno));
   }
 
-  /* --- Read in the encryption key --- */
+  /* --- Now wait for a reply --- */
 
   {
-    FILE *fp;
-
-    if ((fp = fopen(file_KEY, "r")) == 0) {
-      die("couldn't open key file `%s': %s", file_KEY,
-	  strerror(errno));
-    }
-    tx_getBits(k, 128, fp);
-  }
-
-  /* --- Now build a request packet --- */
-
-  t = time(0);
-  pid = getpid();
-  crypt_packRequest(rq, crq, t, pid, k, sk);
+    fd_set fds;
+    struct timeval start, now, tv;
+    int ind;
+    size_t i;
 
-  /* --- Send the packet to the server --- */
+    /* --- State table for waiting for replies --- *
+     *
+     * For each number, send off the request to our servers, and wait for
+     * that many seconds to have elapsed since we started.  If the number is
+     * %$-1$% then it's time to give up.
+     */
 
-  if (sendto(fd, (char *)crq, sizeof(crq), 0,
-	     (struct sockaddr *)&ssin, sizeof(ssin)) < 0) {
-    burn(k);
-    die("couldn't send request to server: %s", strerror(errno));
-  }
-  burn(k);
+    static int tbl[] = { 0, 5, 10, 20, -1 };
 
-  /* --- Now wait for a reply --- */
+    /* --- Find out when we are --- */
 
-  {
-    fd_set fds;
-    struct timeval when, now, tv;
+    gettimeofday(&start, 0);
+    ind = 0;
 
-    gettimeofday(&when, 0);
-    when.tv_sec += 10;
+    /* --- Now loop until everything's done --- */
 
     for (;;) {
-      int i;
+      gettimeofday(&now, 0);
 
-      /* --- Sort out when to return --- */
+      /* --- If the current timer has expired, find one that hasn't --- *
+       *
+       * Also resend the request after I've found a timer which is still
+       * extant.  If there aren't any, report an error.
+       */
+
+      if (now.tv_sec >= start.tv_sec + tbl[ind] &&
+	  now.tv_usec >= start.tv_usec) {
+	do {
+	  ind++;
+	  if (tbl[ind] < 0)
+	    die("no reply from servers");
+	} while (now.tv_sec >= start.tv_sec + tbl[ind] &&
+		 now.tv_usec >= start.tv_usec);
+	check__send(crq, fd, serv, n_serv);
+	T( trace(TRACE_CLIENT, "client: send request to servers"); )
+      }
 
-      gettimeofday(&now, 0);
-      if (now.tv_usec > when.tv_usec) {
+      /* --- Now wait for a packet to arrive --- */
+
+      if (now.tv_usec > start.tv_usec) {
 	now.tv_usec -= 1000000;
 	now.tv_sec += 1;
       }
-      tv.tv_sec = when.tv_sec - now.tv_sec;
-      tv.tv_usec = when.tv_usec - now.tv_usec;
+      tv.tv_sec = start.tv_sec + tbl[ind] - now.tv_sec;
+      tv.tv_usec = start.tv_usec - now.tv_usec;
 
       /* --- Sort out file descriptors to watch --- */
 
@@ -186,8 +235,8 @@ static int check__client(request *rq, const char *serv, int port)
       /* --- Wait for them --- */
 
       i = select(FD_SETSIZE, &fds, 0, 0, &tv);
-      if (i == 0)
-	die("no answer from server");
+      if (i == 0 || (i < 0 && errno == EINTR))
+	continue;
       if (i < 0)
 	die("error waiting for reply: %s", strerror(errno));
 
@@ -205,26 +254,245 @@ static int check__client(request *rq, const char *serv, int port)
 		     (struct sockaddr *)&sin, &slen) < 0)
 	  die("error reading server's reply: %s", strerror(errno));
 
-	/* --- Verify the sender --- */
-
-	if (sin.sin_addr.s_addr != ssin.sin_addr.s_addr ||
-	    sin.sin_port != ssin.sin_port)
+	IF_TRACING(TRACE_CLIENT, {
+	  struct hostent *h = gethostbyaddr((char *)&sin.sin_addr,
+					    sizeof(sin.sin_addr), AF_INET);
+	  trace(TRACE_CLIENT, "client: reply received from %s port %i",
+		h ? h->h_name : inet_ntoa(sin.sin_addr),
+		ntohs(sin.sin_port));
+	})
+
+	/* --- Verify the sender --- *
+	 *
+	 * This is more to avoid confusion than for security: an active
+	 * attacker is quite capable of forging the source address.  We rely
+	 * on the checksum in the reply packet for authentication.
+	 */
+
+	for (i = 0; i < n_serv; i++) {
+	  if (sin.sin_addr.s_addr == serv[i].sin_addr.s_addr &&
+	      sin.sin_port == serv[i].sin_port)
+	    break;
+	}
+	if (i >= n_serv) {
+	  T( trace(TRACE_CLIENT, "client: reply from unknown host"); )
 	  continue;
+	}
     
 	/* --- Unpack and verify the response --- */
 
 	answer = crypt_unpackReply(buff, sk, t, pid);
-	if (answer < 0)
+	if (answer < 0) {
+	  T( trace(TRACE_CLIENT,
+		   "client: invalid or corrupt reply packet"); )
 	  continue;
+	}
 	return (answer);
       }
     }
   }
 
-  die("internal error: can't get here in check_client");
+  die("internal error: can't get here in check__ask");
   return (0);
 }
 
+/* --- @check__client@ --- *
+ *
+ * Arguments:	@request *rq@ = pointer to a request block
+ *		@FILE *fp@ = file containing server configuration
+ *
+ * Returns:	Nonzero if OK, zero if forbidden
+ *
+ * Use:		Asks one or several servers whether a request is acceptable.
+ */
+
+int check__client(request *rq, FILE *fp)
+{
+  /* --- Format of the file --- *
+   *
+   * The `servers' file contains entries of the form
+   *
+   *    %%\syntax{<host> [`:' <port>]}%%
+   *
+   * separates by whitespace.  I build them all into an array of socket
+   * addresses and pass the whole lot to another function.
+   */
+
+  struct sockaddr_in *serv;		/* Array of servers */
+  size_t n_serv, max_serv;		/* Number and maximum number */
+
+  /* --- Initialise the server array --- */
+
+  T( trace(TRACE_CLIENT, "client: reading server definitions"); )
+  n_serv = 0; max_serv = 4;		/* Four seems reasonable */
+  serv = xmalloc(sizeof(*serv) * max_serv);
+
+  /* --- Start reading the file --- */
+
+  {
+    char buff[256], *p, *l;		/* A buffer and pointers for it */
+    int port;				/* Default port for servers */
+    int state;				/* Current parser state */
+    struct in_addr t_host;		/* Temp place for an address*/
+    int t_port;				/* Temp place for a port */
+    int ch;				/* The current character */
+
+    /* --- Parser states --- */
+
+    enum {
+      st_start,				/* Waiting to begin */
+      st_host,				/* Reading a new hostname */
+      st_colon,				/* Expecting a colon, maybe */
+      st_preport,			/* Waiting before reading port */
+      st_port,				/* Reading a port number */
+      st_commit,			/* Commit a newly read server */
+      st_done				/* Finished reading the file */
+    };
+
+    /* --- Find a default port --- */
+
+    {
+      struct servent *s = getservbyname(quis(), "udp");
+      port = (s ? s->s_port : -1);
+    }
+
+    /* --- Initialise for scanning the file --- */
+
+    state = st_host;
+    p = buff;
+    l = buff + sizeof(buff);
+    t_port = port;
+    ch = getc(fp);
+
+    /* --- Go for it --- */
+
+    while (state != st_done) {
+      switch (state) {
+
+	/* --- Initial whitespace before hostname --- */
+
+	case st_start:
+	  if (ch == EOF)
+	    state = st_done;
+	  else if (isspace((unsigned char)ch))
+	    ch = getc(fp);
+	  else
+	    state = st_host;
+	  break;
+
+	/* --- Read a host name --- */
+
+	case st_host:
+	  if (p == l)
+	    die("string too long in `" file_SERVER "'");
+	  if (ch != EOF && !isspace((unsigned char)ch) && ch != ':') {
+	    *p++ = ch;
+	    ch = getc(fp);
+	  } else {
+	    struct hostent *h;
+
+	    *p++ = 0;
+	    if ((h = gethostbyname(buff)) == 0)
+	      die("unknown host `%s' in `" file_SERVER "'", buff);
+	    memcpy(&t_host, h->h_addr, sizeof(t_host));
+	    state = st_colon;
+	  }
+	  break;
+
+	/* --- Waiting for a colon coming up --- */
+
+	case st_colon:
+	  if (ch == EOF)
+	    state = st_commit;
+	  else if (isspace((unsigned char)ch))
+	    ch = getc(fp);
+	  else if (ch == ':') {
+	    state = st_preport;
+	    ch = getc(fp);
+	  }
+	  else
+	    state = st_commit;
+	  break;
+
+	/* --- Clearing whitespace before a port number --- */
+
+	case st_preport:
+	  if (ch == EOF)
+	    state = st_commit;
+	  else if (isspace((unsigned char)ch))
+	    ch = getc(fp);
+	  else {
+	    state = st_port;
+	    p = buff;
+	  }
+	  break;
+
+	/* --- Read a port number --- */
+
+	case st_port:
+	  if (p == l)
+	    die("string too long in `" file_SERVER "'");
+	  if (ch != EOF && !isspace((unsigned char)ch) && ch != ':') {
+	    *p++ = ch;
+	    ch = getc(fp);
+	  } else {
+	    struct servent *s;
+
+	    *p++ = 0;
+	    s = getservbyname(buff, "udp");
+	    if (!s && isdigit((unsigned char)buff[0]))
+	      t_port = htons(atoi(buff));
+	    else if (!s)
+	      die("unknown service `%s' in `" file_SERVER "'", buff);
+	    else
+	      t_port = s->s_port;
+	    state = st_commit;
+	  }
+	  break;
+
+	/* --- A server has been read successfully --- */
+
+	case st_commit:
+	  if (n_serv == max_serv) {
+	    max_serv *= 2;
+	    serv = xrealloc(serv, max_serv * sizeof(*serv));
+	  }
+	  serv[n_serv].sin_family = AF_INET;
+	  serv[n_serv].sin_addr = t_host;
+	  serv[n_serv].sin_port = t_port;
+	  n_serv++;
+	  state = st_start;
+	  p = buff;
+	  t_port = port;
+	  break;
+
+	/* --- A safety net for a broken parser --- */
+
+	default:
+	  die("internal error: can't get here in check__client");
+	  break;	  
+      }
+    }
+  }
+
+  fclose(fp);
+
+  /* --- Now start sending requests --- */
+
+  if (!n_serv)
+    die("no servers specified in `" file_SERVER "'");
+
+  IF_TRACING(TRACE_CLIENT, {
+    size_t i;
+
+    for (i = 0; i < n_serv; i++) {
+      trace(TRACE_CLIENT, "client: server %s port %i",
+	    inet_ntoa(serv[i].sin_addr), ntohs(serv[i].sin_port));
+    }
+  })
+  return (check__ask(rq, serv, n_serv));
+}
+
 /* --- @check@ --- *
  *
  * Arguments:	@request *rq@ = pointer to request buffer
@@ -240,41 +508,19 @@ int check(request *rq)
 
   /* --- Check if we need to talk to a server --- */
 
-  if ((fp = fopen(file_SERVER, "r")) != 0) {
-    char buff[64];
-    int port;
-    int ch;
-
-    if (fscanf(fp, " %63[^: \t] ", buff) < 1)
-      die("error in `%s'", file_SERVER);
-    ch = getc(fp);
-    if (ch == ':') {
-      char b[64];
-      struct servent *se;
-
-      fscanf(fp, "%s", b);
-      if ((se = getservbyname(b, 0)) != 0)
-	port = ntohs(se->s_port);
-      else if ((port = atoi(b)) == 0)
-	die("error in `%s'", file_SERVER);
-    } else {
-      struct servent *se;
-
-      if ((se = getservbyname(quis(), "udp")) == 0)
-	die("no idea which port to use");
-      port = ntohs(se->s_port);
-    }
-    fclose(fp);
-    return (check__client(rq, buff, port));
-  }
+  if ((fp = fopen(file_SERVER, "r")) != 0)
+    return (check__client(rq, fp));
 
-  /* --- Read the configuration in and go --- */
+  /* --- Otherwise do this all the old-fashioned way --- */
 
   if ((fp = fopen(file_RULES, "r")) == 0) {
     die("couldn't read configuration file `%s': %s",
 	file_RULES, strerror(errno));
   }
 
+  userdb_init();
+  userdb_local();
+  userdb_yp();
   name_init();
   rule_init();
   lexer_scan(fp);
diff --git a/src/check.h b/src/check.h
index 24f5cb9..53b4c6b 100644
--- a/src/check.h
+++ b/src/check.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: check.h,v 1.1 1997/07/21 13:47:52 mdw Exp $
+ * $Id: check.h,v 1.2 1997/08/04 10:24:21 mdw Exp $
  *
  * Check validity of requests
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: check.h,v $
- * Revision 1.1  1997/07/21 13:47:52  mdw
+ * Revision 1.2  1997/08/04 10:24:21  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:52  mdw
  * Initial revision
  *
  */
diff --git a/src/class.c b/src/class.c
index d2f5e4b..7a7d016 100644
--- a/src/class.c
+++ b/src/class.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: class.c,v 1.1 1997/07/21 13:47:52 mdw Exp $
+ * $Id: class.c,v 1.2 1997/08/04 10:24:21 mdw Exp $
  *
  * Handling classes of things nicely
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: class.c,v $
- * Revision 1.1  1997/07/21 13:47:52  mdw
+ * Revision 1.2  1997/08/04 10:24:21  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:52  mdw
  * Initial revision
  *
  */
@@ -55,6 +58,7 @@
 
 /* --- Local headers --- */
 
+#include "become.h"
 #include "class.h"
 #include "set.h"
 #include "sym.h"
@@ -166,10 +170,16 @@ int class_userMatch(classdef *c, int u)
 {
   if (~c->type & clType_user)
     return (0);
-  else if (c == class_all)
+  else if (c == class_all) {
+    T( trace(TRACE_CHECK, "check: user %i matched by all", u); )
     return (1);
-  else
-    return (sym_find(c->t, (char *)&u, sizeof(u), 0, 0) != 0);
+  } else {
+    sym_base *s = sym_find(c->t, (char *)&u, sizeof(u), 0, 0);
+    T( trace(TRACE_CHECK,
+	     s ? "check: user %i matched" : "check: user %i not matched",
+	     u); )
+    return (s != 0);
+  }
 }
 
 /* --- @class_commandMatch@ --- *
@@ -192,13 +202,18 @@ int class_commandMatch(classdef *c, const char *p)
 
   if (~c->type & clType_command)
     return (0);
-  else if (c == class_all)
+  else if (c == class_all) {
+    T( trace(TRACE_CHECK, "check: command `%s' matched by all", p); )
     return (1);
-  else {
+  } else {
     for (sym_createIter(&i, c->t); (s = sym_next(&i)) != 0; ) {
-      if (class__wildMatch(s->name, p))
+      if (class__wildMatch(s->name, p)) {
+	T( trace(TRACE_CHECK, "check: command `%s' matched by `%s'",
+		 p, s->name); )
 	return (1);
+      }
     }
+    T( trace(TRACE_CHECK, "check: command `%s' not matched", p); )
     return (0);
   }
 }
@@ -224,16 +239,22 @@ int class_hostMatch(classdef *c, struct in_addr addr)
 
   if (~c->type & clType_host)
     return (0);
-  else if (c == class_all)
+  else if (c == class_all) {
+    T( trace(TRACE_CHECK, "check: host %s matched by all",
+	     inet_ntoa(addr)); )
     return (1);
-  else {
+  } else {
 
     /* --- Get the dotted-quad and other names for the address --- */
 
-    if ((a = inet_ntoa(addr)) == 0)
+    if ((a = inet_ntoa(addr)) == 0) {
+      T( trace(TRACE_CHECK, "check: couldn't translate address (erk!)"); )
       return (0);
-    if ((he = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)) == 0)
+    }
+    if ((he = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET)) == 0) {
+      T( trace(TRACE_CHECK, "check: couldn't resolve hostname for %s", a); )
       return (0);
+    }
 
     /* --- Now search the list for a match --- *
      *
@@ -244,21 +265,33 @@ int class_hostMatch(classdef *c, struct in_addr addr)
 
       /* --- Check the dotted-quad name first --- */
 
-      if (class__wildMatch(s->name, a))
+      if (class__wildMatch(s->name, a)) {
+	T( trace(TRACE_CHECK, "check: host address `%s' matched by `%s'",
+		 a, s->name); )
 	return (1);
+      }
 
       /* --- Now try the host's main name --- */
 
-      if (class__wildMatch(s->name, he->h_name))
+      if (class__wildMatch(s->name, he->h_name)) {
+	T( trace(TRACE_CHECK, "check: host name `%s' matched by `%s'",
+		 he->h_name, s->name); )
 	return (1);
+      }
 
       /* --- Now go through all the names --- */
 
       for (p = he->h_aliases; *p; p++) {
-	if (class__wildMatch(s->name, *p))
+	if (class__wildMatch(s->name, *p)) {
+	  T( trace(TRACE_CHECK, "check: host alias `%s' matched by `%s'",
+		   *p, s->name); )
 	  return (1);
+	}
       }
     }
+
+    T( trace(TRACE_CHECK, "check: couldn't match hostname `%s'",
+	     he->h_name); )
     return (0);
   }
 }
@@ -266,60 +299,34 @@ int class_hostMatch(classdef *c, struct in_addr addr)
 /* --- @class_dump@ --- *
  *
  * Arguments:	@classdef *c@ = pointer to a class block
- *		@FILE *fp@ = pointer to a stream object
  *
  * Returns:	---
  *
  * Use:		Dumps the contents of a class to a stream.
  */
 
-void class_dump(classdef *c, FILE *fp)
+void class_dump(classdef *c)
 {
   sym_iter i;
   sym_base *s;
 
-  /* --- Write a little header block --- */
-
-  {
-    const char *typetbl[] = {
-      "bad class",
-      "user",
-      "command",
-      "user/command",
-      "host",
-      "host/user",
-      "host/command",
-      "all",
-    };
-
-    fprintf(fp,
-	    "*** Type: %s\n"
-	    "*** Refs: %u\n"
-	    "*** \n"
-	    "*** Items:\n",
-	    c->type < clType__limit ? typetbl[c->type] : "bad class",
-	    c->ref);
-  }
-
   /* --- Dump the table --- */
 
   if (c->type != clType_all) {
     for (sym_createIter(&i, c->t); (s = sym_next(&i)) != 0; ) {
       switch (c->type) {
 	case clType_user:
-	  fprintf(fp, "***   %i\n", *(int *)s->name);
+	  trace(TRACE_RULE, "    %i", *(int *)s->name);
 	  break;
 	case clType_command:
 	case clType_host:
-	  fputs("***   ", fp);
-	  fwrite(s->name, s->len, 1, fp);
-	  putc('\n', fp);
+	  trace(TRACE_RULE, "    `%s'", s->name);
 	  break;
       }
     }
   }
-
-  putc('\n', fp);
+  else
+    trace(TRACE_RULE, "    ALL");
 }
 
 /*----- That's all, folks -------------------------------------------------*/
diff --git a/src/class.h b/src/class.h
index cbe3929..9abbe3f 100644
--- a/src/class.h
+++ b/src/class.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: class.h,v 1.1 1997/07/21 13:47:52 mdw Exp $
+ * $Id: class.h,v 1.2 1997/08/04 10:24:21 mdw Exp $
  *
  * Handling classes of things nicely
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: class.h,v $
- * Revision 1.1  1997/07/21 13:47:52  mdw
+ * Revision 1.2  1997/08/04 10:24:21  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:52  mdw
  * Initial revision
  *
  */
@@ -156,14 +159,13 @@ extern int class_hostMatch(classdef */*c*/, struct in_addr /*addr*/);
 /* --- @class_dump@ --- *
  *
  * Arguments:	@classdef *c@ = pointer to a class block
- *		@FILE *fp@ = pointer to a stream object
  *
  * Returns:	---
  *
  * Use:		Dumps the contents of a class to a stream.
  */
 
-extern void class_dump(classdef */*c*/, FILE */*fp*/);
+extern void class_dump(classdef */*c*/);
 
 /*----- That's all, folks -------------------------------------------------*/
 
diff --git a/src/crypt.c b/src/crypt.c
index 86ed605..d052471 100644
--- a/src/crypt.c
+++ b/src/crypt.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: crypt.c,v 1.1 1997/07/21 13:47:51 mdw Exp $
+ * $Id: crypt.c,v 1.2 1997/08/04 10:24:21 mdw Exp $
  *
  * Cryptographic transfer of `become' requests
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: crypt.c,v $
- * Revision 1.1  1997/07/21 13:47:51  mdw
+ * Revision 1.2  1997/08/04 10:24:21  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:51  mdw
  * Initial revision
  *
  */
@@ -48,73 +51,27 @@
 /* --- Unix headers --- */
 
 #include <sys/types.h>
+#include <sys/time.h>
 #include <unistd.h>
 #include <syslog.h>
 #include <fcntl.h>
 
 /* --- Local headers --- */
 
+#include "become.h"
 #include "config.h"
 #include "crypt.h"
 #include "icrypt.h"
 #include "idea.h"
 #include "md5.h"
+#include "noise.h"
+#include "rand.h"
 #include "tx.h"
 #include "utils.h"
 
 /*----- Magic numbers -----------------------------------------------------*/
 
-#define crypt__timeError 15		/* Seconds error to permit */
-#define crypt__seedBits 512		/* Number of random seed bits */
-
-/*----- Dump a block of data ----------------------------------------------*/
-
-/* --- @crypt__dump@ --- *
- *
- * Arguments:   @char *p@ = a string to display at the top of the message
- *              @unsigned char *buf@ = pointer to a buffer to display
- *              @size_t sz@ = size of the buffer
- *		@FILE *fp@ = file to dump on
- *
- * Returns:     --
- *
- * Use:         Dumps a block of data to the terminal.  This allows a
- *              programmer to examine the traffic between client and server,
- *              and possibly locate bugs.
- */
-
-#ifndef NDEBUG
-
-static void crypt__dump(const char *p, const unsigned char *buf,
-			int sz, FILE *fp)
-{
-  int i;
-  fprintf(stderr,"+++ %s\n",p);
-  while (sz>0)
-  {
-    fprintf(stderr,"+++ ");
-    for (i=0;i<8;i++)
-    {
-      if (i<sz)
-        fprintf(stderr,"%02x ",buf[i] & 0xff);
-      else
-        fputs("** ",stderr);
-    }
-    fputs(": ",stderr);
-    for (i=0;i<8;i++)
-      putc(i<sz ? (isprint(buf[i]) ? buf[i] : '.') : '*',stderr);
-    putc('\n',stderr);
-    buf+=8;
-    sz-=8;
-  }
-  putc('\n',stderr);
-}
-
-#else
-
-#define crypt__dump(p, buf, sz, fp) ((void)0)
-
-#endif
+#define crypt__timeError 60		/* Seconds error to permit */
 
 /*----- Main code ---------------------------------------------------------*/
 
@@ -122,8 +79,6 @@ static void crypt__dump(const char *p, const unsigned char *buf,
  *
  * Arguments:	@const char *seedfile@ = pointer to name of seed file
  *		@unsigned char *k@ = our secret key
- *		@time_t t@ = the current time
- *		@pid_t pid@ = our process id
  *		@unsigned *sk@ = where to store the session key
  *		@unsigned char *iv@ = where to store the IV
  *
@@ -133,108 +88,65 @@ static void crypt__dump(const char *p, const unsigned char *buf,
  */
 
 static void crypt__sessionKey(const char *seedfile, unsigned char *k,
-			      time_t t, pid_t pid,
 			      unsigned char *sk, unsigned char *iv)
 {
   FILE *fp;				/* File handle for reading */
-  unsigned char s[crypt__seedBits / 8];	/* Random seed block */
-  unsigned char b[4 + 4];
-					/* For building the hash block */
+  struct flock l;
+  int ok = 1;
 
-  /* --- Read the old seed in --- *
+  /* --- Open the random seed file --- *
    *
-   * Interlock with other processes locking this file.
+   * If I can't manage that, create a new one.
    */
 
-  {
-#ifndef TEST_RIG
-    struct flock l;
-#endif
-
-    if ((fp = fopen(seedfile, "r+")) == 0)
-      die("couldn't open random seed file `%s': %s",
-	  seedfile, strerror(errno));
-
-#ifndef TEST_RIG
-    l.l_type = F_WRLCK;
-    l.l_whence = SEEK_SET;
-    l.l_start = 0;
-    l.l_len = 0;
-    if (fcntl(fileno(fp), F_SETLKW, &l) < 0)
-      die("couldn't lock random number file: %s", strerror(errno));
-#endif
-
-    tx_getBits(s, crypt__seedBits, fp);
+  if ((fp = fopen(seedfile, "r+")) == 0) {
+    ok = 0;
+    if ((fp = fopen(seedfile, "w+")) == 0)
+      die("can't create random number file: %s", strerror(errno));
+    rand_clear();
   }
 
-  crypt__dump("Initial seed", s, crypt__seedBits / 8, stdout);
-
-  /* --- Build a block of data to hash --- */
-
-  store32(b + 0, t);
-  store32(b + 4, pid);
-
-  /* --- Work out the session key --- */
-
-  {
-    md5 md;
-
-    md5_init(&md);
-    md5_buffer(&md, s, sizeof(s));
-    md5_buffer(&md, b, sizeof(b));
-    md5_buffer(&md, k, IDEA_KEYSIZE);
-    md5_final(&md, sk);
-
-    crypt__dump("Session key", sk, 128 / 8, stdout);
-    burn(md);
-  }
+  /* --- Lock the seed file against concurrency problems --- */
 
-  /* --- Build the new seed and write it back again --- */
+  l.l_type = F_WRLCK;
+  l.l_whence = SEEK_SET;
+  l.l_start = 0;
+  l.l_len = 0;
+  if (fcntl(fileno(fp), F_SETLKW, &l) < 0)
+    die("can't lock random number file: %s", strerror(errno));
 
-  if (crypt__seedBits > 128) {
-    unsigned char tb[MD5_HASHSIZE];
-    int i;
+    /* --- Now read the file, and launder the seed --- */
 
-    memcpy(tb, s + crypt__seedBits / 8 - sizeof(tb), sizeof(tb));
-    memmove(s + sizeof(tb), s, crypt__seedBits / 8 - sizeof(tb));
-    memcpy(s, tb, sizeof(tb));
-    for (i = 0; i < sizeof(sk); i++)
-      s[i] ^= sk[i];
-    burn(tb);
-  }
+  if (ok)
+    rand_read(fp);
 
-  /* --- Take the seed we have and hash it again to get an IV --- */
+  /* --- Encrypt the pool using the secret key --- */
 
   {
-    unsigned char mdv[MD5_HASHSIZE];
-    md5 md;
-
-    md5_init(&md);
-    md5_buffer(&md, b, sizeof(b));
-    md5_buffer(&md, k, IDEA_KEYSIZE);
-    md5_buffer(&md, s, sizeof(s));
-    md5_final(&md, mdv);
-    memcpy(iv, mdv, IDEA_BLKSIZE);
-    crypt__dump("IV", iv, IDEA_BLKSIZE, stdout);
-    burn(md); burn(mdv);
+    icrypt_job j;
+    icrypt_init(&j, k, 0);
+    rand_encrypt(&j);
+    burn(j);
   }
 
+  /* --- Generate the session key and IV --- */
 
-  /* --- Lock the file again --- *
-   *
-   * We're closing the file after we've finished, so we don't need to
-   * unlock it afterwards.
-   */
+  noise_acquire();
+  rand_extract(sk, IDEA_KEYSIZE);
+  rand_extract(iv, IDEA_BLKSIZE);
+
+  IF_TRACING(TRACE_CRYPTO,
+    traceblk(TRACE_CRYPTO, "crypto: session key:", sk, IDEA_KEYSIZE);
+    traceblk(TRACE_CRYPTO, "crypto: initialisation vector:",
+	     iv, IDEA_BLKSIZE);
+  );
 
-  crypt__dump("Final seed", s, crypt__seedBits / 8, stdout);
+  /* --- Write the seed back --- */
 
   rewind(fp);
-  tx_putBits(s, crypt__seedBits, fp);
+  rand_write(fp);
   fclose(fp);
 
-  /* --- Destroy sensitive data --- */
-
-  burn(b); burn(s);
 }
 
 /* --- @crypt_packRequest@ --- *
@@ -265,6 +177,11 @@ void crypt_packRequest(request *rq, unsigned char *buff,
   store32(buff + crq_from, rq->from);
   store32(buff + crq_to, rq->to);
 
+  /* --- Now generate session keys and things --- */
+
+  crypt__sessionKey(file_RANDSEED, k, sk, buff + crq_iv);
+  memcpy(buff + crq_session, sk, IDEA_KEYSIZE);
+
   /* --- The string causes a few problems --- *
    *
    * There's a good chance that the string will be a good deal shorter than
@@ -282,45 +199,39 @@ void crypt_packRequest(request *rq, unsigned char *buff,
     icrypt_job j;
     unsigned char *p;
     unsigned u;
+    md5 md;
+    unsigned char qk[IDEA_KEYSIZE];
 
     /* --- Initialise the buffer with junk --- */
 
     srand((unsigned int)(t ^ pid));	/* Seed the (bad) RNG */
     for (p = buff + crq_cmd; p < buff + crq_cmd + CMDLEN_MAX; p++) {
-      u = rand();
-      *p = u ^ (u >> 8);
+      u = rand(); *p = u ^ (u >> 8);
     }
 
     /* --- Now make the junk a whole lot harder to predict --- */
 
     p = buff + crq_cmd;
-    icrypt_init(&j, p, 0);
-    icrypt_encrypt(&j, p, p, CMDLEN_MAX);
-    burn(j);
+    md5_init(&md); md5_buffer(&md, p, CMDLEN_MAX); md5_final(&md, qk);
+    icrypt_init(&j, qk, 0); icrypt_encrypt(&j, p, p, CMDLEN_MAX);
+    burn(j); burn(qk); burn(md);
 
     /* --- Copy the string into here --- */
 
     strcpy((char *)buff + crq_cmd, rq->cmd);
   }
 
-  /* --- Generate a session key --- */
-
-  {
-    crypt__sessionKey(file_RANDSEED, k, t, pid, sk, buff + crq_iv);
-    memcpy(buff + crq_session, sk, IDEA_KEYSIZE);
-  }
-
   /* --- Checksum the finished data --- */
 
   {
     md5 md;
-    unsigned char mdv[MD5_HASHSIZE];
+    unsigned char mdbuf[MD5_HASHSIZE];
 
     md5_init(&md);
     md5_buffer(&md, buff + crq_cipher, crq_check - crq_cipher);
-    md5_final(&md, mdv);
-    memcpy(buff + crq_check, mdv, 4);
-    burn(md); burn(mdv);
+    md5_final(&md, mdbuf);
+    memcpy(buff + crq_check, mdbuf, 4);
+    burn(md); burn(mdbuf);
   }
 
   /* --- Encrypt the block --- *
@@ -334,7 +245,8 @@ void crypt_packRequest(request *rq, unsigned char *buff,
   {
     icrypt_job j;
 
-    crypt__dump("request, before encryption", buff, crq_size, stdout);
+    T( traceblk(TRACE_CRYPTO, "crypto: plaintext request:",
+		buff, crq_size); )
 
     icrypt_init(&j, k, buff + crq_iv);
     icrypt_encrypt(&j, buff + crq_session, buff + crq_session, IDEA_KEYSIZE);
@@ -343,7 +255,8 @@ void crypt_packRequest(request *rq, unsigned char *buff,
 		   buff + crq_cipher, crq_size - crq_cipher);
     burn(j);
 
-    crypt__dump("request, after encryption", buff, crq_size, stdout);
+    T( traceblk(TRACE_CRYPTO, "crypto: ciphertext request:",
+		buff, crq_size); )
   }
 }
 
@@ -376,7 +289,8 @@ int crypt_unpackRequest(request *rq, unsigned char *buff,
 
     icrypt_job j;
 
-    crypt__dump("request, before decryption", buff, crq_size, stdout);
+    T( traceblk(TRACE_CRYPTO, "crypto: ciphertext request:",
+		buff, crq_size); )
 
     icrypt_init(&j, k, buff + crq_iv);
     icrypt_decrypt(&j, buff + crq_session, buff + crq_session, IDEA_KEYSIZE);
@@ -389,23 +303,25 @@ int crypt_unpackRequest(request *rq, unsigned char *buff,
     memset(buff + crq_session, 0, IDEA_KEYSIZE); /* Burn, baby, burn */
     burn(j);
 
-    crypt__dump("request, after decryption", buff, crq_size, stdout);
+    T( traceblk(TRACE_CRYPTO, "crypto: plaintext request:",
+		buff, crq_size); )
   }
 
   {
     /* --- Check the validity of the data therein --- */
 
     md5 md;
-    unsigned char mdv[MD5_HASHSIZE];
+    unsigned char mdbuf[MD5_HASHSIZE];
 
     md5_init(&md);
     md5_buffer(&md, buff + crq_cipher, crq_check - crq_cipher);
-    md5_final(&md, mdv);
-    if (memcmp(mdv, buff + crq_check, 4) != 0) {
+    md5_final(&md, mdbuf);
+    if (memcmp(mdbuf, buff + crq_check, 4) != 0) {
       syslog(LOG_INFO, "packet rejected: bad checksum");
+      T( trace(TRACE_CRYPTO, "crypto: bad checksum on incoming request"); )
       return (0);
     }
-    burn(md); burn(mdv);
+    burn(md); burn(mdbuf);
   }
 
   {
@@ -424,6 +340,7 @@ int crypt_unpackRequest(request *rq, unsigned char *buff,
 
     if (t - u > crypt__timeError || u - t > crypt__timeError) {
       syslog(LOG_INFO, "packet rejected: bad time");
+      T( trace(TRACE_CRYPTO, "crypto: bad time on incoming request"); )
       return (0);
     }
     memcpy(rpl + crp_time, buff + crq_time, 8);
@@ -431,6 +348,7 @@ int crypt_unpackRequest(request *rq, unsigned char *buff,
 
   /* --- Done --- */
 
+  T( trace(TRACE_CRYPTO, "crypto: valid request received"); )
   return (1);
 }
 
@@ -457,25 +375,28 @@ void crypt_packReply(unsigned char *buff, unsigned char *sk, int answer)
     /* --- Build the checksum --- */
 
     md5 md;
-    unsigned char mdv[MD5_HASHSIZE];
+    unsigned char mdbuf[MD5_HASHSIZE];
 
     md5_init(&md);
     md5_buffer(&md, buff + crp_cipher, crp_check - crp_cipher);
-    md5_final(&md, mdv);
-    memcpy(buff + crp_check, mdv, 4);
-    burn(md); burn(mdv);
+    md5_final(&md, mdbuf);
+    memcpy(buff + crp_check, mdbuf, 4);
+    burn(md); burn(mdbuf);
   }
 
   {
     /* --- Encrypt the buffer --- */
 
     icrypt_job j;
+
+    T( traceblk(TRACE_CRYPTO, "crypto: plaintext reply:", buff, crp_size); )
+
     icrypt_init(&j, sk, buff + crp_iv);
-    crypt__dump("reply, before encryption", buff, crp_size, stdout);
     icrypt_encrypt(&j, buff + crp_cipher,
 		   buff + crp_cipher, crp_size - crp_cipher);
-    crypt__dump("reply, after encryption", buff, crp_size, stdout);
     burn(j);
+
+    T( traceblk(TRACE_CRYPTO, "crypto: ciphertext reply:", buff, crp_size); )
   }
 }
 
@@ -498,28 +419,32 @@ int crypt_unpackReply(unsigned char *buff, unsigned char *sk,
     /* --- Decrypt my reply block --- */
 
     icrypt_job j;
+
+    T( traceblk(TRACE_CRYPTO, "crypto: ciphertext reply:", buff, crp_size); )
+
     icrypt_init(&j, sk, buff + crp_iv);
-    crypt__dump("reply, before decryption", buff, crp_size, stdout);
     icrypt_decrypt(&j, buff + crp_cipher,
 		   buff + crp_cipher, crp_size - crp_cipher);
-    crypt__dump("reply, after decryption", buff, crp_size, stdout);
     burn(j);
+
+    T( traceblk(TRACE_CRYPTO, "crypto: plaintext reply:", buff, crp_size); )
   }
 
   {
     /* --- Check validity --- */
 
     md5 md;
-    unsigned char mdv[MD5_HASHSIZE];
+    unsigned char mdbuf[MD5_HASHSIZE];
     char b[8];
 
     /* --- Check the checksum --- */
 
     md5_init(&md);
     md5_buffer(&md, buff + crp_cipher, crp_check - crp_cipher);
-    md5_final(&md, mdv);
-    if (memcmp(buff + crp_check, mdv, 4) != 0) {
+    md5_final(&md, mdbuf);
+    if (memcmp(buff + crp_check, mdbuf, 4) != 0) {
       syslog(LOG_INFO, "reply rejected: bad checksum");
+      T( trace(TRACE_CRYPTO, "crypto: bad checksum on reply"); )
       return (-1);
     }
 
@@ -528,12 +453,14 @@ int crypt_unpackReply(unsigned char *buff, unsigned char *sk,
     store32(b + 0, t); store32(b + 4, pid);
     if (memcmp(b, buff + crp_time, sizeof(b)) != 0) {
       syslog(LOG_INFO, "reply rejected: bad identification marker");
+      T( trace(TRACE_CRYPTO, "crypto: bad id on reply"); )
       return (-1);
     }
   }
 
   /* --- Return the value --- */
 
+  T( trace(TRACE_CRYPTO, "crypto: valid reply received"); )
   return (buff[crp_answer]);
 }
 
@@ -543,13 +470,12 @@ int crypt_unpackReply(unsigned char *buff, unsigned char *sk,
 
 int main(int argc, char *argv[])
 {
-  time_t t = time(0);
-  pid_t pid = getpid();
   unsigned char buff[8];
   unsigned char sk[IDEA_KEYSIZE], k[IDEA_KEYSIZE];
   FILE *fp;
 
   ego(argv[0]);
+  traceon(stdout, TRACE_CRYPTO);
   if (argc < 3)
     die("bad args");
   fp = fopen(argv[1], "r");
@@ -557,7 +483,7 @@ int main(int argc, char *argv[])
     die("fopen: %s", strerror(errno));
   tx_getBits(k, 128, fp);
   fclose(fp);
-  crypt__sessionKey(argv[2], k, t, pid, sk, buff);
+  crypt__sessionKey(argv[2], k, sk, buff);
   return (0);
 }
 
diff --git a/src/crypt.h b/src/crypt.h
index b508b45..e84f508 100644
--- a/src/crypt.h
+++ b/src/crypt.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: crypt.h,v 1.1 1997/07/21 13:47:51 mdw Exp $
+ * $Id: crypt.h,v 1.2 1997/08/04 10:24:21 mdw Exp $
  *
  * Cryptographic transfer of `become' requests
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: crypt.h,v $
- * Revision 1.1  1997/07/21 13:47:51  mdw
+ * Revision 1.2  1997/08/04 10:24:21  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:51  mdw
  * Initial revision
  *
  */
@@ -93,17 +96,6 @@ enum {
   crp_size = crp_check + 4		/* Size of encrypted reply */
 };
 
-/*----- Macros ------------------------------------------------------------*/
-
-/* --- @burn@ --- *
- *
- * Arguments:	@obj@ = some object
- *
- * Use:		Writes zero bytes over the object.
- */
-
-#define burn(obj) ((void)memset(&obj, 0, sizeof(obj)))
-
 /*----- Functions provided ------------------------------------------------*/
 
 /* --- @crypt_packRequest@ --- *
diff --git a/src/daemon.c b/src/daemon.c
index eb36b39..3f1fa93 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: daemon.c,v 1.1 1997/07/21 13:47:50 mdw Exp $
+ * $Id: daemon.c,v 1.2 1997/08/04 10:24:21 mdw Exp $
  *
  * Running a `become' daemon
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: daemon.c,v $
- * Revision 1.1  1997/07/21 13:47:50  mdw
+ * Revision 1.2  1997/08/04 10:24:21  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:50  mdw
  * Initial revision
  *
  */
@@ -152,6 +155,7 @@ static int daemon__readConfig(const char *cf)
   if (!daemon__readKey)
     daemon_readKey(file_KEY);
   daemon__rescan = 0;
+  T( trace(TRACE_DAEMON, "daemon: read config file"); )
   return (0);
 }
 
@@ -210,6 +214,8 @@ void daemon__read(int fd)
 
     if (recvfrom(fd, (char *)buff, sizeof(buff), 0,
 		 (struct sockaddr *)&sin, &slen) < 0) {
+      T( trace(TRACE_DAEMON, "daemon: error reading packet: %s",
+	       strerror(errno)); )
       syslog(LOG_INFO, "duff packet received: %e");
       return;
     }
@@ -226,12 +232,14 @@ void daemon__read(int fd)
 	    he ? he->h_name : inet_ntoa(sin.sin_addr),
 	    sizeof(sender));
     syslog(LOG_DEBUG, "packet received from %s", sender);
+    T( trace(TRACE_DAEMON, "daemon: received request from %s", sender); )
   }
 
   /* --- Unpack the block --- */
 
   if (crypt_unpackRequest(&rq, buff, daemon__key, sk, rpl) == 0) {
     burn(buff);
+    T( trace(TRACE_DAEMON, "daemon: received corrupt or invalid request"); )
     syslog(LOG_INFO, "packet from %s rejected", sender);
     return;
   }
@@ -254,6 +262,7 @@ void daemon__read(int fd)
   /* --- Send the reply off --- */
 
   sendto(fd, (char *)rpl, crp_size, 0, (struct sockaddr *)&sin, sizeof(sin));
+  T( trace(TRACE_DAEMON, "daemon: reply sent"); )
   burn(rpl);
 }
 
@@ -345,26 +354,38 @@ void daemon_init(const char *cf, int port)
       fprintf(fp, "%lu\n", (unsigned long)getpid());
       fclose(fp);
     }
+    T( trace(TRACE_DAEMON, "daemon: forked to pid %li", (long)getpid()); )
   }
 #endif
 
   /* --- Program in daemon death mode --- */
 
   if (setjmp(daemon__dieBuf)) {
-    syslog(LOG_NOTICE, "killed by signal type %i", daemon__signum);
-    remove(file_PID);
-    exit(0);
-  }
+#ifdef TRACING
+    if (daemon__signum == SIGQUIT && tracing() & TRACE_RULE) {
+      T( rule_dump(); )
+      signal(SIGQUIT, daemon__die);
+    } else
+#endif
+    {
+      T( trace(TRACE_DAEMON, "daemon: killed by signal %i",
+	       daemon__signum); )
+      syslog(LOG_NOTICE, "killed by signal type %i", daemon__signum);
+      remove(file_PID);
+      exit(0);
+    }
+  } else {
 
-  /* --- Set signal handlers --- */
+    /* --- Set signal handlers --- */
 
-  signal(SIGHUP, daemon__restart);
-  signal(SIGQUIT, daemon__restart);
-  signal(SIGINT, daemon__die);
-  signal(SIGTERM, daemon__die);
-  signal(SIGSEGV, daemon__die);
-  signal(SIGFPE, daemon__die);
-  signal(SIGBUS, daemon__die);
+    signal(SIGHUP, daemon__restart);
+    signal(SIGQUIT, daemon__die);
+    signal(SIGINT, daemon__die);
+    signal(SIGTERM, daemon__die);
+    signal(SIGSEGV, daemon__die);
+    signal(SIGFPE, daemon__die);
+    signal(SIGBUS, daemon__die);
+  }
 
   /* --- Now wait for something exciting to happen --- *
    *
@@ -391,6 +412,7 @@ void daemon_init(const char *cf, int port)
 
       /* --- Now wait for something interesting --- */
 
+      T( trace(TRACE_DAEMON, "daemon: waiting for requests"); )
       i = select(FD_SETSIZE, &fds, 0, 0, 0);
 
       /* --- Now, see if I need to rescan the config --- */
diff --git a/src/daemon.h b/src/daemon.h
index ed3c05c..a1b1eef 100644
--- a/src/daemon.h
+++ b/src/daemon.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: daemon.h,v 1.1 1997/07/21 13:47:50 mdw Exp $
+ * $Id: daemon.h,v 1.2 1997/08/04 10:24:21 mdw Exp $
  *
  * Running a `become' daemon
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: daemon.h,v $
- * Revision 1.1  1997/07/21 13:47:50  mdw
+ * Revision 1.2  1997/08/04 10:24:21  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:50  mdw
  * Initial revision
  *
  */
diff --git a/src/dbutils.h b/src/dbutils.h
index 70f24ee..89dff81 100644
--- a/src/dbutils.h
+++ b/src/dbutils.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: dbutils.h,v 1.1 1997/07/21 13:47:50 mdw Exp $
+ * $Id: dbutils.h,v 1.2 1997/08/04 10:24:22 mdw Exp $
  *
  * Debugging things
  *
@@ -29,7 +29,10 @@
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: dbutils.h,v $
- * Revision 1.1  1997/07/21 13:47:50  mdw
+ * Revision 1.2  1997/08/04 10:24:22  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:50  mdw
  * Initial revision
  *
  */
diff --git a/src/icrypt.c b/src/icrypt.c
index 828ce1e..589c5a5 100644
--- a/src/icrypt.c
+++ b/src/icrypt.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: icrypt.c,v 1.1 1997/07/21 13:47:49 mdw Exp $
+ * $Id: icrypt.c,v 1.2 1997/08/04 10:24:22 mdw Exp $
  *
  * Higher level IDEA encryption
  *
  * (c) 1997 Mark Wooding
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: icrypt.c,v $
- * Revision 1.1  1997/07/21 13:47:49  mdw
+ * Revision 1.2  1997/08/04 10:24:22  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:49  mdw
  * Initial revision
  *
  */
@@ -285,12 +288,13 @@ int main(int argc, char *argv[])
 
   {
     char *pass = getpass("Password: ");
+    unsigned char k[IDEA_KEYSIZE];
     md5_init(&md);
     md5_buffer(&md, pass, strlen(pass));
     memset(pass, 0, strlen(pass));
-    md5_final(&md);
+    md5_final(&md, k);
 
-    icrypt_init(&j, md.val, 0);
+    icrypt_init(&j, k, 0);
   }
 
   if (optind >= argc)
diff --git a/src/icrypt.h b/src/icrypt.h
index 38deed9..2117814 100644
--- a/src/icrypt.h
+++ b/src/icrypt.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: icrypt.h,v 1.1 1997/07/21 13:47:49 mdw Exp $
+ * $Id: icrypt.h,v 1.2 1997/08/04 10:24:22 mdw Exp $
  *
  * Higher level IDEA encryption
  *
  * (c) 1997 Mark Wooding
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: icrypt.h,v $
- * Revision 1.1  1997/07/21 13:47:49  mdw
+ * Revision 1.2  1997/08/04 10:24:22  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:49  mdw
  * Initial revision
  *
  */
diff --git a/src/idea.c b/src/idea.c
index e1bacfe..1bdd9e8 100644
--- a/src/idea.c
+++ b/src/idea.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: idea.c,v 1.1 1997/07/21 13:47:49 mdw Exp $
+ * $Id: idea.c,v 1.2 1997/08/04 10:24:22 mdw Exp $
  *
  * IDEA encryption routines
  *  Based on Straylight ARM assembler routines
@@ -8,7 +8,7 @@
  * (c) 1996, 1997 Mark Wooding
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -23,14 +23,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: idea.c,v $
- * Revision 1.1  1997/07/21 13:47:49  mdw
+ * Revision 1.2  1997/08/04 10:24:22  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:49  mdw
  * Initial revision
  *
  */
@@ -48,6 +51,7 @@
 /*----- Header files ------------------------------------------------------*/
 
 #include <stdio.h>
+#include <string.h>
 
 #include "config.h"
 #include "idea.h"
diff --git a/src/idea.h b/src/idea.h
index 79ca601..08e7f93 100644
--- a/src/idea.h
+++ b/src/idea.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: idea.h,v 1.1 1997/07/21 13:47:48 mdw Exp $
+ * $Id: idea.h,v 1.2 1997/08/04 10:24:22 mdw Exp $
  *
  * IDEA encryption routines
  *  Based on Straylight ARM assembler routines
@@ -8,7 +8,7 @@
  * (c) 1996, 1997 Mark Wooding
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -23,14 +23,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: idea.h,v $
- * Revision 1.1  1997/07/21 13:47:48  mdw
+ * Revision 1.2  1997/08/04 10:24:22  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:48  mdw
  * Initial revision
  *
  */
diff --git a/src/keygen.c b/src/keygen.c
index 17bf93c..f1b0abe 100644
--- a/src/keygen.c
+++ b/src/keygen.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: keygen.c,v 1.1 1997/07/21 13:47:48 mdw Exp $
+ * $Id: keygen.c,v 1.2 1997/08/04 10:24:23 mdw Exp $
  *
  * Key generation
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: keygen.c,v $
- * Revision 1.1  1997/07/21 13:47:48  mdw
+ * Revision 1.2  1997/08/04 10:24:23  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:48  mdw
  * Initial revision
  *
  */
@@ -245,9 +248,9 @@ static void kg__gen(unsigned char *ui, size_t sz)
   unsigned long fact = 1000000 / CLOCKS_PER_SEC;
 
   fprintf(kg__ttyfp,
-"I need to get %i random bits; I'll do this by timing your keypresses.\n"
+"I need to get %lu random bits; I'll do this by timing your keypresses.\n"
 "Please type some arbitrary text until I say `done'.\n",
-	  sz);
+	  (unsigned long)sz);
 
   {
     struct timeval tv;
@@ -261,7 +264,7 @@ static void kg__gen(unsigned char *ui, size_t sz)
 
     /* --- Print current status --- */
 
-    fprintf(kg__ttyfp, "\r%5i...", sz);
+    fprintf(kg__ttyfp, "\r%5lu...", (unsigned long)sz);
     fflush(kg__ttyfp);
 
     /* --- Read the next character --- */
diff --git a/src/lexer.h b/src/lexer.h
index 603d382..c3bbc65 100644
--- a/src/lexer.h
+++ b/src/lexer.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: lexer.h,v 1.1 1997/07/21 13:47:48 mdw Exp $
+ * $Id: lexer.h,v 1.2 1997/08/04 10:24:23 mdw Exp $
  *
  * Lexical analyser for `become.conf' files
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: lexer.h,v $
- * Revision 1.1  1997/07/21 13:47:48  mdw
+ * Revision 1.2  1997/08/04 10:24:23  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:48  mdw
  * Initial revision
  *
  */
diff --git a/src/lexer.l b/src/lexer.l
index 597690a..ccaff7e 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: lexer.l,v 1.1 1997/07/21 13:47:48 mdw Exp $
+ * $Id: lexer.l,v 1.2 1997/08/04 10:24:23 mdw Exp $
  *
  * Lexical analyser for `become.conf' files
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: lexer.l,v $
- * Revision 1.1  1997/07/21 13:47:48  mdw
+ * Revision 1.2  1997/08/04 10:24:23  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:48  mdw
  * Initial revision
  *
  */
diff --git a/src/md5.c b/src/md5.c
index 80cadf2..23ce693 100644
--- a/src/md5.c
+++ b/src/md5.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: md5.c,v 1.1 1997/07/21 13:47:47 mdw Exp $
+ * $Id: md5.c,v 1.2 1997/08/04 10:24:23 mdw Exp $
  *
  * MD-5 secure hash routines
  *  Based on RSA MD-5 code
@@ -8,7 +8,7 @@
  * (c) 1996, 1997 Mark Wooding
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -23,14 +23,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: md5.c,v $
- * Revision 1.1  1997/07/21 13:47:47  mdw
+ * Revision 1.2  1997/08/04 10:24:23  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:47  mdw
  * Initial revision
  *
  */
diff --git a/src/md5.h b/src/md5.h
index a105630..bce4d47 100644
--- a/src/md5.h
+++ b/src/md5.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: md5.h,v 1.1 1997/07/21 13:47:47 mdw Exp $
+ * $Id: md5.h,v 1.2 1997/08/04 10:24:23 mdw Exp $
  *
  * MD-5 secure hash routines
  *  Based on RSA MD-5 code
@@ -8,7 +8,7 @@
  * (c) 1996, 1997 Mark Wooding
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -23,14 +23,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: md5.h,v $
- * Revision 1.1  1997/07/21 13:47:47  mdw
+ * Revision 1.2  1997/08/04 10:24:23  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:47  mdw
  * Initial revision
  *
  */
diff --git a/src/mdwopt.c b/src/mdwopt.c
index af30491..ad078a5 100644
--- a/src/mdwopt.c
+++ b/src/mdwopt.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: mdwopt.c,v 1.1 1997/07/21 13:47:47 mdw Exp $
+ * $Id: mdwopt.c,v 1.2 1997/08/04 10:24:23 mdw Exp $
  *
  * Options parsing, similar to GNU @getopt_long@
  *
@@ -22,15 +22,20 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `mdwopt'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `mdwopt'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: mdwopt.c,v $
- * Revision 1.1  1997/07/21 13:47:47  mdw
- * Initial revision
+ * Revision 1.2  1997/08/04 10:24:23  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.4  1997/07/29 21:11:35  mdw
+ * Reformatted.  Fixed buffer overflow when dealing with environment
+ * variables.  Included NT in list of daft operating systems with `\' as a
+ * path separator.  Fixed address of the FSF.
  *
  * Revision 1.3  1997/02/26 00:41:10  mdw
  * Added GPL notice to the top.  Slight formatting changes.
@@ -57,7 +62,7 @@
 
 #if defined(__riscos)
 #  define PATHSEP '.'
-#elif defined(__OS2__) || defined(__MSDOS__)
+#elif defined(__OS2__) || defined(__MSDOS__) || defined(__WINNT__)
 #  define PATHSEP '\\'
 #else /* Assume a sane filing system */
 #  define PATHSEP '/'
diff --git a/src/mdwopt.h b/src/mdwopt.h
index 38e89e4..78087d6 100644
--- a/src/mdwopt.h
+++ b/src/mdwopt.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: mdwopt.h,v 1.1 1997/07/21 13:47:47 mdw Exp $
+ * $Id: mdwopt.h,v 1.2 1997/08/04 10:24:24 mdw Exp $
  *
  * Options parsing, similar to GNU @getopt_long@
  *
@@ -22,19 +22,18 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `mdwopt'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `mdwopt'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: mdwopt.h,v $
- * Revision 1.1  1997/07/21 13:47:47  mdw
- * Initial revision
+ * Revision 1.2  1997/08/04 10:24:24  mdw
+ * Sources placed under CVS control.
  *
- * Revision 1.4  1997/02/26 00:39:55  mdw
- * Added GPL notice to the top.  Slight formatting changes.  Commented out
- * arguments to functions.
+ * Revision 1.4  1997/07/29 21:11:49  mdw
+ * Fixed address of the FSF.
  *
  * Revision 1.3  1996/12/31 19:41:33  mdw
  * Formatting changes.
diff --git a/src/name.c b/src/name.c
index faa06ab..fe61272 100644
--- a/src/name.c
+++ b/src/name.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: name.c,v 1.1 1997/07/21 13:47:46 mdw Exp $
+ * $Id: name.c,v 1.2 1997/08/04 10:24:24 mdw Exp $
  *
  * Looking up of names in symbol tables
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: name.c,v $
- * Revision 1.1  1997/07/21 13:47:46  mdw
+ * Revision 1.2  1997/08/04 10:24:24  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:46  mdw
  * Initial revision
  *
  */
@@ -44,11 +47,19 @@
 
 /* --- Unix headers --- */
 
+#include "config.h"
+
+#ifdef HAVE_YP
+#  include <rpcsvc/ypclnt.h>
+#  include <rpcsvc/yp_prot.h>
+#endif
+
 #include <grp.h>
 #include <pwd.h>
 
 /* --- Local headers --- */
 
+#include "become.h"
 #include "class.h"
 #include "name.h"
 #include "sym.h"
@@ -61,87 +72,113 @@ static sym_table name__table;		/* Symbol table for everything */
 
 /*----- Main code ---------------------------------------------------------*/
 
-/* --- @name_init@ --- *
+/* --- @name__users@ --- *
  *
  * Arguments:	---
  *
  * Returns:	---
  *
- * Use:		Initialises the name table.  Requires the user database to
- *		be populated (see @userdb_local@ and @userdb_yp@).
+ * Use:		Adds all of the users registered with the user database to
+ *		the name table.  Also adds the users' primary groups.
  */
 
-void name_init(void)
+static void name__users(void)
 {
-  /* --- Initialise the name table --- */
-
-  sym_createTable(&name__table);
+  struct passwd *pw;
+  struct group *gr;
 
-  /* --- Insert all the users and groups into the table --- */
+  userdb_iterateUsers();
+  while ((pw = userdb_nextUser()) != 0) {
+    unsigned f;
+    name *n;
+    int u;
 
-  {
-    struct passwd *pw;
-    struct group *gr;
+    /* --- First, add the user to the table --- */
 
-    userdb_iterateUsers();
-    while ((pw = userdb_nextUser()) != 0) {
-      unsigned f;
-      name *n;
-      int u;
+    n = sym_find(&name__table, pw->pw_name, -1, sizeof(name), &f);
+    if (!f) {
+      sym_table *t = xmalloc(sizeof(*t));
+      sym_createTable(t);
+      n->c = class_create(clType_user, t);
+    }
+    u = pw->pw_uid;
+    sym_find(n->c->t, (char *)&u, sizeof(u), sizeof(sym_base), 0);
 
-      /* --- First, add the user to the table --- */
+    /* --- Now handle the user's default group --- */
 
-      n = sym_find(&name__table, pw->pw_name, -1, sizeof(name), &f);
+    if ((gr = userdb_groupById(pw->pw_gid)) != 0) {
+      n = sym_find(&name__table, gr->gr_name, -1, sizeof(name), &f);
       if (!f) {
 	sym_table *t = xmalloc(sizeof(*t));
 	sym_createTable(t);
 	n->c = class_create(clType_user, t);
       }
-      u = pw->pw_uid;
       sym_find(n->c->t, (char *)&u, sizeof(u), sizeof(sym_base), 0);
+    }
+  }
+}
 
-      /* --- Now handle the user's default group --- */
+/* --- @name__groups@ --- *
+ *
+ * Arguments:	---
+ *
+ * Returns:	---
+ *
+ * Use:		Adds users into all of their supplementary groups.
+ */
+
+static void name__groups(void)
+{
+  struct group *gr;
+  struct passwd *pw;
+  char **p;
+
+  userdb_iterateGroups();
+  while ((gr = userdb_nextGroup()) != 0) {
+    unsigned f;
+    name *n;
+    int u;
 
-      if ((gr = userdb_groupById(pw->pw_gid)) != 0) {
-	n = sym_find(&name__table, gr->gr_name, -1, sizeof(name), &f);
-	if (!f) {
-	  sym_table *t = xmalloc(sizeof(*t));
-	  sym_createTable(t);
-	  n->c = class_create(clType_user, t);
-	}
+    /* --- Add the group name to the table --- */
+
+    n = sym_find(&name__table, gr->gr_name, -1, sizeof(name), &f);
+    if (!f) {
+      sym_table *t = xmalloc(sizeof(*t));
+      sym_createTable(t);
+      n->c = class_create(clType_user, t);
+    }
+
+    /* --- Now add all of the members --- */
+
+    for (p = gr->gr_mem; *p; p++) {
+      if ((pw = userdb_userByName(*p)) != 0) {
+	u = pw->pw_uid;
 	sym_find(n->c->t, (char *)&u, sizeof(u), sizeof(sym_base), 0);
       }
     }
   }
+}
 
-  /* --- Now get the subsidiary groups --- */
+/* --- @name_init@ --- *
+ *
+ * Arguments:	---
+ *
+ * Returns:	---
+ *
+ * Use:		Initialises the name table.  Requires the user database to
+ *		be populated (see @userdb_local@ and @userdb_yp@).
+ */
 
-  {
-    struct group *gr;
-    struct passwd *pw;
-    char **p;
+void name_init(void)
+{
+  /* --- Initialise the name table --- */
 
-    userdb_iterateGroups();
-    while ((gr = userdb_nextGroup()) != 0) {
-      unsigned f;
-      name *n;
-      int u;
+  sym_createTable(&name__table);
 
-      n = sym_find(&name__table, gr->gr_name, -1, sizeof(name), &f);
-      if (!f) {
-	sym_table *t = xmalloc(sizeof(*t));
-	sym_createTable(t);
-	n->c = class_create(clType_user, t);
-      }
+  /* --- Add everyone into the table --- */
 
-      for (p = gr->gr_mem; *p; p++) {
-	if ((pw = userdb_userByName(*p)) != 0) {
-	  u = pw->pw_uid;
-	  sym_find(n->c->t, (char *)&u, sizeof(u), sizeof(sym_base), 0);
-	}
-      }
-    }
-  }
+  name__users();
+  name__groups();
 
   /* --- Finally add in the `all' class --- *
    *
@@ -213,21 +250,22 @@ name *name_find(const char *p, unsigned create, unsigned *f)
 
 /* --- @name_dump@ --- *
  *
- * Arguments:	@FILE *fp@ = stream to dump on
+ * Arguments:	---
  *
  * Returns:	---
  *
  * Use:		Dumps a complete listing of the symbol table.
  */
 
-void name_dump(FILE *fp)
+void name_dump(void)
 {
   sym_iter i;
   name *n;
 
+  trace(TRACE_DEBUG, "name: dumping names");
   for (sym_createIter(&i, &name__table); (n = sym_next(&i)) != 0; ) {
-    fprintf(fp, "\n--- name `%s'\n", n->base.name);
-    class_dump(n->c, fp);
+    trace(TRACE_DEBUG, "name: dumping `%s'", n->base.name);
+    class_dump(n->c);
   }
 }  
 
@@ -240,8 +278,10 @@ int main(void)
   userdb_init();
   userdb_local();
   userdb_yp();
+  ego("name-test");
+  traceon(stdout, TRACE_DEBUG);
   name_init();
-  name_dump(stdout);
+  name_dump();
   return (0);
 }
 
diff --git a/src/name.h b/src/name.h
index 8d94ed5..93793c9 100644
--- a/src/name.h
+++ b/src/name.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: name.h,v 1.1 1997/07/21 13:47:46 mdw Exp $
+ * $Id: name.h,v 1.2 1997/08/04 10:24:24 mdw Exp $
  *
  * Looking up of names in symbol tables
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: name.h,v $
- * Revision 1.1  1997/07/21 13:47:46  mdw
+ * Revision 1.2  1997/08/04 10:24:24  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:46  mdw
  * Initial revision
  *
  */
@@ -105,14 +108,14 @@ extern name *name_find(const char */*p*/,
 
 /* --- @name_dump@ --- *
  *
- * Arguments:	@FILE *fp@ = stream to dump on
+ * Arguments:	---
  *
  * Returns:	---
  *
  * Use:		Dumps a complete listing of the symbol table.
  */
 
-extern void name_dump(FILE */*fp*/);
+extern void name_dump(void);
 
 /*----- That's all, folks -------------------------------------------------*/
 
diff --git a/src/parser.h b/src/parser.h
index cd64a67..db09482 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: parser.h,v 1.1 1997/07/21 13:47:46 mdw Exp $
+ * $Id: parser.h,v 1.2 1997/08/04 10:24:24 mdw Exp $
  *
  * Parser for `become.conf' files
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: parser.h,v $
- * Revision 1.1  1997/07/21 13:47:46  mdw
+ * Revision 1.2  1997/08/04 10:24:24  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:46  mdw
  * Initial revision
  *
  */
diff --git a/src/parser.y b/src/parser.y
index 0a8462f..688ffc4 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: parser.y,v 1.1 1997/07/21 13:47:45 mdw Exp $
+ * $Id: parser.y,v 1.2 1997/08/04 10:24:24 mdw Exp $
  *
  * Parser for `become.conf' files
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: parser.y,v $
- * Revision 1.1  1997/07/21 13:47:45  mdw
+ * Revision 1.2  1997/08/04 10:24:24  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:45  mdw
  * Initial revision
  *
  */
diff --git a/src/rule.c b/src/rule.c
index 000c290..41fa371 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: rule.c,v 1.1 1997/07/21 13:47:45 mdw Exp $
+ * $Id: rule.c,v 1.2 1997/08/04 10:24:25 mdw Exp $
  *
  * Managing rule sets
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: rule.c,v $
- * Revision 1.1  1997/07/21 13:47:45  mdw
+ * Revision 1.2  1997/08/04 10:24:25  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:45  mdw
  * Initial revision
  *
  */
@@ -42,11 +45,21 @@
 #include <stdlib.h>
 #include <string.h>
 
+/* --- Unix headers --- */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+
 /* --- Local headers --- */
 
 #include "become.h"
 #include "class.h"
 #include "rule.h"
+#include "userdb.h"
 #include "utils.h"
 
 /*----- Type definitions --------------------------------------------------*/
@@ -142,17 +155,77 @@ void rule_add(classdef *host, classdef *from, classdef *to, classdef *cmd)
 
 int rule_check(request *r)
 {
-  rule *rr = rule__list;
+  rule *rr;
+
+  /* --- Trace out the request we're checking --- */
+
+  IF_TRACING(TRACE_CHECK, {
+    struct passwd *pw_from = userdb_userById(r->from);
+    struct passwd *pw_to = userdb_userById(r->to);
+    struct hostent *h = gethostbyaddr((char *)&r->host, sizeof(r->host),
+				      AF_INET);
+
+    trace(TRACE_CHECK, "check: request from %s (%li) to become %s (%li)",
+	  pw_from ? pw_from->pw_name : "<unknown>", (long)r->from,
+	  pw_to ? pw_to->pw_name : "<unknown>", (long)r->to);
+    trace(TRACE_CHECK, "check: ... at %s (%s) for `%s'",
+	  h ? h->h_name : "<unknown>", inet_ntoa(r->host), r->cmd);
+  })
+
+  /* --- Search the rule list --- */
+
+  for (rr = rule__list; rr; rr = rr->next) {
+
+    /* --- Trace out the rule --- */
+
+    IF_TRACING(TRACE_RULE, {
+      trace(TRACE_RULE, "rule: check against rule...");
+      trace(TRACE_RULE, "  from"); class_dump(rr->from);
+      trace(TRACE_RULE, "  to"); class_dump(rr->to);
+      trace(TRACE_RULE, "  cmd"); class_dump(rr->cmd);
+      trace(TRACE_RULE, "  host"); class_dump(rr->host);
+    })
+
+    /* --- Check the rule --- */
 
-  while (rr) {
     if (class_userMatch(rr->from, r->from) &&
 	class_userMatch(rr->to, r->to) &&
 	class_commandMatch(rr->cmd, r->cmd) &&
-	class_hostMatch(rr->host, r->host))
+	class_hostMatch(rr->host, r->host)) {
+      T( trace(TRACE_CHECK, "check: rule matched -- granting permission"); )
       return (1);
-    rr = rr->next;
+    }
   }
+
+  /* --- Failed to match --- */
+
+  T( trace(TRACE_CHECK, "check: no rules matched -- permission denied"); )
   return (0);
 }
 
+/* --- @rule_dump@ --- *
+ *
+ * Arguments:	---
+ *
+ * Returns:	---
+ *
+ * Use:		Dumps a map of the current ruleset to the trace output.
+ */
+
+void rule_dump(void)
+{
+  rule *rr = rule__list;
+
+  trace(TRACE_RULE, "rule: dumping rules");
+  while (rr) {
+    trace(TRACE_RULE, "rule dump...");
+    trace(TRACE_RULE, "  from"); class_dump(rr->from);
+    trace(TRACE_RULE, "  to"); class_dump(rr->to);
+    trace(TRACE_RULE, "  cmd"); class_dump(rr->cmd);
+    trace(TRACE_RULE, "  host"); class_dump(rr->host);
+    rr = rr->next;
+  }
+  trace(TRACE_RULE, "rule: dump finished");
+}
+
 /*----- That's all, folks -------------------------------------------------*/
diff --git a/src/rule.h b/src/rule.h
index 7e337f6..8ce7ea2 100644
--- a/src/rule.h
+++ b/src/rule.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: rule.h,v 1.1 1997/07/21 13:47:45 mdw Exp $
+ * $Id: rule.h,v 1.2 1997/08/04 10:24:25 mdw Exp $
  *
  * Managing rule sets
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: rule.h,v $
- * Revision 1.1  1997/07/21 13:47:45  mdw
+ * Revision 1.2  1997/08/04 10:24:25  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:45  mdw
  * Initial revision
  *
  */
@@ -106,6 +109,17 @@ extern void rule_add(classdef */*host*/, classdef */*from*/,
 
 extern int rule_check(request */*r*/);
 
+/* --- @rule_dump@ --- *
+ *
+ * Arguments:	---
+ *
+ * Returns:	---
+ *
+ * Use:		Dumps a map of the current ruleset to the trace output.
+ */
+
+extern void rule_dump(void);
+
 /*----- That's all, folks -------------------------------------------------*/
 
 #ifdef __cplusplus
diff --git a/src/set.c b/src/set.c
index 7c36bb7..75a7a72 100644
--- a/src/set.c
+++ b/src/set.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: set.c,v 1.1 1997/07/21 13:47:44 mdw Exp $
+ * $Id: set.c,v 1.2 1997/08/04 10:24:25 mdw Exp $
  *
  * Management of sets (for the use of the class expression handler)
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: set.c,v $
- * Revision 1.1  1997/07/21 13:47:44  mdw
+ * Revision 1.2  1997/08/04 10:24:25  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:44  mdw
  * Initial revision
  *
  */
diff --git a/src/set.h b/src/set.h
index 62b15c5..2620426 100644
--- a/src/set.h
+++ b/src/set.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: set.h,v 1.1 1997/07/21 13:47:44 mdw Exp $
+ * $Id: set.h,v 1.2 1997/08/04 10:24:25 mdw Exp $
  *
  * Management of sets (for the use of the class expression handler)
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: set.h,v $
- * Revision 1.1  1997/07/21 13:47:44  mdw
+ * Revision 1.2  1997/08/04 10:24:25  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:44  mdw
  * Initial revision
  *
  */
diff --git a/src/sym.c b/src/sym.c
index d882f5f..a698382 100644
--- a/src/sym.c
+++ b/src/sym.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: sym.c,v 1.1 1997/07/21 13:47:44 mdw Exp $
+ * $Id: sym.c,v 1.2 1997/08/04 10:24:25 mdw Exp $
  *
  * Symbol table management
  *
  * (c) 1996 Straylight
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: sym.c,v $
- * Revision 1.1  1997/07/21 13:47:44  mdw
+ * Revision 1.2  1997/08/04 10:24:25  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:44  mdw
  * Initial revision
  *
  */
@@ -575,7 +578,10 @@ int main(void)
       case 0: {
 	sym_word *w;
 
-	printf("find `%s'\n", line[i]);
+	/* printf("find `%s'\n", line[i]); */
+	if ((rand() & 1023) == 0) {
+	  putchar('.'); fflush(stdout);
+	}
 
 	w = sym_find(&tbl, line[i], -1, 0, 0);
 	if (w != flag[i])
@@ -590,7 +596,10 @@ int main(void)
 	unsigned f;
 	sym_word *w;
 
-	printf("create `%s'\n", line[i]);
+	/* printf("create `%s'\n", line[i]); */
+	if ((rand() & 1023) == 0) {
+	  putchar('+'); fflush(stdout);
+	}
 
 	w = sym_find(&tbl, line[i], -1, sizeof(sym_word), &f);
 	if (f)
@@ -618,6 +627,11 @@ int main(void)
       case 2: {
 	sym_iter it;
 	sym_word *w, **ntbl;
+	int v = (rand() % entries) == 0;
+	if (!v)
+	  break;
+	printf("\niterated %i entries\n", entries);
+	break;
 
 	printf("iterate\n");
 
@@ -641,6 +655,7 @@ int main(void)
       case 3: {
 	sym_base *b;
 	int v = rand() & 255 ? 0 : 1;
+	break;
 
 	printf("dump\n");
 
@@ -663,7 +678,10 @@ int main(void)
 
       case 4: {
 	if (flag[i]) {
-	  printf("remove `%s'\n", flag[i]->base.name);
+	  /* printf("remove `%s'\n", flag[i]->base.name); */
+	  if ((rand() & 1023) == 0) {
+	    putchar('-'); fflush(stdout);
+	  }
 	  sym_remove(&tbl, flag[i]);
 	  flag[i] = 0;
 	  entries--;
diff --git a/src/sym.h b/src/sym.h
index 8f708e1..16511af 100644
--- a/src/sym.h
+++ b/src/sym.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: sym.h,v 1.1 1997/07/21 13:47:43 mdw Exp $
+ * $Id: sym.h,v 1.2 1997/08/04 10:24:25 mdw Exp $
  *
  * Symbol table management
  *
  * (c) 1996 Straylight
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: sym.h,v $
- * Revision 1.1  1997/07/21 13:47:43  mdw
+ * Revision 1.2  1997/08/04 10:24:25  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:43  mdw
  * Initial revision
  *
  */
diff --git a/src/tx.c b/src/tx.c
index b17456a..54a04f4 100644
--- a/src/tx.c
+++ b/src/tx.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: tx.c,v 1.1 1997/07/21 13:47:43 mdw Exp $
+ * $Id: tx.c,v 1.2 1997/08/04 10:24:25 mdw Exp $
  *
  * Transfer for keys and other large integers
  *
  * (c) 1997 Mark Wooding
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: tx.c,v $
- * Revision 1.1  1997/07/21 13:47:43  mdw
+ * Revision 1.2  1997/08/04 10:24:25  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:43  mdw
  * Initial revision
  *
  */
diff --git a/src/tx.h b/src/tx.h
index 4aaaaee..d5fef73 100644
--- a/src/tx.h
+++ b/src/tx.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: tx.h,v 1.1 1997/07/21 13:47:43 mdw Exp $
+ * $Id: tx.h,v 1.2 1997/08/04 10:24:26 mdw Exp $
  *
  * Transfer for keys and other large integers
  *
  * (c) 1997 Mark Wooding
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: tx.h,v $
- * Revision 1.1  1997/07/21 13:47:43  mdw
+ * Revision 1.2  1997/08/04 10:24:26  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:43  mdw
  * Initial revision
  *
  */
diff --git a/src/userdb.c b/src/userdb.c
index bcefc85..77e1a3d 100644
--- a/src/userdb.c
+++ b/src/userdb.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: userdb.c,v 1.1 1997/07/21 13:47:43 mdw Exp $
+ * $Id: userdb.c,v 1.2 1997/08/04 10:24:26 mdw Exp $
  *
  * User database management
  *
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: userdb.c,v $
- * Revision 1.1  1997/07/21 13:47:43  mdw
+ * Revision 1.2  1997/08/04 10:24:26  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:43  mdw
  * Initial revision
  *
  */
@@ -46,15 +49,21 @@
 
 /* --- Unix headers --- */
 
+#include "config.h"
+
 #include <sys/types.h>
 
+#ifdef HAVE_YP
+#  include <rpcsvc/ypclnt.h>
+#  include <rpcsvc/yp_prot.h>
+#endif
+
 #include <grp.h>
 #include <pwd.h>
 #include <unistd.h>
 
 /* --- Local headers --- */
 
-#include "config.h"
 #include "sym.h"
 #include "userdb.h"
 #include "utils.h"
@@ -486,137 +495,7 @@ void userdb_freeGroup(void *rec)
   free(gr);
 } 
 
-/*----- Higher-level functions --------------------------------------------*/
-
-/* --- @userdb_local@ --- *
- *
- * Arguments:	---
- *
- * Returns:	---
- *
- * Use:		Reads the local list of users into the maps.
- */
-
-void userdb_local(void)
-{
-  D( printf("adding local users...\n"); )
-
-  /* --- Fetch users first --- */
-
-  {
-    struct passwd *pw;
-
-    setpwent();
-    while ((pw = getpwent()) != 0) {
-      D( userdb__dumpUser(pw, stdout); )
-      if (!userdb__byName(&userdb__users, pw->pw_name))
-	userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid,
-			 userdb_copyUser(pw));
-    }
-    endpwent();
-  }
-
-  /* --- Then fetch groups --- */
-
-  {
-    struct group *gr;
-
-    setgrent();
-    while ((gr = getgrent()) != 0) {
-      D( userdb__dumpGroup(gr, stdout); )
-      if (!userdb__byName(&userdb__groups, gr->gr_name))
-	userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid,
-			 userdb_copyGroup(gr));
-    }
-    endgrent();
-  }
-}
-
-/* --- @userdb__getLine@ --- *
- *
- * Arguments:	@char *buff@ = pointer to buffer to read into
- *		@size_t sz@ = size of the buffer
- *		@FILE *fp@ = pointer to stream to read on
- *
- * Returns:	Zero if something didn't work.
- *
- * Use:		Reads a line into the buffer.  If the line didn't fit, bits
- *		of it are thrown away.  The newline character is not
- *		included.
- */
-
-static char *userdb__getLine(char *buff, size_t sz, FILE *fp)
-{
-  if ((buff = fgets(buff, sz, fp)) == 0)
-    return (0);
-  sz = strlen(buff) - 1;
-  if (buff[sz] == '\n')
-    buff[sz] = 0;
-  else for (;;) {
-    int ch = getc(fp);
-    if (ch == '\n' || ch == EOF)
-      break;
-  }
-  return (buff);
-}
-  
-/* --- @userdb_yp@ --- *
- *
- * Arguments:	---
- *
- * Returns:	---
- *
- * Use:		Fetches the YP database of users.
- */
-
-void userdb_yp(void)
-{
-
-#ifdef HAVE_YP
-
-  char line[1024];
-  FILE *fp;
-
-  D( printf("adding nis users\n"); )
-
-  /* --- First, users --- */
-
-  if ((fp = popen("ypcat passwd", "r")) != 0) {
-    while (userdb__getLine(line, sizeof(line), fp)) {
-      struct passwd *pw;
-
-      if ((pw = userdb__buildUser(line)) != 0) {
-	D( userdb__dumpUser(pw, stdout); )
-	if (userdb__byName(&userdb__users, pw->pw_name))
-	  userdb_freeUser(pw);
-	else
-	  userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid, pw);
-      }
-    }
-    pclose(fp);
-  }
-
-  /* --- Next, groups --- */
-
-
-  if ((fp = popen("ypcat group", "r")) != 0) {
-    while (userdb__getLine(line, sizeof(line), fp)) {
-      struct group *gr;
-
-      if ((gr = userdb__buildGroup(line)) != 0) {
-	D( userdb__dumpGroup(gr, stdout); )
-	if (userdb__byName(&userdb__groups, gr->gr_name))
-	  userdb_freeGroup(gr);
-	else
-	  userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid, gr);
-      }
-    }
-    pclose(fp);
-  }
-
-#endif
-
-}
+/*----- Answering queries -------------------------------------------------*/
 
 /* --- @userdb_userByName@, @userdb_userById@ --- *
  *
@@ -716,6 +595,163 @@ struct group *userdb_nextGroup_r(userdb_iter *i)
   return (s ? s->rec : 0);
 }
 
+/*----- Yellow pages support ----------------------------------------------*/
+
+#ifdef HAVE_YP
+
+/* --- @userdb__foreachUser@ --- *
+ *
+ * Arguments:	@int st@ = YP protocol-level status code
+ *		@char *k@ = address of the key for this record
+ *		@int ksz@ = size of the key
+ *		@char *v@ = address of the value for this record
+ *		@int vsz@ = size of the value
+ *		@char *data@ = pointer to some data passed to me
+ *
+ * Returns:	Zero to be called again, nonzero to end the enumeration.
+ *
+ * Use:		Handles an incoming user record.
+ */
+
+static int userdb__foreachUser(int st, char *k, int ksz,
+			       char *v, int vsz, char *data)
+{
+  char *cv;
+  struct passwd *pw;
+
+  if (st != YP_TRUE)
+    return (-1);
+  cv = xmalloc(vsz + 1);
+  memcpy(cv, v, vsz);
+  cv[vsz] = 0;
+  pw = userdb__buildUser(cv);
+  if (pw && !userdb__byName(&userdb__users, pw->pw_name))
+    userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid, pw);
+  free(cv);
+  return (0);
+}
+
+/* --- @userdb__foreachGroup@ --- *
+ *
+ * Arguments:	@int st@ = YP protocol-level status code
+ *		@char *k@ = address of the key for this record
+ *		@int ksz@ = size of the key
+ *		@char *v@ = address of the value for this record
+ *		@int vsz@ = size of the value
+ *		@char *data@ = pointer to some data passed to me
+ *
+ * Returns:	Zero to be called again, nonzero to end the enumeration.
+ *
+ * Use:		Handles an incoming user record.
+ */
+
+static int userdb__foreachGroup(int st, char *k, int ksz,
+				char *v, int vsz, char *data)
+{
+  char *cv;
+  struct group *gr;
+
+  if (st != YP_TRUE)
+    return (-1);
+  cv = xmalloc(vsz + 1);
+  memcpy(cv, v, vsz);
+  cv[vsz] = 0;
+  gr = userdb__buildGroup(cv);
+  if (gr && !userdb__byName(&userdb__groups, gr->gr_name))
+    userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid, gr);
+  free(cv);
+  return (0);
+}
+
+/* --- @userdb_yp@ --- *
+ *
+ * Arguments:	---
+ *
+ * Returns:	---
+ *
+ * Use:		Fetches the YP database of users.
+ */
+
+void userdb_yp(void)
+{
+  char *ypdom;
+
+  /* --- Bind to a server --- */
+
+  if (yp_get_default_domain(&ypdom) ||
+      yp_bind(ypdom))
+    return;
+
+  /* --- Fetch the users map --- */
+
+  {
+    static struct ypall_callback ucb = { userdb__foreachUser, 0 };
+    yp_all(ypdom, "passwd.byuid", &ucb);
+  }
+
+  /* --- Fetch the groups map --- */
+
+  {
+    static struct ypall_callback gcb = { userdb__foreachGroup, 0 };
+    yp_all(ypdom, "group.bygid", &gcb);
+  }
+
+  yp_unbind(ypdom);
+  free(ypdom);
+}
+
+#else
+
+void userdb_yp(void) { ; }
+
+#endif
+
+/*----- Building the databases --------------------------------------------*/
+
+/* --- @userdb_local@ --- *
+ *
+ * Arguments:	---
+ *
+ * Returns:	---
+ *
+ * Use:		Reads the local list of users into the maps.
+ */
+
+void userdb_local(void)
+{
+  D( printf("adding local users...\n"); )
+
+  /* --- Fetch users first --- */
+
+  {
+    struct passwd *pw;
+
+    setpwent();
+    while ((pw = getpwent()) != 0) {
+      D( userdb__dumpUser(pw, stdout); )
+      if (!userdb__byName(&userdb__users, pw->pw_name))
+	userdb__addToMap(&userdb__users, pw->pw_name, pw->pw_uid,
+			 userdb_copyUser(pw));
+    }
+    endpwent();
+  }
+
+  /* --- Then fetch groups --- */
+
+  {
+    struct group *gr;
+
+    setgrent();
+    while ((gr = getgrent()) != 0) {
+      D( userdb__dumpGroup(gr, stdout); )
+      if (!userdb__byName(&userdb__groups, gr->gr_name))
+	userdb__addToMap(&userdb__groups, gr->gr_name, gr->gr_gid,
+			 userdb_copyGroup(gr));
+    }
+    endgrent();
+  }
+}
+
 /* --- @userdb_init@ --- *
  *
  * Arguments:	---
diff --git a/src/userdb.h b/src/userdb.h
index 91038d7..19dba5f 100644
--- a/src/userdb.h
+++ b/src/userdb.h
@@ -7,7 +7,7 @@
  * (c) 1997 EBI
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: userdb.h,v $
- * Revision 1.1  1997/07/21 13:47:42  mdw
+ * Revision 1.2  1997/08/04 10:24:26  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:42  mdw
  * Initial revision
  *
  */
diff --git a/src/utils.c b/src/utils.c
index a46a310..7867411 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: utils.c,v 1.1 1997/07/21 13:47:42 mdw Exp $
+ * $Id: utils.c,v 1.2 1997/08/04 10:24:26 mdw Exp $
  *
  * Miscellaneous useful bits of code.
  *
  * (c) 1997 Mark Wooding
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: utils.c,v $
- * Revision 1.1  1997/07/21 13:47:42  mdw
+ * Revision 1.2  1997/08/04 10:24:26  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:42  mdw
  * Initial revision
  *
  */
@@ -38,20 +41,22 @@
 
 /* --- ANSI headers --- */
 
+#include <ctype.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 /* --- Local headers --- */
 
 #include "config.h"
 #include "utils.h"
 
-/*----- Static data -------------------------------------------------------*/
+/*----- Program name handling ---------------------------------------------*/
 
-static const char *myname = 0;		/* What's my name? */
+/* --- Static data --- */
 
-/*----- Program name handling ---------------------------------------------*/
+static const char *myname = 0;		/* What's my name? */
 
 /* --- @quis@ --- *
  *
@@ -140,6 +145,129 @@ void die(const char *f, ...)
   exit(EXIT_FAILURE);
 }
 
+/*----- Trace messages ----------------------------------------------------*/
+
+#if defined(TRACING) || !defined(NDEBUG)
+
+/* --- Static data --- */
+
+static FILE *tracefp = 0;		/* Where does debugging go? */
+static unsigned int tracelvl = 0;	/* How much tracing gets done? */
+
+/* --- @trace@ --- *
+ *
+ * Arguments:	@unsigned int lvl@ = trace level for output
+ *		@const char *f@ = a @printf@-style format string
+ *		@...@ = other arguments
+ *
+ * Returns:	---
+ *
+ * Use:		Reports a message to the trace output.
+ */
+
+void trace(unsigned int lvl, const char *f, ...)
+{
+  va_list ap;
+  if ((lvl & tracing()) == 0)
+    return;
+  va_start(ap, f);
+  fprintf(tracefp, "*** %s: ", myname);
+  vfprintf(tracefp, f, ap);
+  va_end(ap);
+  putc('\n', tracefp);
+}
+
+/* --- @traceblk@ --- *
+ *
+ * Arguments:	@unsigned int lvl@ = trace level for output
+ *		@const char *hdr@ = some header string to write
+ *		@const void *blk@ = pointer to a block of memory to dump
+ *		@size_t sz@ = size of the block of memory
+ *
+ * Returns:	---
+ *
+ * Use:		Dumps the contents of a block to the trace output.
+ */
+
+void traceblk(unsigned int lvl, const char *hdr, const void *blk, size_t sz)
+{
+  const unsigned char *p = blk;
+  size_t i;
+  unsigned long o = 0;
+  size_t c;
+
+  /* --- Skip if the trace level is too high --- */
+
+  if ((lvl & tracing()) == 0)
+    return;
+
+  /* --- Now start work --- */
+
+  fprintf(tracefp, "*** %s: %s\n", myname, hdr);
+
+  while (sz) {
+    fprintf(tracefp, "*** %s:   %08lu : ", myname, o);
+    for (i = 0; i < 8; i++) {
+      if (i < sz)
+	fprintf(tracefp, "%02x ", p[i]);
+      else
+	fputs("** ", tracefp);
+    }
+    fputs(": ", tracefp);
+    for (i = 0; i < 8; i++) {
+      if (i < sz)
+	fputc(isprint(p[i]) ? p[i] : '.', tracefp);
+      else
+	fputc('*', tracefp);
+    }
+    fputc('\n', tracefp);
+    c = (sz >= 8) ? 8 : sz;
+    sz -= c, p += c, o += c;
+  }
+}
+
+
+/* --- @traceon@ --- *
+ *
+ * Arguments:	@FILE *fp@ = a file to trace on
+ *		@unsigned int lvl@ = trace level to set
+ *
+ * Returns:	---
+ *
+ * Use:		Enables tracing to a file.
+ */
+
+void traceon(FILE *fp, unsigned int lvl)
+{
+  tracefp = fp;
+  if (!tracelvl)
+    tracelvl = lvl;
+}
+
+/* --- @tracesetlvl@ --- *
+ *
+ * Arguments:	@unsigned int lvl@ = trace level to set
+ *
+ * Returns:	---
+ *
+ * Use:		Sets the tracing level.
+ */
+
+void tracesetlvl(unsigned int lvl) { tracelvl = lvl; }
+
+/* --- @tracing@ --- *
+ *
+ * Arguments:	---
+ *
+ * Returns:	Zero if not tracing, tracing level if tracing.
+ *
+ * Use:		Informs the caller whether tracing is enabled.
+ */
+
+unsigned int tracing(void) { return (tracefp ? tracelvl : 0u); }
+
+#endif
+
 /*----- Memory management functions ---------------------------------------*/
 
 /* --- @xmalloc@ --- *
diff --git a/src/utils.h b/src/utils.h
index 09ee6d2..dce373e 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: utils.h,v 1.1 1997/07/21 13:47:42 mdw Exp $
+ * $Id: utils.h,v 1.2 1997/08/04 10:24:26 mdw Exp $
  *
  * Miscellaneous useful bits of code.
  *
  * (c) 1997 Mark Wooding
  */
 
-/*----- Licencing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of `become'
  *
@@ -22,14 +22,17 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with `become'; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with `become'; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: utils.h,v $
- * Revision 1.1  1997/07/21 13:47:42  mdw
+ * Revision 1.2  1997/08/04 10:24:26  mdw
+ * Sources placed under CVS control.
+ *
+ * Revision 1.1  1997/07/21  13:47:42  mdw
  * Initial revision
  *
  */
@@ -78,6 +81,17 @@
    (p)[2] = ((unsigned long)(v) >> 16) & 0xFF,				\
    (p)[3] = ((unsigned long)(v) >> 24) & 0xFF)
 
+/*----- Other macros ------------------------------------------------------*/
+
+/* --- @burn@ --- *
+ *
+ * Arguments:	@obj@ = some object
+ *
+ * Use:		Writes zero bytes over the object.
+ */
+
+#define burn(obj) ((void)memset(&obj, 0, sizeof(obj)))
+
 /*----- Program name handling ---------------------------------------------*/
 
 /* --- @quis@ --- *
@@ -129,6 +143,88 @@ extern void moan(const char */*f*/, ...);
 
 extern void die(const char */*f*/, ...);
 
+/*----- Trace messages ----------------------------------------------------*/
+
+#if !defined(NDEBUG) && !defined(TRACING)
+#  define TRACING
+#endif
+
+#ifdef TRACING
+
+/* --- @trace@ --- *
+ *
+ * Arguments:	@unsigned int lvl@ = trace level for output
+ *		@const char *f@ = a @printf@-style format string
+ *		@...@ = other arguments
+ *
+ * Returns:	---
+ *
+ * Use:		Reports a message to the trace output.
+ */
+
+extern void trace(unsigned int /*lvl*/, const char */*f*/, ...);
+
+/* --- @traceblk@ --- *
+ *
+ * Arguments:	@unsigned int lvl@ = trace level for output
+ *		@const char *hdr@ = some header string to write
+ *		@const void *blk@ = pointer to a block of memory to dump
+ *		@size_t sz@ = size of the block of memory
+ *
+ * Returns:	---
+ *
+ * Use:		Dumps the contents of a block to the trace output.
+ */
+
+extern void traceblk(unsigned int /*lvl*/, const char */*hdr*/,
+		     const void */*blk*/, size_t /*sz*/);
+
+/* --- @traceon@ --- *
+ *
+ * Arguments:	@FILE *fp@ = a file to trace on
+ *		@unsigned int lvl@ = trace level to set
+ *
+ * Returns:	---
+ *
+ * Use:		Enables tracing to a file.
+ */
+
+extern void traceon(FILE */*fp*/, unsigned int /*lvl*/);
+
+/* --- @tracesetlvl@ --- *
+ *
+ * Arguments:	@unsigned int lvl@ = trace level to set
+ *
+ * Returns:	---
+ *
+ * Use:		Sets the tracing level.
+ */
+
+extern void tracesetlvl(unsigned int /*lvl*/);
+
+/* --- @tracing@ --- *
+ *
+ * Arguments:	---
+ *
+ * Returns:	Zero if not tracing, tracing level if tracing.
+ *
+ * Use:		Informs the caller whether tracing is enabled.
+ */
+
+extern unsigned int tracing(void);
+
+#endif
+
+/* --- Some hacky macros --- */
+
+#ifdef TRACING
+#  define T(x) x
+#  define IF_TRACING(lvl, x) if ((lvl) & tracing()) x
+#else
+#  define T(x)
+#  define IF_TRACING(lvl, x)
+#endif
+
 /*----- Memory management functions ---------------------------------------*/
 
 /* --- @xmalloc@ --- *
-- 
2.11.0

