svn rev #3259: trunk/ tests/ tests/config/ tests/krb-root/ tests/krb-standalone/ ...

ghudson@MIT.EDU ghudson at MIT.EDU
Fri Jul 10 16:35:46 EDT 2009


Commit By: ghudson
Log Message:
Add test framework and application tests.  Root tests are currently
failing.



Changed Files:
U   trunk/Makefile.in
U   trunk/aclocal.m4
U   trunk/configure.ac
U   trunk/pre.in
A   trunk/tests/
A   trunk/tests/Makefile.in
A   trunk/tests/config/
A   trunk/tests/config/default.exp
A   trunk/tests/deps
A   trunk/tests/krb-root/
A   trunk/tests/krb-root/rlogin.exp
A   trunk/tests/krb-root/telnet.exp
A   trunk/tests/krb-standalone/
A   trunk/tests/krb-standalone/gssftp.exp
A   trunk/tests/krb-standalone/rcp.exp
A   trunk/tests/krb-standalone/rsh.exp
A   trunk/tests/resolve/
A   trunk/tests/resolve/Makefile.in
A   trunk/tests/resolve/addrinfo-test.c
A   trunk/tests/resolve/deps
A   trunk/tests/resolve/fake-addrinfo-test.c
A   trunk/tests/resolve/resolve.c
A   trunk/tests/t_inetd.c
Modified: trunk/Makefile.in
===================================================================
--- trunk/Makefile.in	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/Makefile.in	2009-07-10 20:35:46 UTC (rev 3259)
@@ -1,6 +1,4 @@
 mydir=.
 BUILDTOP=$(REL)$(C)
 
-SUBDIRS= sample simple user_user gss-sample \
-	libpty bsd gssftp telnet
-
+SUBDIRS= libpty bsd gssftp telnet tests

Modified: trunk/aclocal.m4
===================================================================
--- trunk/aclocal.m4	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/aclocal.m4	2009-07-10 20:35:46 UTC (rev 3259)
@@ -506,231 +506,6 @@
 
 ])dnl
 dnl
-dnl AC_KRB5_TCL_FIND_CONFIG (uses tcl_dir)
-dnl
-AC_DEFUN(AC_KRB5_TCL_FIND_CONFIG,[
-AC_REQUIRE([KRB5_LIB_AUX])dnl
-AC_MSG_CHECKING(for tclConfig.sh)
-dnl On Debian, we might be given --with-tcl=/usr, or tclsh might
-dnl point us to /usr/lib/tcl8.4; either way, we need to find
-dnl /usr/lib/tcl8.4/tclConfig.sh.
-dnl On NetBSD, we might be given --with-tcl=/usr/pkg, or tclsh
-dnl might point us to /usr/pkg/lib/tcl8.4; we need to find
-dnl /usr/pkg/lib/tclConfig.sh.
-if test -r "$tcl_dir/lib/tclConfig.sh" ; then
-  tcl_conf="$tcl_dir/lib/tclConfig.sh"
-elif test -r "$tcl_dir/tclConfig.sh" ; then
-  tcl_conf="$tcl_dir/tclConfig.sh"
-elif test -r "$tcl_dir/../tclConfig.sh" ; then
-  tcl_conf="$tcl_dir/../tclConfig.sh"
-else
-  tcl_conf=
-  lib="$tcl_dir/lib"
-  changequote(<<,>>)dnl
-  for d in "$lib" "$lib"/tcl7.[0-9] "$lib"/tcl8.[0-9] ; do
-    if test -r "$d/tclConfig.sh" ; then
-      tcl_conf="$tcl_conf $d/tclConfig.sh"
-    fi
-  done
-  changequote([,])dnl
-fi
-if test -n "$tcl_conf" ; then
-  AC_MSG_RESULT($tcl_conf)
-else
-  AC_MSG_RESULT(not found)
-fi
-tcl_ok_conf=
-tcl_vers_maj=
-tcl_vers_min=
-old_CPPFLAGS=$CPPFLAGS
-old_LIBS=$LIBS
-old_LDFLAGS=$LDFLAGS
-if test -n "$tcl_conf" ; then
-  for file in $tcl_conf ; do
-    TCL_MAJOR_VERSION=x ; TCL_MINOR_VERSION=x
-    AC_MSG_CHECKING(Tcl info in $file)
-    . $file
-    v=$TCL_MAJOR_VERSION.$TCL_MINOR_VERSION
-    if test -z "$tcl_vers_maj" \
-	|| test "$tcl_vers_maj" -lt "$TCL_MAJOR_VERSION" \
-	|| test "$tcl_vers_maj" = "$TCL_MAJOR_VERSION" -a "$tcl_vers_min" -lt "$TCL_MINOR_VERSION" ; then
-      for incdir in "$TCL_PREFIX/include/tcl$v" "$TCL_PREFIX/include" ; do
-	if test -r "$incdir/tcl.h" -o -r "$incdir/tcl/tcl.h" ; then
-	  CPPFLAGS="$old_CPPFLAGS -I$incdir"
-	  break
-	fi
-      done
-      LIBS="$old_LIBS `eval echo x $TCL_LIB_SPEC $TCL_LIBS | sed 's/^x//'`"
-      LDFLAGS="$old_LDFLAGS $TCL_LD_FLAGS"
-      AC_TRY_LINK( , [Tcl_CreateInterp ();],
-	tcl_ok_conf=$file
-	tcl_vers_maj=$TCL_MAJOR_VERSION
-	tcl_vers_min=$TCL_MINOR_VERSION
-	AC_MSG_RESULT($v - working),
-	AC_MSG_RESULT($v - compilation failed)
-      )
-    else
-      AC_MSG_RESULT(older version $v)
-    fi
-  done
-fi
-CPPFLAGS=$old_CPPFLAGS
-LIBS=$old_LIBS
-LDFLAGS=$old_LDFLAGS
-tcl_header=no
-tcl_lib=no
-if test -n "$tcl_ok_conf" ; then
-  . $tcl_ok_conf
-  TCL_INCLUDES=
-  for incdir in "$TCL_PREFIX/include/tcl$v" "$TCL_PREFIX/include" ; do
-    if test -r "$incdir/tcl.h" -o -r "$incdir/tcl/tcl.h" ; then
-      if test "$incdir" != "/usr/include" ; then
-        TCL_INCLUDES=-I$incdir
-      fi
-      break
-    fi
-  done
-  # Need eval because the first-level expansion could reference
-  # variables like ${TCL_DBGX}.
-  eval TCL_LIBS='"'$TCL_LIB_SPEC $TCL_LIBS $TCL_DL_LIBS'"'
-  TCL_LIBPATH="-L$TCL_EXEC_PREFIX/lib"
-  TCL_RPATH=":$TCL_EXEC_PREFIX/lib"
-  if test "$DEPLIBEXT" != "$SHLIBEXT" && test -n "$RPATH_FLAG"; then
-    TCL_MAYBE_RPATH='$(RPATH_FLAG)'"$TCL_EXEC_PREFIX/lib$RPATH_TAIL"
-  else
-    TCL_MAYBE_RPATH=
-  fi
-  CPPFLAGS="$old_CPPFLAGS $TCL_INCLUDES"
-  AC_CHECK_HEADER(tcl.h,AC_DEFINE(HAVE_TCL_H,1,[Define if tcl.h is available]) tcl_header=yes)
-  if test $tcl_header=no; then
-     AC_CHECK_HEADER(tcl/tcl.h,AC_DEFINE(HAVE_TCL_TCL_H,1,[Define if tcl/tcl.h is available]) tcl_header=yes)
-  fi
-  CPPFLAGS="$old_CPPFLAGS"
-  tcl_lib=yes
-else
-  # If we read a tclConfig.sh file, it probably set this.
-  TCL_LIBS=
-fi  
-AC_SUBST(TCL_INCLUDES)
-AC_SUBST(TCL_LIBS)
-AC_SUBST(TCL_LIBPATH)
-AC_SUBST(TCL_RPATH)
-AC_SUBST(TCL_MAYBE_RPATH)
-])dnl
-dnl
-dnl AC_KRB5_TCL_TRYOLD
-dnl attempt to use old search algorithm for locating tcl
-dnl
-AC_DEFUN(AC_KRB5_TCL_TRYOLD, [
-AC_REQUIRE([KRB5_AC_FIND_DLOPEN])
-AC_MSG_WARN([trying old tcl search code])
-if test "$with_tcl" != yes -a "$with_tcl" != no; then
-	TCL_INCLUDES=-I$with_tcl/include
-	TCL_LIBPATH=-L$with_tcl/lib
-	TCL_RPATH=:$with_tcl/lib
-fi
-if test "$with_tcl" != no ; then
-	krb5_save_CPPFLAGS="$CPPFLAGS"
-	krb5_save_LDFLAGS="$LDFLAGS"
-	CPPFLAGS="$CPPFLAGS $TCL_INCLUDES"
-	LDFLAGS="$LDFLAGS $TCL_LIBPATH"
-	tcl_header=no
-	AC_CHECK_HEADER(tcl.h,AC_DEFINE(HAVE_TCL_H,1,[Define if tcl.h found]) tcl_header=yes)
-	if test $tcl_header=no; then
-	   AC_CHECK_HEADER(tcl/tcl.h,AC_DEFINE(HAVE_TCL_TCL_H,1,[Define if tcl/tcl.h found]) tcl_header=yes)
-	fi
-
-	if test $tcl_header = yes ; then
-		tcl_lib=no
-
-		if test $tcl_lib = no; then
-			AC_CHECK_LIB(tcl8.0, Tcl_CreateCommand, 
-				TCL_LIBS="$TCL_LIBS -ltcl8.0 -lm $DL_LIB $LIBS"
-				tcl_lib=yes,,-lm $DL_LIB)
-		fi
-		if test $tcl_lib = no; then
-			AC_CHECK_LIB(tcl7.6, Tcl_CreateCommand, 
-				TCL_LIBS="$TCL_LIBS -ltcl7.6 -lm $DL_LIB $LIBS"
-				tcl_lib=yes,,-lm $DL_LIB)
-		fi
-		if test $tcl_lib = no; then
-			AC_CHECK_LIB(tcl7.5, Tcl_CreateCommand, 
-				TCL_LIBS="$TCL_LIBS -ltcl7.5 -lm $DL_LIB $LIBS"
-				tcl_lib=yes,,-lm $DL_LIB)
-
-		fi
-		if test $tcl_lib = no ; then
-			AC_CHECK_LIB(tcl, Tcl_CreateCommand, 
-				TCL_LIBS="$TCL_LIBS -ltcl -lm $DL_LIB $LIBS"
-				tcl_lib=yes,,-lm $DL_LIB)
-
-		fi
-		if test $tcl_lib = no ; then		
-			AC_MSG_WARN("tcl.h found but not library")
-		fi
-	else
-		AC_MSG_WARN(Could not find Tcl which is needed for the kadm5 tests)
-		TCL_LIBS=
-	fi
-	CPPFLAGS="$krb5_save_CPPFLAGS"
-	LDFLAGS="$krb5_save_LDFLAGS"
-	AC_SUBST(TCL_INCLUDES)
-	AC_SUBST(TCL_LIBS)
-	AC_SUBST(TCL_LIBPATH)
-	AC_SUBST(TCL_RPATH)
-else
-	AC_MSG_RESULT("Not looking for Tcl library")
-fi
-])dnl
-dnl
-dnl AC_KRB5_TCL - determine if the TCL library is present on system
-dnl
-AC_DEFUN(AC_KRB5_TCL,[
-TCL_INCLUDES=
-TCL_LIBPATH=
-TCL_RPATH=
-TCL_LIBS=
-TCL_WITH=
-tcl_dir=
-AC_ARG_WITH(tcl,
-[  --with-tcl=path         where Tcl resides], , with_tcl=try)
-if test "$with_tcl" = no ; then
-  true
-elif test "$with_tcl" = yes -o "$with_tcl" = try ; then
-  tcl_dir=/usr
-  if test ! -r /usr/lib/tclConfig.sh; then
-    cat >> conftest <<\EOF
-puts "tcl_dir=$tcl_library"
-EOF
-    if tclsh conftest >conftest.out 2>/dev/null; then
-      if grep tcl_dir= conftest.out >/dev/null 2>&1; then
-        t=`sed s/tcl_dir=// conftest.out`
-        tcl_dir=$t
-      fi
-    fi # tclsh ran script okay
-  rm -f conftest conftest.out
-  fi # no /usr/lib/tclConfig.sh
-else
-  tcl_dir=$with_tcl
-fi
-if test "$with_tcl" != no ; then
-  AC_KRB5_TCL_FIND_CONFIG
-  if test $tcl_lib = no ; then
-    if test "$with_tcl" != try ; then
-      AC_KRB5_TCL_TRYOLD
-    else
-      AC_MSG_WARN(Could not find Tcl which is needed for some tests)
-    fi
-  fi
-fi
-# If "yes" or pathname, error out if not found.
-if test "$with_tcl" != no -a "$with_tcl" != try ; then
-  if test "$tcl_header $tcl_lib" != "yes yes" ; then
-    AC_MSG_ERROR(Could not find Tcl)
-  fi
-fi
-])dnl
-dnl
 dnl Check if we need the prototype for a function - we give it a bogus 
 dnl prototype and if it complains - then a valid prototype exists on the 
 dnl system.
@@ -802,43 +577,6 @@
 AC_DEFINE_UNQUOTED([GETSOCKNAME_ARG3_TYPE],$res2,[Type of pointer target for argument 3 to getsockname])
 ])dnl
 dnl
-dnl KRB5_AC_PRIOCNTL_HACK
-dnl
-dnl
-AC_DEFUN([KRB5_AC_PRIOCNTL_HACK],
-[AC_REQUIRE([AC_PROG_AWK])dnl
-AC_REQUIRE([AC_LANG_COMPILER_REQUIRE])dnl
-AC_CACHE_CHECK([whether to use priocntl hack], [krb5_cv_priocntl_hack],
-[case $krb5_cv_host in
-*-*-solaris2.9*)
-	if test "$cross_compiling" = yes; then
-		krb5_cv_priocntl_hack=yes
-	else
-		# Solaris patch 117171-11 (sparc) or 117172-11 (x86)
-		# fixes the Solaris 9 bug where final pty output
-		# gets lost on close.
-		if showrev -p | $AWK 'BEGIN { e = 1 }
-/Patch: 11717[[12]]/ { x = index[]([$]2, "-");
-if (substr[]([$]2, x + 1, length([$]2) - x) >= 11)
-{ e = 0 } else { e = 1 } }
-END { exit e; }'; then
-			krb5_cv_priocntl_hack=no
-		else
-			krb5_cv_priocntl_hack=yes
-		fi
-	fi
-	;;
-*)
-	krb5_cv_priocntl_hack=no
-	;;
-esac])
-if test "$krb5_cv_priocntl_hack" = yes; then
-	PRIOCNTL_HACK=1
-else
-	PRIOCNTL_HACK=0
-fi
-AC_SUBST(PRIOCNTL_HACK)])dnl
-dnl
 dnl KRB5_AC_LIBUTIL
 dnl
 dnl Check for libutil, for NetBSD, et al.; needed for openpty() and

Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/configure.ac	2009-07-10 20:35:46 UTC (rev 3259)
@@ -21,9 +21,13 @@
 KRB5_CFLAGS=`$krb5_config --cflags`
 KRB5_BASE_LIBS=`$krb5_config --libs krb5`" -lkrb5support"
 GSS_LIBS=`$krb5_config --libs gssapi`" -lkrb5support"
+KRB5_BINDIR=`$krb5_config --exec-prefix`/bin
+KRB5_SBINDIR=`$krb5_config --exec-prefix`/sbin
 AC_SUBST(KRB5_CFLAGS)
 AC_SUBST(KRB5_BASE_LIBS)
 AC_SUBST(GSS_LIBS)
+AC_SUBST(KRB5_BINDIR)
+AC_SUBST(KRB5_SBINDIR)
 
 WITH_CC
 if test -z "$LD" ; then LD=$CC; fi
@@ -40,6 +44,7 @@
 AC_CHECK_PROG(AR, ar, ar, false)
 AC_FUNC_FORK
 AC_TYPE_MODE_T
+AC_TYPE_SIGNAL
 AC_CHECK_TYPES([socklen_t, struct sockaddr_storage],,,
 [#include <sys/types.h>
 #include <sys/socket.h>
@@ -64,9 +69,9 @@
 AC_CHECK_HEADERS(curses.h lastlog.h libutil.h memory.h paths.h pty.h stdlib.h)
 AC_CHECK_HEADERS(string.h ttyent.h util.h sac.h unistd.h utmp.h utmpx.h)
 AC_CHECK_HEADERS(arpa/inet.h arpa/nameser.h)
-AC_CHECK_HEADERS(sys/filio.h sys/ioctl_compat.h sys/label.h sys/select.h)
-AC_CHECK_HEADERS(sys/sockio.h sys/stream.h sys/time.h sys/tty.h sys/uio.h)
-AC_CHECK_HEADERS(sys/utsname.h sys/wait.h)
+AC_CHECK_HEADERS(sys/filio.h sys/ioctl_compat.h sys/label.h sys/param.h)
+AC_CHECK_HEADERS(sys/select.h sys/sockio.h sys/stream.h sys/time.h sys/tty.h)
+AC_CHECK_HEADERS(sys/uio.h sys/utsname.h sys/wait.h)
 dnl On some systems, term.h requires curses.h inclusion
 AC_CHECK_HEADERS(term.h,,,
 [#ifdef HAVE_CURSES_H
@@ -475,6 +480,16 @@
              [Define if system termios interface doesn't define speed_t])
 fi
 
+dnl For dejagnu tests
+AC_CHECK_PROG(RUNTEST,runtest,runtest)
+if test x"$RUNTEST" != x; then
+    HAVE_RUNTEST=yes
+else
+    HAVE_RUNTEST=no
+fi
+AC_SUBST(HAVE_RUNTEST)
+
 V5_AC_OUTPUT_MAKEFILE(. bsd libpty
                       gssftp gssftp/ftp gssftp/ftpd
-                      telnet telnet/libtelnet telnet/telnet telnet/telnetd)
+                      telnet telnet/libtelnet telnet/telnet telnet/telnetd
+                      tests tests/resolve)

Modified: trunk/pre.in
===================================================================
--- trunk/pre.in	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/pre.in	2009-07-10 20:35:46 UTC (rev 3259)
@@ -169,12 +169,7 @@
 CLIENT_MANDIR = $(KRB5MANROOT)/man1
 
 # Dejagnu variables.
-# We have to set the host with --host so that setup_xfail will work.
-# If we don't set it, then the host type used is "native", which
-# doesn't match "*-*-*".
-host=@krb5_cv_host@
-DEJAFLAGS	= $(DEJALFLAGS) $(CLFLAGS) --debug --srcdir $(srcdir) --host \
-		   $(host)
+DEJAFLAGS	= --debug --srcdir $(srcdir)
 RUNTEST		= runtest $(DEJAFLAGS)
 
 transform = @program_transform_name@

Added: trunk/tests/Makefile.in
===================================================================
--- trunk/tests/Makefile.in	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/Makefile.in	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,37 @@
+mydir=tests
+BUILDTOP=$(REL)..
+SUBDIRS = resolve
+
+RUNTEST = @RUNTEST@ $(DEJAFLAGS)
+RUNTESTFLAGS =
+
+SRCS=$(srcdir)/t_inetd.c
+OBJS=t_inetd.o
+
+KRB5_BINDIR = @KRB5_BINDIR@
+KRB5_SBINDIR = @KRB5_SBINDIR@
+
+all install::
+
+check:: check-runtest- at HAVE_RUNTEST@
+
+check-runtest-no::
+	@echo "+++"
+	@echo "+++ WARNING: tests/dejagnu tests not run."
+	@echo "+++ runtest is unavailable."
+	@echo "+++"
+
+# Set VALGRIND at run time, that may be changed when running 'make'.
+check-runtest-yes:: t_inetd site.exp
+	$(RUNTEST) --tool krb VALGRIND="$(VALGRIND)" $(RUNTESTFLAGS)
+
+# KRB5_BASE_LIBS is a cheap way to get network libraries here.
+t_inetd:: t_inetd.o
+	$(CC_LINK) -o t_inetd t_inetd.o $(KRB5_BASE_LIBS)
+
+clean::
+	$(RM) t_inetd tmpdir dbg.log krb.log krb.sum
+
+site.exp: Makefile
+	echo "set KRB5_BINDIR {$(KRB5_BINDIR)}" > site.exp
+	echo "set KRB5_SBINDIR {$(KRB5_SBINDIR)}" >> site.exp

Added: trunk/tests/config/default.exp
===================================================================
--- trunk/tests/config/default.exp	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/config/default.exp	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,2561 @@
+# Basic expect script for Kerberos tests.
+# This is a DejaGnu test script.
+# Written by Ian Lance Taylor, Cygnus Support, <ian at cygnus.com>.
+# This script is automatically run by DejaGnu before running any of
+# the Kerberos test scripts.
+
+# This file provides several functions which deal with a local
+# Kerberos database.  We have to do this such that we don't interfere
+# with any existing Kerberos database.  We will create all the files
+# in the directory $tmppwd, which will have been created by the
+# testsuite default script.  We will use $REALMNAME as our Kerberos
+# realm name, defaulting to KRBTEST.COM.
+
+set timeout 100
+set stty_init {erase \^h kill \^u}
+set env(TERM) dumb
+
+set des3_krbtgt 0
+set tgt_support_desmd5 0
+set supported_enctypes "des-cbc-crc:normal"
+set kdc_supported_enctypes "des-cbc-crc:normal"
+
+# The names of the individual passes must be unique; lots of things
+# depend on it.  The PASSES variable may not contain comments; only
+# small pieces get evaluated, so comments will do strange things.
+
+# Most of the purpose of using multiple passes is to exercise the
+# dependency of various bugs on configuration file settings,
+# particularly with regards to encryption types.
+
+# The des.no-kdc-md5 pass will fail if the KDC does not constrain
+# session key enctypes to those in its permitted_enctypes list.  It
+# works by assuming enctype similarity, thus allowing the client to
+# request a des-cbc-md4 session key.  Since only des-cbc-crc is in the
+# KDC's permitted_enctypes list, the TGT will be unusable.
+
+# KLUDGE for tracking down leaking ptys
+if 0 {
+    rename spawn oldspawn
+    rename wait oldwait
+    proc spawn { args } {
+	upvar 1 spawn_id spawn_id
+	verbose "spawn: args=$args"
+	set pid [eval oldspawn $args]
+	verbose "spawn: pid=$pid spawn_id=$spawn_id"
+	return $pid
+    }
+    proc wait { args } {
+	upvar 1 spawn_id spawn_id
+	verbose "wait: args=$args"
+	set ret [eval oldwait $args]
+	verbose "wait: $ret"
+	return $ret
+    }
+}
+
+if { [string length $VALGRIND] } {
+    rename spawn valgrind_aux_spawn
+    proc spawn { args } {
+	global VALGRIND
+	upvar 1 spawn_id spawn_id
+	set newargs {}
+	set inflags 1
+	set eatnext 0
+	foreach arg $args {
+	    if { $arg == "-ignore" \
+		     || $arg == "-open" \
+		     || $arg == "-leaveopen" } {
+		lappend newargs $arg
+		set eatnext 1
+		continue
+	    }
+	    if [string match "-*" $arg] {
+		lappend newargs $arg
+		continue
+	    }
+	    if { $eatnext } {
+		set eatnext 0
+		lappend newargs $arg
+		continue
+	    }
+	    if { $inflags } {
+		set inflags 0
+		# Only run valgrind for local programs, not
+		# system ones.
+#&&![string match "/bin/sh" $arg] sh is used to start kadmind!
+		if [string match "/" [string index $arg 0]]&&![string match "/bin/ls" $arg]&&![regexp {/kshd$} $arg] {
+		    set newargs [concat $newargs $VALGRIND]
+		}
+	    }
+	    lappend newargs $arg
+	}
+	set pid [eval valgrind_aux_spawn $newargs]
+	return $pid
+    }
+}
+
+# The des.des3-tgt.no-kdc-des3 pass will fail if the KDC doesn't
+# constrain ticket key enctypes to those in permitted_enctypes.  It
+# does this by not putting des3 in the permitted_enctypes, while
+# creating a TGT princpal that has a des3 key as well as a des key.
+
+# XXX -- master_key_type is fragile w.r.t. permitted_enctypes; it is
+# possible to configure things such that you have a master_key_type
+# that is not permitted, and the error message used to be cryptic.
+
+set passes {
+    {
+	des
+	mode=udp
+	des3_krbtgt=0
+	{supported_enctypes=des-cbc-crc:normal}
+	{kdc_supported_enctypes=des-cbc-crc:normal}
+	{dummy=[verbose -log "DES TGT, DES enctype"]}
+    }
+    {
+	des.des3tgt
+	mode=udp
+	des3_krbtgt=1
+	{supported_enctypes=des-cbc-crc:normal}
+	{kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal}
+	{dummy=[verbose -log "DES3 TGT, DES enctype"]}
+    }
+    {
+	des3
+	mode=udp
+	des3_krbtgt=1
+	{supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal}
+	{kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal}
+	{dummy=[verbose -log "DES3 TGT, DES3 + DES enctypes"]}
+    }
+    {
+	aes
+	mode=udp
+	des3_krbtgt=0
+	{supported_enctypes=aes256-cts-hmac-sha1-96:normal des-cbc-crc:normal}
+	{kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal des-cbc-crc:normal}
+	{permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96 des-cbc-crc}
+	{permitted_enctypes(client)=aes256-cts-hmac-sha1-96 des-cbc-crc}
+	{permitted_enctypes(server)=aes256-cts-hmac-sha1-96 des-cbc-crc}
+	{master_key_type=aes256-cts-hmac-sha1-96}
+	{dummy=[verbose -log "AES + DES enctypes"]}
+    }
+    {
+	aes-des3
+	mode=udp
+	des3_krbtgt=0
+	{supported_enctypes=aes256-cts-hmac-sha1-96:normal des3-cbc-sha1:normal des-cbc-crc:normal}
+	{kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal des3-cbc-sha1:normal des-cbc-crc:normal}
+	{permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc}
+	{permitted_enctypes(client)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc}
+	{permitted_enctypes(server)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc}
+	{master_key_type=aes256-cts-hmac-sha1-96}
+	{dummy=[verbose -log "AES + DES enctypes"]}
+    }
+    {
+	des3-aes
+	mode=udp
+	des3_krbtgt=1
+	{supported_enctypes=aes256-cts-hmac-sha1-96:normal des3-cbc-sha1:normal des-cbc-crc:normal}
+	{kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal des3-cbc-sha1:normal des-cbc-crc:normal}
+	{permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc}
+	{permitted_enctypes(client)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc}
+	{permitted_enctypes(server)=aes256-cts-hmac-sha1-96 des3-cbc-sha1 des-cbc-crc}
+	{master_key_type=aes256-cts-hmac-sha1-96}
+	{dummy=[verbose -log "AES + DES enctypes, DES3 TGT"]}
+    }
+    {
+	des-v4
+	mode=udp
+	des3_krbtgt=0
+	{supported_enctypes=des-cbc-crc:v4}
+	{kdc_supported_enctypes=des-cbc-crc:v4}
+	{default_tkt_enctypes(client)=des-cbc-crc}
+	{dummy=[verbose -log "DES TGT, DES-CRC enctype, V4 salt"]}
+    }
+    {
+	des-md5-v4
+	mode=udp
+	des3_krbtgt=0
+	{supported_enctypes=des-cbc-md5:v4 des-cbc-crc:v4}
+	{kdc_supported_enctypes=des-cbc-md5:v4 des-cbc-crc:v4}
+	{default_tkt_enctypes(client)=des-cbc-md5 des-cbc-crc}
+	{dummy=[verbose -log "DES TGT, DES-MD5 and -CRC enctypes, V4 salt"]}
+    }
+    {
+	all-des-des3-enctypes
+	mode=udp
+	des3_krbtgt=1
+	{supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal \
+		des-cbc-md5:normal des-cbc-crc:v4 des-cbc-md5:norealm \
+		des-cbc-md4:normal}
+	{kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal \
+		des-cbc-md5:normal des-cbc-crc:v4 des-cbc-md5:norealm \
+		des-cbc-md4:normal}
+	{dummy=[verbose -log "DES3 TGT, many DES3 + DES enctypes"]}
+    }
+    {
+	des.no-kdc-md5
+	mode=udp
+	des3_krbtgt=0
+	tgt_support_desmd5=0
+	{permitted_enctypes(kdc)=des-cbc-crc}
+	{default_tgs_enctypes(client)=des-cbc-md5 des-cbc-md4 des-cbc-crc}
+	{default_tkt_enctypes(client)=des-cbc-md5 des-cbc-md4 des-cbc-crc}
+	{supported_enctypes=des-cbc-crc:normal}
+	{kdc_supported_enctypes=des-cbc-crc:normal}
+	{master_key_type=des-cbc-crc}
+	{dummy=[verbose -log \
+		"DES TGT, KDC permitting only des-cbc-crc"]}
+    }
+    {
+	des.des3-tgt.no-kdc-des3
+	mode=udp
+	tgt_support_desmd5=0
+	{permitted_enctypes(kdc)=des-cbc-crc}
+	{default_tgs_enctypes(client)=des-cbc-crc}
+	{default_tkt_enctypes(client)=des-cbc-crc}
+	{supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal}
+	{kdc_supported_enctypes=des3-cbc-sha1:normal des-cbc-crc:normal}
+	{master_key_type=des-cbc-crc}
+	{dummy=[verbose -log \
+		"DES3 TGT, KDC permitting only des-cbc-crc"]}
+    }
+}
+
+# des.md5-tgt is set as unused, since it won't trigger the error case
+# if SUPPORT_DESMD5 isn't honored.
+
+# The des.md5-tgt pass will fail if enctype similarity is inconsisent;
+# between 1.0.x and 1.1, the decrypt functions became more strict
+# about matching enctypes, while the KDB retrieval functions didn't
+# coerce the enctype to match what was requested.  It works by setting
+# SUPPORT_DESMD5 on the TGT principal, forcing an enctype of
+# des-cbc-md5 on the TGT key.  Since the database only contains a
+# des-cbc-crc key, the decrypt will fail if enctypes are not coerced.
+
+# des.no-kdc-md5.client-md4-skey is retained in unsed_passes, even
+# though des.no-kdc-md5 is roughly equivalent, since the associated
+# comment needs additional investigation at some point re the kadmin
+# client.
+
+# The des.no-kdc-md5.client-md4-skey will fail on TGS requests due to
+# the KDC issuing session keys that it won't accept.  It will also
+# fail for a kadmin client, but for different reasons, since the kadm5
+# library does some curious filtering of enctypes, and also uses
+# get_in_tkt() rather than get_init_creds(); the former does an
+# intersection of the enctypes provided by the caller and those listed
+# in the config file!
+
+set unused_passes {
+    {
+	des.md5-tgt
+	des3_krbtgt=0
+	tgt_support_desmd5=1
+	supported_enctypes=des-cbc-crc:normal
+	kdc_supported_enctypes=des-cbc-crc:normal
+	{permitted_enctypes(kdc)=des-cbc-md5 des-cbc-md4 des-cbc-crc}
+	{permitted_enctypes(client)=des-cbc-md5 des-cbc-md4 des-cbc-crc}
+	{dummy=[verbose -log "DES TGT, SUPPORTS_DESMD5"]}
+    }
+    {
+	des.md5-tgt.no-kdc-md5
+	des3_krbtgt=0
+	tgt_support_desmd5=1
+	{permitted_enctypes(kdc)=des-cbc-crc}
+	{default_tgs_enctypes(client)=des-cbc-crc}
+	{default_tkt_enctypes(client)=des-cbc-crc}
+	{supported_enctypes=des-cbc-crc:normal}
+	{kdc_supported_enctypes=des-cbc-crc:normal}
+	{master_key_type=des-cbc-crc}
+	{dummy=[verbose -log \
+		"DES TGT, SUPPORTS_DESMD5, KDC permitting only des-cbc-crc"]}
+    }
+    {
+	des.no-kdc-md5.client-md4-skey
+	des3_krbtgt=0
+	{permitted_enctypes(kdc)=des-cbc-crc}
+	{permitted_enctypes(client)=des-cbc-crc des-cbc-md4}
+	{default_tgs_enctypes(client)=des-cbc-crc des-cbc-md4}
+	{default_tkt_enctypes(client)=des-cbc-md4}
+	{supported_enctypes=des-cbc-crc:normal}
+	{kdc_supported_enctypes=des-cbc-crc:normal}
+	{dummy=[verbose -log \
+		"DES TGT, DES enctype, KDC permitting only des-cbc-crc, client requests des-cbc-md4 session key"]}
+    }
+    {
+	all-enctypes
+	des3_krbtgt=1
+	{supported_enctypes=\
+	aes256-cts-hmac-sha1-96:normal aes256-cts-hmac-sha1-96:norealm \
+	aes128-cts-hmac-sha1-96:normal aes128-cts-hmac-sha1-96:norealm \
+	des3-cbc-sha1:normal des3-cbc-sha1:none \
+	des-cbc-md5:normal des-cbc-md4:normal des-cbc-crc:normal \
+	des-cbc-md5:v4 des-cbc-md4:v4 des-cbc-crc:v4 \
+	}
+	{kdc_supported_enctypes=\
+	des3-cbc-sha1:normal des3-cbc-sha1:none \
+	des-cbc-md5:normal des-cbc-md4:normal des-cbc-crc:normal \
+	des-cbc-md5:v4 des-cbc-md4:v4 des-cbc-crc:v4 \
+	}
+	{dummy=[verbose -log "DES3 TGT, default enctypes"]}
+    }
+    {
+	aes-tcp
+	mode=tcp
+	des3_krbtgt=0
+	{supported_enctypes=aes256-cts-hmac-sha1-96:normal}
+	{kdc_supported_enctypes=aes256-cts-hmac-sha1-96:normal}
+	{permitted_enctypes(kdc)=aes256-cts-hmac-sha1-96}
+	{permitted_enctypes(client)=aes256-cts-hmac-sha1-96}
+	{permitted_enctypes(server)=aes256-cts-hmac-sha1-96}
+	{master_key_type=aes256-cts-hmac-sha1-96}
+	{dummy=[verbose -log "AES via TCP"]}
+    }
+}
+#	{supported_enctypes=des-cbc-md5:normal des-cbc-crc:normal twofish256-hmac-sha1:normal }
+#	{kdc_supported_enctypes= des-cbc-md5:normal des-cbc-crc:normal twofish256-hmac-sha1:normal}
+
+# This shouldn't be necessary on dejagnu-1.4 and later, but 1.3 seems
+# to need it because its runtest.exp doesn't deal with PASS at all.
+if [info exists PASS] {
+    foreach pass $passes {
+	if { [lsearch -exact $PASS [lindex $pass 0]] >= 0 } {
+	    lappend MULTIPASS $pass
+	}
+    }
+} else {
+    set MULTIPASS $passes
+}
+
+set last_passname_conf ""
+set last_passname_db ""
+
+# We do everything in a temporary directory.
+if ![info exists TMPDIR] {
+    set tmppwd "[pwd]/tmpdir"
+    if ![file isdirectory $tmppwd] {
+	catch "exec mkdir $tmppwd" status
+    }
+} else {
+    set tmppwd $TMPDIR
+}
+verbose "tmppwd=$tmppwd"
+
+# On Ultrix, use /bin/sh5 in preference to /bin/sh.
+if ![info exists BINSH] {
+    if [file exists /bin/sh5] {
+	set BINSH /bin/sh5
+    } else {
+	set BINSH /bin/sh
+    }
+}
+
+# For security, we must not use generally known passwords.  This is
+# because some of the tests may be run as root.  If the passwords were
+# generally know, then somebody could work out the appropriate
+# Kerberos ticket to use, and come in when, say, the telnetd daemon
+# was being tested by root.  The window for doing this is very very
+# small, so the password does not have to be perfect, it just can't be
+# constant.
+if ![info exists KEY] {
+    catch {exec $BINSH -c "echo $$"} KEY
+    verbose "KEY is $KEY"
+    set keyfile [open $tmppwd/KEY w]
+    puts $keyfile "$KEY"
+    close $keyfile
+}
+
+# Clear away any files left over from a previous run.
+# We can't use them now because we don't know the right KEY.
+# krb5.conf might change if running tests on another host
+file delete $tmppwd/krb5.conf $tmppwd/kdc.conf $tmppwd/slave.conf \
+    $tmppwd/krb5.client.conf $tmppwd/krb5.server.conf \
+    $tmppwd/krb5.kdc.conf $tmppwd/krb5.slave.conf
+
+proc delete_db {} {
+    global tmppwd
+    # Master and slave db files
+    file delete $tmppwd/kdc-db $tmppwd/kdc-db.ok $tmppwd/kdc-db.kadm5 \
+	$tmppwd/kdc-db.kadm5.lock \
+	$tmppwd/kdc-db.ulog \
+	$tmppwd/slave-db $tmppwd/slave-db.ok $tmppwd/slave-db.kadm5 $tmppwd/slave-db.kadm5.lock \
+	$tmppwd/slave-db~ $tmppwd/slave-db~.ok $tmppwd/slave-db~.kadm5 $tmppwd/slave-db~.kadm5.lock
+    # Creating a new database means we need a new srvtab.
+    file delete $tmppwd/srvtab $tmppwd/cpw_srvtab
+}
+
+delete_db
+
+# Put the installed kerberos directories on PATH.
+# This needs to be fixed for V5.
+# set env(PATH) $env(PATH):/usr/kerberos/bin:/usr/kerberos/etc
+# verbose "PATH=$env(PATH)"
+
+# Some of the tests expect $env(USER) to be set.
+if ![info exists env(USER)] {
+    if [info exists env(LOGNAME)] {
+	set env(USER) $env(LOGNAME)
+    } else {
+	if [info exists logname] {
+	    set env(USER) $logname
+	} else {
+	    catch "exec whoami" env(USER)
+	}
+    }
+}
+
+# set the realm. The user can override this on the runtest line.
+if ![info exists REALMNAME] {
+    set REALMNAME "KRBTEST.COM"
+}
+verbose "Test realm is $REALMNAME"
+
+# Find some programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be ...tests/dejagnu.
+
+foreach i {
+    {KDB5_UTIL $KRB5_SBINDIR/kdb5_util}
+    {KRB5KDC $KRB5_SBINDIR/krb5kdc}
+    {KADMIND $KRB5_SBINDIR/kadmind}
+    {KADMIN $KRB5_BINDIR/kadmin}
+    {KADMIN_LOCAL $KRB5_SBINDIR/kadmin.local}
+    {KINIT $KRB5_BINDIR/kinit}
+    {KTUTIL $KRB5_BINDIR/ktutil}
+    {KLIST $KRB5_BINDIR/klist}
+    {KDESTROY $KRB5_BINDIR/kdestroy}
+    {RESOLVE $objdir/resolve/resolve}
+    {T_INETD $objdir/t_inetd}
+} {
+    set varname [lindex $i 0]
+    if ![info exists $varname] {
+	eval set varval [lindex $i 1]
+	set varval [findfile $varval]
+	set $varname $varval
+	verbose "$varname=$varval"
+    } {
+	eval set varval \$$varname
+	verbose "$varname already set to $varval"
+    }
+}
+
+if ![info exists RLOGIN] {
+    set RLOGIN rlogin
+}
+
+if ![info exists RLOGIN_FLAGS] {
+    set RLOGIN_FLAGS "-x"
+}
+
+# We use a couple of variables to hold shell prompts which may be
+# overridden by the user.
+
+if ![info exists ROOT_PROMPT] {
+    set ROOT_PROMPT "(%|#|>|\\$) $"
+}
+
+if ![info exists SHELL_PROMPT] {
+    set SHELL_PROMPT "(%|#|>|\\$) $"
+}
+
+verbose "setting up onexit handler (old handler=[exit -onexit])"
+exit -onexit [concat {
+    verbose "calling stop_kerberos_daemons (onexit handler)"
+    stop_kerberos_daemons;
+} [exit -onexit]]
+
+# run_once
+
+# Many tests are independent of the actual enctypes used, which is
+# what our passes are (currently) all about.  Use this to prevent
+# multiple invocations.  If a test depends on, say, the master key
+# type but nothing else, you could also use the master key type in the
+# tag name, and avoid redundant tests in additional passes using the
+# same master key type.
+
+proc run_once { tag body } {
+    global run_once_tags
+    if ![info exists run_once_tags($tag)] {
+	set run_once_tags($tag) 1
+	uplevel 1 $body
+    }
+}
+
+# check_k5login
+
+# Most of the tests won't work if the user has a .k5login file, unless
+# the user's name appears with $REALMNAME in .k5login
+
+# This procedure returns 1 if the .k5login file appears to be OK, 0
+# otherwise.  This check is not foolproof.
+
+# Note that this previously checked for a username with no realm; this
+# works for krb4's kuserok() but not for krb5_kuserok(), due to some
+# implementation details.  *sigh*
+
+proc check_k5login { testname } {
+    global env
+    global REALMNAME
+
+    if {![file exists ~/.k5login]} {
+	if {$env(USER) == "root"} {
+	    return 0
+	} else {
+	    return 1
+	}
+    }
+
+    verbose "looking for $env(USER)@$REALMNAME in ~/.k5login" 2
+    set file [open ~/.k5login r]
+    while { [gets $file principal] != -1 } {
+	verbose " found $principal" 2
+	if { $principal == "$env(USER)@$REALMNAME" } {
+	    close $file
+	    return 1
+	}
+    }
+    close $file
+
+    note "$testname test requires that your name appear in your ~/.k5login"
+    note "file in the form $env(USER)@$REALMNAME"
+    unsupported "$testname"
+
+    return 0
+}
+
+proc check_klogin { testname } {
+    global env
+    global REALMNAME
+
+    if {![file exists ~/.klogin]} {
+	if {$env(USER) == "root"} {
+	    return 0
+	} else {
+	    return 1
+	}
+    }
+
+    verbose "looking for $env(USER) in ~/.klogin" 2
+    set file [open ~/.klogin r]
+    while { [gets $file principal] != -1 } {
+	verbose " found $principal" 2
+	if { $principal == "$env(USER)" \
+		|| $principal == "$env(USER)@$REALMNAME" } {
+	    close $file
+	    return 1
+	}
+    }
+    close $file
+
+    note "$testname test requires that your name appear in your ~/.klogin"
+    note "file without a realm."
+    unsupported "$testname"
+
+    return 0
+}
+
+# check_exit_status
+# Check the exit status of a spawned program (using the caller's value
+# of spawn_id).  Returns 1 if the program succeeded, 0 if it failed.
+
+proc check_exit_status { testname } {
+    upvar 1 spawn_id spawn_id
+
+    verbose "about to wait ($testname)"
+    set status_list [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $status_list ($testname)"
+    catch "close -i $spawn_id"
+    if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 0 } {
+	verbose -log "exit status: $status_list"
+	fail "$testname"
+	return 0
+    } else {
+	return 1
+    }
+}
+
+#
+# ENVSTACK
+#
+
+# These procedures implement an environment variable stack.  They use
+# the global variable $envvars_tosave for the purpose of identifying
+# which environment variables to save.  They also track which ones are
+# unset at any particular point.  The stack pointer is $envstackp,
+# which is an integer.  The arrays $envstack$envstackp and
+# $unenvstack$envstackp store respectively the set of old environment
+# variables/values pushed onto the stack and the set of old unset
+# environment variables for a given value of $envstackp.
+
+# Changing the value of $envvars_tosave after performing the first
+# push operation may result in strangeness.
+
+#
+# envstack_push
+#
+# Push set of current environment variables.
+#
+proc envstack_push { } {
+    global env
+    global envvars_tosave
+    global envstackp
+    global envstack$envstackp
+    global unenvstack$envstackp
+
+    verbose "envstack_push: starting, sp=$envstackp"
+    foreach i $envvars_tosave {
+	if [info exists env($i)] {
+	    verbose "envstack_push: saving $i=$env($i)"
+	    set envstack${envstackp}($i) $env($i)
+	} {
+	    verbose "envstack_push: marking $i as unset"
+	    set unenvstack${envstackp}($i) unset
+	}
+    }
+    incr envstackp
+    verbose "envstack_push: exiting, sp=$envstackp"
+}
+
+#
+# envstack_pop
+#
+# Pop set of current environment variables.
+#
+proc envstack_pop { } {
+    global env
+    global envstackp
+
+    verbose "envstack_pop: starting, sp=$envstackp"
+    incr envstackp -1
+    global envstack$envstackp	# YUCK!!! no obvious better way though...
+    global unenvstack$envstackp
+    if {$envstackp < 0} {
+	perror "envstack_pop: stack underflow!"
+	return
+    }
+    if [info exists envstack$envstackp] {
+	foreach i [array names envstack$envstackp] {
+	    if [info exists env($i)] {
+		verbose "envstack_pop: $i was $env($i)"
+	    }
+	    eval set env($i) \$envstack${envstackp}($i)
+	    verbose "envstack_pop: restored $i to $env($i)"
+	}
+	unset envstack$envstackp
+    }
+    if [info exists unenvstack$envstackp] {
+	foreach i [array names unenvstack$envstackp] {
+	    if [info exists env($i)] {
+		verbose "envstack_pop: $i was $env($i)"
+		unset env($i)
+		verbose "envstack_pop: $i unset"
+	    } {
+		verbose "envstack_pop: ignoring already unset $i"
+	    }
+	}
+	unset unenvstack$envstackp
+    }
+    verbose "envstack_pop: exiting, sp=$envstackp"
+}
+
+#
+# Initialize the envstack
+#
+set envvars_tosave {
+    KRB5_CONFIG KRB5CCNAME KRBTKFILE KRB5RCACHEDIR
+    KERBEROS_SERVER KRB5_KDC_PROFILE
+}
+set envstackp 0
+envstack_push
+
+# get_hostname
+# This procedure will get the local hostname.  It sets the global
+# variables hostname (the full name) and localhostname (the first part
+# of the name).  Returns 1 on success, 0 on failure.
+
+proc get_hostname { } {
+    global RESOLVE
+    global hostname
+    global localhostname
+    global domain
+    global tmppwd
+
+    if {[info exists hostname] && [info exists localhostname]} {
+	return 1
+    }
+
+    envstack_push
+    catch "exec $RESOLVE -q >$tmppwd/hostname" exec_output
+    envstack_pop
+    if ![string match "" $exec_output] {
+	verbose -log $exec_output
+	perror "can't get hostname"
+	return 0
+    }
+    set file [open $tmppwd/hostname r]
+    if { [ gets $file hostname ] == -1 } {
+	perror "no output from hostname"
+	return 0
+    }
+    close $file
+    file delete $tmppwd/hostname
+    regexp "^(\[^.\]*)\\.(.*)$" $hostname foo localhostname domain
+
+    set hostname [string tolower $hostname]
+    set localhostname [string tolower $localhostname]
+    set domain [string tolower $domain]
+    verbose "hostname: $hostname; localhostname: $localhostname; domain $domain"
+
+    return 1
+}
+
+# modify_principal name options...
+
+proc modify_principal { name args } {
+    global KADMIN_LOCAL
+    global REALMNAME
+
+    envstack_push
+    setup_kerberos_env kdc
+    spawn $KADMIN_LOCAL -r $REALMNAME
+    envstack_pop
+    expect_after {
+	eof {
+	    fail "modprinc (kadmin.local)"
+	    return 0
+	}
+	timeout {
+	    fail "modprinc (kadmin.local)"
+	    return 0
+	}
+    }
+    expect "kadmin.local: "
+    send "modprinc $args $name\r"
+    expect -re "modprinc \[^\n\r\]* $name"
+    expect -re "Principal .* modified."
+    send "quit\r"
+    expect eof
+    catch expect_after
+    if ![check_exit_status "kadmin.local modprinc"] {
+	perror "kadmin.local modprinc exited abnormally"
+    }
+    return 1
+}
+
+# kdc listens on +0..+3, depending whether we're testing reachable or not
+# client tries +1 and +6
+# kadmind +4
+# kpasswd +5
+# (nothing) +6
+# application servers (krlogind, telnetd, krshd, ftpd, etc) +8
+# iprop +9 (if enabled)
+# kpropd +10
+if [info exists PORTBASE] {
+    set portbase $PORTBASE
+} else {
+    set portbase 3085
+}
+
+set ulog 0
+
+# setup_kerberos_files
+# This procedure will create some Kerberos files which must be created
+# manually before trying to run any Kerberos programs.  Returns 1 on
+# success, 0 on failure.
+
+proc setup_kerberos_files { } {
+    global REALMNAME
+    global hostname
+    global domain
+    global tmppwd
+    global supported_enctypes
+    global kdc_supported_enctypes
+    global last_passname_conf
+    global multipass_name
+    global master_key_type
+    global mode
+    global portbase
+    global ulog
+
+    if ![get_hostname] { 
+	return 0
+    }
+
+    setup_krb5_conf client
+    setup_krb5_conf server
+    setup_krb5_conf kdc
+    setup_krb5_conf slave
+
+    # Create a kdc.conf file.
+    if { ![file exists $tmppwd/kdc.conf] \
+	    || $last_passname_conf != $multipass_name } {
+	if ![info exists master_key_type] {
+	    set master_key_type des-cbc-md5
+	}
+	set conffile [open $tmppwd/kdc.conf w]
+	puts $conffile "\[kdcdefaults\]"
+	puts $conffile "	kdc_ports = $portbase,[expr 1 + $portbase],[expr 2 + $portbase]"
+	puts $conffile "	kdc_tcp_ports = $portbase,[expr 1 + $portbase],[expr 2 + $portbase]"
+	puts $conffile ""
+	puts $conffile "\[realms\]"
+	puts $conffile "	$REALMNAME = \{"
+#	puts $conffile "		database_name = $tmppwd/db"
+	puts $conffile "		admin_database_name = $tmppwd/adb"
+	puts $conffile "		admin_database_lockfile = $tmppwd/adb.lock"
+	# Testing with a colon in the name exercises default handling
+	# for pathnames.
+	puts $conffile "		key_stash_file = $tmppwd/stash:foo"
+	puts $conffile "		acl_file = $tmppwd/acl"
+	puts $conffile "		kadmind_port = [expr 4 + $portbase]"
+	puts $conffile "		kpasswd_port = [expr 5 + $portbase]"
+	puts $conffile "		max_life = 1:00:00"
+	puts $conffile "		max_renewable_life = 3:00:00"
+	puts $conffile "		master_key_type = $master_key_type"
+	puts $conffile "		master_key_name = master/key"
+	puts $conffile "		supported_enctypes = $supported_enctypes"
+	puts $conffile "		kdc_supported_enctypes = $kdc_supported_enctypes"
+	if { $mode == "tcp" } {
+	    puts $conffile "		kdc_ports = [expr 3 + $portbase]"
+	    puts $conffile "		kdc_tcp_ports = [expr 1 + $portbase],[expr 3 + $portbase]"
+	} else {
+	    puts $conffile "		kdc_ports = [expr 1 + $portbase]"
+	    puts $conffile "		kdc_tcp_ports = [expr 3 + $portbase]"
+	}
+	puts $conffile "		default_principal_expiration = 2037.12.31.23.59.59"
+	puts $conffile "		default_principal_flags = -postdateable forwardable"
+	puts $conffile "		dict_file = $tmppwd/dictfile"
+	if { $ulog != 0 } {
+	    puts $conffile "		iprop_enable = true"
+	    puts $conffile "		iprop_port = [expr 9 + $portbase]"
+	    puts $conffile "		iprop_logfile = $tmppwd/db.ulog"
+	} else {
+	    puts $conffile "# no ulog"
+	}
+	puts $conffile "	\}"
+	puts $conffile ""
+	close $conffile
+    }
+
+    # Create a config file for the slave KDC (kpropd only, no normal
+    # KDC processes).
+    if { ![file exists $tmppwd/slave.conf] \
+	    || $last_passname_conf != $multipass_name } {
+	if ![info exists master_key_type] {
+	    set master_key_type des-cbc-md5
+	}
+	set conffile [open $tmppwd/slave.conf w]
+	puts $conffile "\[kdcdefaults\]"
+	puts $conffile "	kdc_ports = $portbase,[expr 1 + $portbase],[expr 2 + $portbase]"
+	puts $conffile "	kdc_tcp_ports = $portbase,[expr 1 + $portbase],[expr 2 + $portbase]"
+	puts $conffile ""
+	puts $conffile "\[realms\]"
+	puts $conffile "	$REALMNAME = \{"
+#	puts $conffile "		database_name = $tmppwd/slave-db"
+	puts $conffile "		admin_database_name = $tmppwd/slave-adb"
+	puts $conffile "		admin_database_lockfile = $tmppwd/slave-adb.lock"
+	# Testing with a colon in the name exercises default handling
+	# for pathnames.
+	puts $conffile "		key_stash_file = $tmppwd/slave-stash"
+	puts $conffile "		acl_file = $tmppwd/slave-acl"
+	puts $conffile "		kadmind_port = [expr 4 + $portbase]"
+	puts $conffile "		kpasswd_port = [expr 5 + $portbase]"
+	puts $conffile "		max_life = 1:00:00"
+	puts $conffile "		max_renewable_life = 3:00:00"
+	puts $conffile "		master_key_type = $master_key_type"
+	puts $conffile "		master_key_name = master/key"
+	puts $conffile "		supported_enctypes = $supported_enctypes"
+	puts $conffile "		kdc_supported_enctypes = $kdc_supported_enctypes"
+	if { $mode == "tcp" } {
+	    puts $conffile "		kdc_ports = [expr 3 + $portbase]"
+	    puts $conffile "		kdc_tcp_ports = [expr 1 + $portbase],[expr 3 + $portbase]"
+	} else {
+	    puts $conffile "		kdc_ports = [expr 1 + $portbase]"
+	    puts $conffile "		kdc_tcp_ports = [expr 3 + $portbase]"
+	}
+	puts $conffile "		default_principal_expiration = 2037.12.31.23.59.59"
+	puts $conffile "		default_principal_flags = -postdateable forwardable"
+	puts $conffile "		dict_file = $tmppwd/dictfile"
+	if { $ulog != 0 } {
+	    puts $conffile "		iprop_enable = true"
+	    puts $conffile "		iprop_port = [expr 9 + $portbase]"
+	    puts $conffile "		iprop_logfile = $tmppwd/slave-db.ulog"
+	} else {
+	    puts $conffile "# no ulog"
+	}
+	puts $conffile "	\}"
+	puts $conffile ""
+	close $conffile
+    }
+
+    # Create ACL file.
+    if ![file exists $tmppwd/acl] {
+	set aclfile [open $tmppwd/acl w]
+	puts $aclfile "krbtest/admin@$REALMNAME *"
+	puts $aclfile "kiprop/$hostname@$REALMNAME p"
+	close $aclfile
+    }
+
+    # Create dictfile file.
+    if ![file exists $tmppwd/dictfile] {
+	set dictfile [open $tmppwd/dictfile w]
+	puts $dictfile "weak_password"
+	close $dictfile
+    }
+
+    set last_passname_conf $multipass_name
+    return 1
+}
+
+proc reset_kerberos_files { } {
+    global tmppwd
+    file delete $tmppwd/kdc.conf $tmppwd/slave.conf $tmppwd/krb5.client.conf \
+	$tmppwd/krb5.server.conf $tmppwd/krb5.kdc.conf
+    setup_kerberos_files
+}
+
+proc setup_krb5_conf { {type client} } {
+    global tmppwd
+    global hostname
+    global domain
+    global REALMNAME
+    global last_passname_conf
+    global multipass_name
+    global default_tgs_enctypes
+    global default_tkt_enctypes
+    global permitted_enctypes
+    global mode
+    global portbase
+
+    # Create a krb5.conf file.
+    if { ![file exists $tmppwd/krb5.$type.conf] \
+	    || $last_passname_conf != $multipass_name } {
+	set conffile [open $tmppwd/krb5.$type.conf w]
+	puts $conffile "\[libdefaults\]"
+	puts $conffile "	default_realm = $REALMNAME"
+	puts $conffile "	dns_lookup_kdc = false"
+	puts $conffile "	allow_weak_crypto = true"
+	if [info exists default_tgs_enctypes($type)] {
+	    puts $conffile \
+		    "	default_tgs_enctypes = $default_tgs_enctypes($type)"
+	}
+	if [info exists default_tkt_enctypes($type)] {
+	    puts $conffile \
+		    "	default_tkt_enctypes = $default_tkt_enctypes($type)"
+	}
+	if [info exists permitted_enctypes($type)] {
+	    puts $conffile \
+		    "	permitted_enctypes = $permitted_enctypes($type)"
+	}
+	if { $mode == "tcp" } {
+	    puts $conffile "	udp_preference_limit = 1"
+	}
+	puts $conffile ""
+	puts $conffile "\[realms\]"
+	puts $conffile "	$REALMNAME = \{"
+	# There's probably nothing listening here.  It would be a good
+	# test for the handling of a non-responsive KDC address.  However,
+	# on some systems, like Tru64, we often wind up with the client's
+	# socket bound to this address, causing our request to appear in
+	# our incoming queue as if it were a response, which causes test
+	# failures.  If we were running the client and KDC on different
+	# hosts, this would be okay....
+	#puts $conffile "		kdc = $hostname:[expr 6 + $portbase]"
+	puts $conffile "		kdc = $hostname:[expr 1 + $portbase]"
+	puts $conffile "		admin_server = $hostname:[expr 4 + $portbase]"
+	puts $conffile "		kpasswd_server = $hostname:[expr 5 + $portbase]"
+	puts $conffile "		default_domain = $domain"
+	puts $conffile "		database_module = foo_db2"
+	puts $conffile "	\}"
+	puts $conffile ""
+	puts $conffile "\[domain_realm\]"
+	puts $conffile "	.$domain = $REALMNAME"
+	puts $conffile "	$domain = $REALMNAME"
+	puts $conffile ""
+	puts $conffile "\[logging\]"
+	puts $conffile "	admin_server = FILE:$tmppwd/kadmind5.log"
+	puts $conffile "	kdc = FILE:$tmppwd/kdc.log"
+	puts $conffile "	default = FILE:$tmppwd/others.log"
+	puts $conffile ""
+	puts $conffile "\[dbmodules\]"
+	puts $conffile "	foo_db2 = {"
+	puts $conffile "		db_library = db2"
+	puts $conffile "		database_name = $tmppwd/$type-db"
+	puts $conffile "	}"
+	close $conffile
+    }
+}
+
+# Save the original values of the environment variables we are going
+# to muck with.
+
+# XXX deal with envstack later.
+
+if [info exists env(KRB5_CONFIG)] {
+    set orig_krb5_conf $env(KRB5_CONFIG)
+} else {
+    catch "unset orig_krb5_config"
+}
+
+if [info exists env(KRB5CCNAME)] {
+    set orig_krb5ccname $env(KRB5CCNAME)
+} else {
+    catch "unset orig_krb5ccname"
+}
+
+if [ info exists env(KRB5RCACHEDIR)] {
+    set orig_krb5rcachedir $env(KRB5RCACHEDIR)
+} else {
+    catch "unset orig_krb5rcachedir"
+}
+
+if [ info exists env(KERBEROS_SERVER)] {
+    set orig_kerberos_server $env(KERBEROS_SERVER)
+} else {
+    catch "unset orig_kerberos_server"
+}
+
+# setup_kerberos_env
+# Set the environment variables needed to run Kerberos programs.
+
+proc setup_kerberos_env { {type client} } {
+    global REALMNAME
+    global env
+    global tmppwd
+    global hostname
+    global portbase
+
+    # Set the environment variable KRB5_CONFIG to point to our krb5.conf file.
+    # All the Kerberos tools check KRB5_CONFIG.
+    # Actually, V5 doesn't currently use this.
+    set env(KRB5_CONFIG) $tmppwd/krb5.$type.conf
+    verbose "KRB5_CONFIG=$env(KRB5_CONFIG)"
+
+    # Direct the Kerberos programs at a local ticket file.
+    set env(KRB5CCNAME) $tmppwd/tkt
+    verbose "KRB5CCNAME=$env(KRB5CCNAME)"
+
+    # Direct the Kerberos server at a cache file stored in the
+    # temporary directory.
+    set env(KRB5RCACHEDIR) $tmppwd
+    verbose "KRB5RCACHEDIR=$env(KRB5RCACHEDIR)"
+
+    # Tell the Kerberos tools how to contact the $REALMNAME server.
+    set env(KERBEROS_SERVER) "$REALMNAME:$hostname:[expr 1 + $portbase]"
+    verbose "KERBEROS_SERVER=$env(KERBEROS_SERVER)"
+
+    # Set our kdc config file, if needed.
+    switch $type {
+	client	-
+	server	{ catch {unset env(KRB5_KDC_PROFILE)} }
+	kdc	{ set env(KRB5_KDC_PROFILE) $tmppwd/kdc.conf }
+	slave	{ set env(KRB5_KDC_PROFILE) $tmppwd/slave.conf }
+	default	{ error "unknown config file type $type" }
+    }
+    if [info exists env(KRB5_KDC_PROFILE)] {
+	verbose "KRB5_KDC_PROFILE=$env(KRB5_KDC_PROFILE)"
+    }
+
+    # Create an environment setup script.  (For convenience)
+    if ![file exists $tmppwd/$type-env.sh] {
+	set envfile [open $tmppwd/$type-env.sh w]
+	puts $envfile "KRB5_CONFIG=$env(KRB5_CONFIG)"
+	puts $envfile "KRB5CCNAME=$env(KRB5CCNAME)"
+	puts $envfile "KRB5RCACHEDIR=$env(KRB5RCACHEDIR)"
+	puts $envfile "KERBEROS_SERVER=$env(KERBEROS_SERVER)"
+	if [info exists env(KRB5_KDC_PROFILE)] {
+	    puts $envfile "KRB5_KDC_PROFILE=$env(KRB5_KDC_PROFILE)"
+	} else {
+	    puts $envfile "unset KRB5_KDC_PROFILE"
+	}
+	puts $envfile "export KRB5_CONFIG KRB5CCNAME KRB5RCACHEDIR"
+	puts $envfile "export KERBEROS_SERVER KRB5_KDC_PROFILE"
+	close $envfile
+    }
+    if ![file exists $tmppwd/$type-env.csh] {
+	set envfile [open $tmppwd/$type-env.csh w]
+	puts $envfile "setenv KRB5_CONFIG $env(KRB5_CONFIG)"
+	puts $envfile "setenv KRB5CCNAME $env(KRB5CCNAME)"
+	puts $envfile "setenv KRB5RCACHEDIR $env(KRB5RCACHEDIR)"
+	puts $envfile "setenv KERBEROS_SERVER $env(KERBEROS_SERVER)"
+	if [info exists env(KRB5_KDC_PROFILE)] {
+	    puts $envfile "setenv KRB5_KDC_PROFILE $env(KRB5_KDC_PROFILE)"
+	} else {
+	    puts $envfile "unsetenv KRB5_KDC_PROFILE"
+	}
+	close $envfile
+    }
+    return 1
+}
+
+# Restore the Kerberos environment, in case setup_kerberos_env was
+# already called by an earlier test.
+
+proc restore_kerberos_env { } {
+    global env
+    global orig_krb5_config
+    global orig_krb5ccname
+    global orig_krb5rcachedir
+    global orig_kerberos_server
+
+    if [info exists orig_krb5_config] {
+    set env(KRB5_CONFIG) $orig_krb5_config
+    } else {
+    catch "unset env(KRB5_CONFIG)"
+    }
+
+    if [info exists orig_krb5ccname] {
+	set env(KRB5CCNAME) $orig_krb5ccname
+    } else {
+	catch "unset env(KRB5CCNAME)"
+    }
+
+    if [info exists orig_krb5rcachedir] {
+	set env(KRB5RCACHEDIR) $orig_krb5rcachedir
+    } else {
+	catch "unset env(KRB5RCACHEDIR)"
+    }
+
+    if [info exists orig_kerberos_server] {
+	set env(KERBEROS_SERVER) $orig_kerberos_server
+    } else {
+	catch "unset env(KERBEROS_SERVER)"
+    }
+
+}
+
+# setup_kerberos_db
+# Initialize the Kerberos database.  If the argument is non-zero, call
+# pass at relevant points.  Returns 1 on success, 0 on failure.
+
+proc setup_kerberos_db { standalone } {
+    global REALMNAME KDB5_UTIL KADMIN_LOCAL KEY
+    global tmppwd hostname
+    global spawn_id
+    global des3_krbtgt tgt_support_desmd5
+    global multipass_name last_passname_db
+
+    set failall 0
+
+    if {!$standalone && [file exists $tmppwd/kdc-db.ok] \
+	&& $last_passname_db == $multipass_name} {
+	return 1
+    }
+
+    delete_db
+
+    envstack_push
+    if { ![setup_kerberos_files] || ![setup_kerberos_env kdc] } {
+	set failall 1
+    }
+
+    # Set up a common expect_after for use in multiple places.
+    set def_exp_after {
+	timeout {
+	    set test "$test (timeout)"
+	    break
+	}
+	eof {
+	    set test "$test (eof)"
+	    break
+	}
+    }
+
+    set test "kdb5_util create"
+    set body {
+	if $failall {
+	    break
+	}
+	#exec xterm
+	verbose "starting $test"
+	spawn $KDB5_UTIL -r $REALMNAME create -W
+	expect_after $def_exp_after
+
+	expect "Enter KDC database master key:"
+
+	set test "kdb5_util create (verify)"
+	send "masterkey$KEY\r"
+	expect "Re-enter KDC database master key to verify:"
+
+	set test "kdb5_util create"
+	send "masterkey$KEY\r"
+	expect {
+	    -re "\[Cc\]ouldn't" {
+		expect eof
+		break
+	    }
+	    "Cannot find/read stored" exp_continue
+	    "Warning: proceeding without master key" exp_continue
+	    eof { }
+	}
+	catch expect_after
+	if ![check_exit_status kdb5_util] {
+	    break
+	}
+    }
+    set ret [catch $body]
+    catch expect_after
+    if $ret {
+	set failall 1
+	if $standalone {
+	    fail $test
+	}
+    } else {
+	if $standalone {
+	    pass $test
+	}
+    }
+
+    # Stash the master key in a file.
+    set test "kdb5_util stash"
+    set body {
+	if $failall {
+	    break
+	}
+	spawn $KDB5_UTIL  -r $REALMNAME stash
+	verbose "starting $test"
+	expect_after $def_exp_after
+	expect "Enter KDC database master key:"
+	send "masterkey$KEY\r"
+	expect eof
+	catch expect_after
+	if ![check_exit_status kdb5_util] {
+	    break
+	}
+    }
+    set ret [catch $body]
+    catch "expect eof"
+    catch expect_after
+    if $ret {
+	set failall 1
+	if $standalone {
+	    fail $test
+	} else {
+	    delete_db
+	}
+    } else {
+	if $standalone {
+	    pass $test
+	}
+    }
+
+    # Add an admin user.
+    set test "kadmin.local ank krbtest/admin"
+    set body {
+	if $failall {
+	    break
+	}
+	spawn $KADMIN_LOCAL -r $REALMNAME
+	verbose "starting $test"
+	expect_after $def_exp_after
+
+	expect "kadmin.local: "
+	send "ank krbtest/admin@$REALMNAME\r"
+	# It echos...
+	expect "ank krbtest/admin@$REALMNAME\r"
+	expect "Enter password for principal \"krbtest/admin@$REALMNAME\":"
+	send "adminpass$KEY\r"
+	expect "Re-enter password for principal \"krbtest/admin@$REALMNAME\":"
+	send "adminpass$KEY\r"
+	expect {
+	    "Principal \"krbtest/admin@$REALMNAME\" created" { }
+	    "Principal or policy already exists while creating*" { }
+	}
+	expect "kadmin.local: "
+	send "quit\r"
+	expect eof
+	catch expect_after
+	if ![check_exit_status kadmin_local] {
+	    break
+	}
+    }
+    set ret [catch $body]
+    catch "expect eof"
+    catch expect_after
+    if $ret {
+	set failall 1
+	if $standalone {
+	    fail $test
+	} else {
+	    delete_db
+	}
+    } else {
+	if $standalone {
+	    pass $test
+	}
+    }
+
+    # Add an incremental-propagation service.
+    set test "kadmin.local ank kiprop/$hostname"
+    set body {
+	if $failall {
+	    break
+	}
+	spawn $KADMIN_LOCAL -r $REALMNAME
+	verbose "starting $test"
+	expect_after $def_exp_after
+
+	expect "kadmin.local: "
+	send "ank kiprop/$hostname@$REALMNAME\r"
+	# It echos...
+	expect "ank kiprop/$hostname@$REALMNAME\r"
+	expect "Enter password for principal \"kiprop/$hostname@$REALMNAME\":"
+	send "kiproppass$KEY\r"
+	expect "Re-enter password for principal \"kiprop/$hostname@$REALMNAME\":"
+	send "kiproppass$KEY\r"
+	expect {
+	    "Principal \"kiprop/$hostname@$REALMNAME\" created" { }
+	    "Principal or policy already exists while creating*" { }
+	}
+	expect "kadmin.local: "
+	send "quit\r"
+	expect eof
+	catch expect_after
+	if ![check_exit_status kadmin_local] {
+	    break
+	}
+    }
+    set ret [catch $body]
+    catch "expect eof"
+    catch expect_after
+    if $ret {
+	set failall 1
+	if $standalone {
+	    fail $test
+	} else {
+	    delete_db
+	}
+    } else {
+	if $standalone {
+	    pass $test
+	}
+    }
+
+    if $des3_krbtgt {
+	# Set the TGT key to DES3.
+	set test "kadmin.local TGT to DES3"
+	set body {
+	    if $failall {
+		break
+	    }
+	    spawn $KADMIN_LOCAL -r $REALMNAME -e des3-cbc-sha1:normal
+	    verbose "starting $test"
+	    expect_after $def_exp_after
+
+	    expect "kadmin.local: "
+	    send "cpw -randkey krbtgt/$REALMNAME@$REALMNAME\r"
+	    # It echos...
+	    expect "cpw -randkey krbtgt/$REALMNAME@$REALMNAME\r"
+	    expect {
+		"Key for \"krbtgt/$REALMNAME@$REALMNAME\" randomized." { }
+	    }
+	    expect "kadmin.local: "
+	    send "quit\r"
+	    expect eof
+	    catch expect_after
+	    if ![check_exit_status kadmin_local] {
+		break
+	    }
+	}
+	set ret [catch $body]
+	catch "expect eof"
+	catch expect_after
+	if $ret {
+	    set failall 1
+	    if $standalone {
+		fail $test
+	    } else {
+		delete_db
+	    }
+	} else {
+	    if $standalone {
+		pass $test
+	    }
+	}
+    }
+    if $tgt_support_desmd5 {
+	# Make TGT support des-cbc-md5
+	set test "kadmin.local TGT to SUPPORT_DESMD5"
+	set body {
+	    if $failall {
+		break
+	    }
+	    spawn $KADMIN_LOCAL -r $REALMNAME
+	    verbose "starting $test"
+	    expect_after $def_exp_after
+
+	    expect "kadmin.local: "
+	    send "modprinc +support_desmd5 krbtgt/$REALMNAME@$REALMNAME\r"
+	    # It echos...
+	    expect "modprinc +support_desmd5 krbtgt/$REALMNAME@$REALMNAME\r"
+	    expect {
+		"Principal \"krbtgt/$REALMNAME@$REALMNAME\" modified.\r\n" { }
+	    }
+	    expect "kadmin.local: "
+	    send "quit\r"
+	    expect eof
+	    catch expect_after
+	    if ![check_exit_status kadmin_local] {
+		break
+	    }
+	}
+	set ret [catch $body]
+	catch "expect eof"
+	catch expect_after
+	if $ret {
+	    set failall 1
+	    if $standalone {
+		fail $test
+	    } else {
+		delete_db
+	    }
+	} else {
+	    if $standalone {
+		pass $test
+	    }
+	}
+    }
+    envstack_pop
+
+    # create the admin database lock file
+    catch "exec touch $tmppwd/adb.lock"
+
+    set last_passname_db $multipass_name
+    return 1
+}
+
+proc start_tail { fname spawnid_var pid_var which standalone } {
+    upvar $spawnid_var spawnid
+    upvar $pid_var pid
+    global timeout
+
+    set f [open $fname a]
+
+    spawn tail -f $fname
+    set spawnid $spawn_id
+    set pid [exp_pid]
+
+    set markstr "===MARK $pid [clock format [clock seconds]] ==="
+    puts $f $markstr
+    flush $f
+
+    set p 0
+    set otimeout $timeout
+    set timeout 3
+    set ok 0
+    while { $ok == 0 && $p < 3 } {
+	expect {
+	    -i $spawn_id
+	    -ex "$markstr" { set ok 1 }
+	    -re "\[^\r\n\]*\r\n" { exp_continue }
+	    timeout {
+		# Some versions of GNU tail had a race condition where
+		# the first batch of data would be read from the end
+		# of the file, and then there was a brief window
+		# before calling stat and recording the size of the
+		# file.  If the marker is written during that window,
+		# then yet another file modification is needed to get
+		# the first one noticed.
+		if { $p < 3 } {
+		    verbose -log "no tail output yet, prodding with a blank line"
+		    incr p
+		    puts $f ""
+		    flush $f
+		    exp_continue
+		} else {
+		    close $f
+		    verbose -log "tail $fname output:"
+		    verbose -log [exec tail $fname]
+		    if {$standalone} {
+			verbose -log "tail -f timed out ($timeout sec) looking for mark in $which log"
+			fail "$which"
+		    } else {
+			perror "$which tail -f timed out ($timeout sec) looking for mark in $which log"
+		    }
+		    stop_kerberos_daemons
+		    exec kill $pid
+		    expect -i $spawn_id eof
+		    wait -i $spawn_id
+		    set timeout $otimeout
+		    return 0
+		}
+	    }
+	}
+    }
+    close $f
+    set timeout $otimeout
+    return 1
+}
+
+# start_kerberos_daemons
+# A procedure to build a Kerberos database and start up the kerberos
+# and kadmind daemons.  This sets the global variables kdc_pid,
+# kdc_spawn_id, kadmind_pid, and kadmind_spawn_id.  The procedure
+# stop_kerberos_daemons should be used to stop the daemons.  If the
+# argument is non-zero, call pass at relevant points.  Returns 1 on
+# success, 0 on failure.
+
+proc start_kerberos_daemons { standalone } {
+    global BINSH
+    global REALMNAME
+    global KRB5KDC
+    global KADMIND
+    global KEY
+    global kdc_pid
+    global kdc_spawn_id
+    global kadmind_pid
+    global kadmind_spawn_id
+    global tmppwd
+    global env
+    global timeout
+
+    if ![setup_kerberos_db 0] {
+	return 0
+    }
+
+    if {$standalone} {
+        file delete $tmppwd/krb.log $tmppwd/kadmind.log $tmppwd/krb5kdc_rcache
+    }
+
+    # Start up the kerberos daemon
+    # Why are we doing all this with the log file you may ask.
+    #   We need a handle on when the server starts. If we log the output
+    #   of the server to say stderr, then if we stop looking for output,
+    #   buffers will fill and the server will stop working....
+    #   So, we look to see when a line is added to the log file and then
+    #   check it..
+    # The same thing is done a little later for the kadmind
+    set kdc_lfile $tmppwd/kdc.log
+    set kadmind_lfile $tmppwd/kadmind5.log
+
+    if ![start_tail $kdc_lfile tailf_spawn_id tailf_pid krb5kdc $standalone] {
+	return 0
+    }
+
+    envstack_push
+    setup_kerberos_env kdc
+    spawn $KRB5KDC -r $REALMNAME -n full
+    envstack_pop
+    set kdc_pid [exp_pid]
+    set kdc_spawn_id $spawn_id
+
+    expect {
+	-i $tailf_spawn_id
+	-re "commencing operation\r\n" { }
+	-re "krb5kdc: \[a-zA-Z\]* - Cannot bind server socket to \[ 0-9a-fA-F:.\]*\r\n" {
+	    verbose -log "warning: $expect_out(0,string)"
+	    exp_continue
+	}
+	"no sockets set up?" {
+	    if {$standalone} {
+		verbose -log "krb5kdc startup failed to bind listening sockets"
+		fail "krb5kdc"
+	    } else {
+		perror "krb5kdc startup failed to bind listening sockets"
+	    }
+	    stop_kerberos_daemons
+	    exec kill $tailf_pid
+	    expect -i $tailf_spawn_id eof
+	    wait -i $tailf_spawn_id
+	    return 0
+	}
+	timeout {
+	    if {$standalone} {
+		verbose -log "krb5kdc startup timed out"
+		fail "krb5kdc"
+	    } else {
+		perror "krb5kdc startup timed out"
+	    }
+	    stop_kerberos_daemons
+	    exec kill $tailf_pid
+	    expect -i $tailf_spawn_id eof
+	    wait -i $tailf_spawn_id
+	    return 0
+	}
+    }
+    exec kill $tailf_pid
+    expect -i $tailf_spawn_id eof
+    wait -i $tailf_spawn_id
+
+    if {$standalone} {
+	pass "krb5kdc"
+    }
+
+    # Give the kerberos daemon a few seconds to get set up.
+#    sleep 2
+
+    #
+    # Save setting of KRB5_KTNAME. We do not want to override kdc.conf
+    # file during kadmind startup. (this is in case user has KRB5_KTNAME
+    # set before starting make check)
+    #
+    if [info exists env(KRB5_KTNAME)] {
+	set start_save_ktname $env(KRB5_KTNAME)
+    }
+    catch "unset env(KRB5_KTNAME)"
+
+    if ![start_tail $kadmind_lfile tailf_spawn_id tailf_pid kadmind $standalone] {
+	return 0
+    }
+
+    # Start up the kadmind daemon
+    # XXXX kadmind uses stderr a lot.  the sh -c and redirect can be
+    # removed when this is fixed
+    envstack_push
+    setup_kerberos_env kdc
+    spawn $BINSH -c "exec $KADMIND -r $REALMNAME -W -nofork 2>>$kadmind_lfile"
+    envstack_pop
+    set kadmind_pid [exp_pid]
+    set kadmind_spawn_id $spawn_id
+
+    # Restore KRB5_KTNAME
+    if [info exists start_save_ktname] {
+        set env(KRB5_KTNAME) $start_save_ktname
+        unset start_save_ktname
+    }
+
+    expect {
+	-i $tailf_spawn_id
+	"Seeding random number" exp_continue
+	"cannot initialize network" {
+	    if {$standalone} {
+		verbose -log "kadmind failed network init"
+		fail "kadmind"
+	    } else {
+		perror "kadmind failed network init"
+	    }
+	    stop_kerberos_daemons
+	    exec kill $tailf_pid
+	    expect -i $tailf_spawn_id eof
+	    wait -i $tailf_spawn_id
+	    return 0
+	}
+	"cannot bind to network address" {
+	    if {$standalone} {
+		verbose -log "kadmind failed to bind socket"
+		fail "kadmind"
+	    } else {
+		perror "kadmind failed to bind socket"
+	    }
+	    stop_kerberos_daemons
+	    exec kill $tailf_pid
+	    expect -i $tailf_spawn_id eof
+	    wait -i $tailf_spawn_id
+	    return 0
+	}
+	"No principal in keytab matches desired name" {
+	    dump_db
+	    exp_continue
+	}
+	"starting" { }
+	timeout {
+	    if {$standalone} {
+		verbose -log "kadmind failed to start"
+		fail "kadmind"
+	    } else {
+		verbose -log "kadmind failed to start"
+		perror "kadmind failed to start"
+	    }
+#sleep 10
+	    stop_kerberos_daemons
+	    exec kill $tailf_pid
+	    expect -i $tailf_spawn_id eof
+	    wait -i $tailf_spawn_id
+	    return 0
+	}
+    }
+    exec kill $tailf_pid
+    expect -i $tailf_spawn_id eof
+    wait -i $tailf_spawn_id
+
+    if {$standalone} {
+	pass "kadmind"
+    }
+
+    # Give the kadmind daemon a few seconds to get set up.
+#    sleep 2
+
+    return 1
+}
+
+# stop_kerberos_daemons
+# Stop the kerberos daemons.  Returns 1 on success, 0 on failure.
+
+proc stop_kerberos_daemons { } {
+    global kdc_pid
+    global kdc_spawn_id
+    global kadmind_pid
+    global kadmind_spawn_id
+
+    verbose "entered stop_kerberos_daemons"
+
+    if [info exists kdc_pid] {
+	if [catch "exec kill $kdc_pid" msg] {
+	    verbose "kill kdc: $msg"
+	}
+	if [catch "expect -i $kdc_spawn_id eof" msg] {
+	    verbose "expect kdc eof: $msg"
+	}
+	set kdc_list [wait -i $kdc_spawn_id]
+	verbose "wait -i $kdc_spawn_id returned $kdc_list (kdc)"
+	unset kdc_pid
+	unset kdc_list
+    }
+
+    if [info exists kadmind_pid] {
+	if [catch "exec kill $kadmind_pid" msg] {
+	    verbose "kill kadmind: $msg"
+	}
+	if [catch "expect -i $kadmind_spawn_id eof" msg] {
+	    verbose "expect kadmind eof: $msg"
+	}
+	set kadmind_list [wait -i $kadmind_spawn_id]
+	verbose "wait -i $kadmind_spawn_id returned $kadmind_list (kadmind5)"
+	unset kadmind_pid
+	unset kadmind_list
+    }
+
+    verbose "exiting stop_kerberos_daemons"
+
+    return 1
+}
+
+# add_kerberos_key
+# Add an key to the Kerberos database.  start_kerberos_daemons must be
+# called before this procedure.  If the standalone argument is
+# non-zero, call pass at relevant points.  Returns 1 on success, 0 on
+# failure.
+
+proc add_kerberos_key { kkey standalone } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+
+    # Use kadmin to add an key.
+    set test "kadmin ank $kkey"
+    set body {
+	envstack_push
+	setup_kerberos_env client
+	spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank $kkey@$REALMNAME"
+	envstack_pop
+	verbose "starting $test"
+	expect_after {
+	    "Cannot contact any KDC" {
+		set test "$test (lost KDC)"
+		break
+	    }
+	    timeout {
+		set test "$test (timeout)"
+		break
+	    }
+	    eof {
+		set test "$test (eof)"
+		break
+	    }
+	}
+	expect -re "assword\[^\r\n\]*: *"
+	send "adminpass$KEY\r"
+	expect "Enter password for principal \"$kkey@$REALMNAME\":"
+	send "$kkey"
+	send "$KEY\r"
+	expect "Re-enter password for principal \"$kkey@$REALMNAME\":"
+	send "$kkey"
+	send "$KEY\r"
+	expect {
+	    "Principal \"$kkey@$REALMNAME\" created" { }
+	    "Principal or policy already exists while creating*" { }
+	}
+	expect eof
+	if ![check_exit_status kadmin] {
+	    break
+	}
+    }
+    set ret [catch $body]
+    catch "expect eof"
+    catch expect_after
+    if $ret {
+	if $standalone {
+	    fail $test
+	}
+	return 0
+    } else {
+	if $standalone {
+	    pass $test
+	}
+	return 1
+    }
+}
+
+# dump_db
+proc dump_db { } {
+    global KADMIN_LOCAL
+    global REALMNAME
+
+    spawn $KADMIN_LOCAL -r $REALMNAME
+    expect_after {
+	eof {
+	    perror "failed to get debugging dump of database (eof)"
+	}
+	timeout {
+	    perror "failed to get debugging dump of database (timeout)"
+	}
+    }
+    expect "kadmin.local: "
+    send "getprincs\r"
+    expect "kadmin.local: "
+    send "quit\r"
+    expect eof
+    catch expect_after
+}
+
+# add_random_key
+# Add a key with a random password to the Kerberos database.
+# start_kerberos_daemons must be called before this procedure.  If the
+# standalone argument is non-zero, call pass at relevant points.
+# Returns 1 on success, 0 on failure.
+
+proc add_random_key { kkey standalone } {
+    global REALMNAME
+    global KADMIN
+    global KEY
+    global spawn_id
+
+    # Use kadmin to add an key.
+    set test "kadmin ark $kkey"
+    set body {
+	envstack_push
+	setup_kerberos_env client
+	spawn $KADMIN -p krbtest/admin@$REALMNAME -q "ank -randkey $kkey@$REALMNAME"
+	envstack_pop
+	expect_after {
+	    timeout {
+		set test "$test (timeout)"
+		break
+	    }
+	    eof {
+		set test "$test (eof)"
+		break
+	    }
+	}
+	expect -re "assword\[^\r\n\]*: *"
+	send "adminpass$KEY\r"
+	expect {
+	    "Principal \"$kkey@$REALMNAME\" created" { }
+	    "Principal or policy already exists while creating*" { }
+	}
+	expect eof
+	if ![check_exit_status kadmin] {
+	    break
+	}
+    }
+    if [catch $body] {
+	catch expect_after
+	if $standalone {
+	    fail $test
+	}
+	return 0
+    } else {
+	catch expect_after
+	if $standalone {
+	    pass $test
+	}
+	return 1
+    }
+}
+
+# setup_srvtab
+# Set up a srvtab file.  start_kerberos_daemons and add_random_key
+# $id/$hostname must be called before this procedure.  If the
+# argument is non-zero, call pass at relevant points.  Returns 1 on
+# success, 0 on failure. If the id field is not provided, host is used.
+
+proc setup_srvtab { standalone {id host} } {
+    global REALMNAME
+    global KADMIN_LOCAL
+    global KEY
+    global tmppwd
+    global hostname
+    global spawn_id
+    global last_service
+
+    if {!$standalone && [file exists $tmppwd/srvtab] && $last_service == $id} {
+	return 1
+    }
+
+    file delete $tmppwd/srvtab $tmppwd/srvtab.old
+
+    if ![get_hostname] {
+	return 0
+    }
+
+    file delete $hostname-new-srvtab
+
+    envstack_push
+    setup_kerberos_env kdc
+    spawn $KADMIN_LOCAL -r $REALMNAME
+    envstack_pop
+    expect_after {
+	-re "(.*)\r\nkadmin.local:  " {
+	    fail "kadmin.local srvtab (unmatched output: $expect_out(1,string))"
+	    if {!$standalone} {
+		file delete $tmppwd/srvtab
+	    }
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin.local srvtab"
+	    if {!$standalone} {
+		file delete $tmppwd/srvtab
+	    }
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin.local srvtab"
+	    if {!$standalone} {
+		file delete $tmppwd/srvtab
+	    }
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect "kadmin.local:  "
+    send "xst -k $hostname-new-srvtab $id/$hostname kiprop/$hostname\r"
+    expect "xst -k $hostname-new-srvtab $id/$hostname kiprop/$hostname\r\n"
+    expect {
+	-re ".*Entry for principal $id/$hostname.* added to keytab WRFILE:$hostname-new-srvtab." { }
+	-re "\r\nkadmin.local:  " {
+	    if {$standalone} {
+		fail "kadmin.local srvtab"
+	    } else {
+		file delete $tmppwd/srvtab
+	    }
+	    catch expect_after
+	    return 0
+	}
+    }
+    expect "kadmin.local:  "
+    send "quit\r"
+    expect eof
+    catch expect_after
+    if ![check_exit_status "kadmin.local srvtab"] {
+	if {!$standalone} {
+	    file delete $tmppwd/srvtab
+	}
+	return 0
+    }
+
+    catch "exec mv -f $hostname-new-srvtab $tmppwd/srvtab" exec_output
+    if ![string match "" $exec_output] {
+	verbose -log "$exec_output"
+	perror "can't mv new srvtab"
+	return 0
+    }
+
+    if {$standalone} {
+	pass "kadmin.local srvtab"
+    }
+
+    # Make the srvtab file globally readable in case we are using a
+    # root shell and the srvtab is NFS mounted.
+    catch "exec chmod a+r $tmppwd/srvtab"
+
+    # Remember what we just extracted
+    set last_service $id
+
+    return 1
+}
+
+# kinit
+# Use kinit to get a ticket.  If the argument is non-zero, call pass
+# at relevant points.  Returns 1 on success, 0 on failure.
+
+proc kinit { name pass standalone } {
+    global REALMNAME
+    global KINIT
+    global spawn_id
+
+    # Use kinit to get a ticket.
+	#
+	# For now always get forwardable tickets. Later when we need to make
+	# tests that distiguish between forwardable tickets and otherwise
+	# we should but another option to this proc. --proven
+	#
+    spawn $KINIT -5 -f $name@$REALMNAME
+    expect {
+	"Password for $name@$REALMNAME:" {
+	    verbose "kinit started"
+	}
+	timeout {
+	    fail "kinit"
+	    return 0
+	}
+	eof {
+	    fail "kinit"
+	    return 0
+	}
+    }
+    send "$pass\r"
+    expect eof
+    if ![check_exit_status kinit] {
+	return 0
+    }
+
+    if {$standalone} {
+	pass "kinit"
+    }
+
+    return 1
+}
+
+proc kinit_kt { name keytab standalone testname } {
+    global REALMNAME
+    global KINIT
+    global spawn_id
+
+    # Use kinit to get a ticket.
+	#
+	# For now always get forwardable tickets. Later when we need to make
+	# tests that distiguish between forwardable tickets and otherwise
+	# we should but another option to this proc. --proven
+	#
+    spawn $KINIT -5 -f -k -t $keytab $name@$REALMNAME
+    expect {
+	timeout {
+	    fail "kinit $testname"
+	    return 0
+	}
+	eof { }
+    }
+    if ![check_exit_status "kinit $testname"] {
+	return 0
+    }
+
+    if {$standalone} {
+	pass "kinit $testname"
+    }
+
+    return 1
+}
+
+# List tickets.  Requires client and server names, and test name.
+# Checks that klist exist status is zero.
+# Records pass or fail, and returns 1 or 0.
+proc do_klist { myname servname testname } {
+    global KLIST
+    global tmppwd
+
+    spawn $KLIST -5 -e
+    expect {
+	-re "Ticket cache:\[ 	\]*(.+:)?$tmppwd/tkt.*Default principal:\[ 	\]*$myname.*$servname\r\n" {
+	    verbose "klist started"
+	}
+	timeout {
+	    fail $testname
+	    return 0
+	}
+	eof {
+	    fail $testname
+	    return 0
+	}
+    }
+
+    expect eof
+
+    if ![check_exit_status $testname] {
+	return 0
+    }
+    pass $testname
+    return 1
+}
+
+proc do_klist_kt { keytab testname } {
+    global KLIST
+    global tmppwd
+
+    spawn $KLIST -5 -e -k $keytab
+    expect {
+	-re "Keytab name:\[ 	\]*(.+:)?.*KVNO Principal\r\n---- -*\r\n" {
+	    verbose "klist started"
+	}
+	timeout {
+	    fail $testname
+	    return 0
+	}
+	eof {
+	    fail $testname
+	    return 0
+	}
+    }
+    set more 1
+    while {$more} {
+	expect {
+	    -re { *[0-9][0-9]* *[a-zA-Z/@.-]* \([/a-zA-Z 0-9-]*\) *\r\n} {
+		verbose -log "key: $expect_out(buffer)"
+	    }
+	    eof { set more 0 }
+	}
+    }
+
+    if ![check_exit_status $testname] {
+	return 0
+    }
+    pass $testname
+    return 1
+}
+
+proc do_klist_err { testname } {
+    global KLIST
+    global spawn_id
+
+    spawn $KLIST -5
+    # Might say "credentials cache" or "credentials cache file".
+    expect {
+	-re "klist: No credentials cache.*found.*\r\n" {
+	    verbose "klist started"
+	}
+	timeout {
+	    fail $testname
+	    return 0
+	}
+	eof {
+	    fail $testname
+	    return 0
+	}
+    }
+    # We can't use check_exit_status, because we expect an exit status
+    # of 1.
+    catch "expect eof"
+    set status_list [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $status_list ($testname)"
+    if { [lindex $status_list 2] != 0 } {
+	fail "$testname (bad exit status) $status_list"
+	return 0
+    } else { if { [lindex $status_list 3] != 1 } {
+	fail "$testname (bad exit status) $status_list"
+	return 0
+    } else {
+	pass $testname
+    } }
+    return 1
+}
+
+proc do_kdestroy { testname } {
+    global KDESTROY
+    global spawn_id
+
+    spawn $KDESTROY -5
+    if ![check_exit_status $testname] {
+	fail $testname
+	return 0
+    }
+    pass $testname
+    return 1
+}
+
+proc xst { keytab name } {
+    global KADMIN_LOCAL
+    global REALMNAME
+
+    envstack_push
+    setup_kerberos_env kdc
+    spawn $KADMIN_LOCAL -r $REALMNAME
+    envstack_pop
+    catch expect_after
+    expect_after {
+	-re "(.*)\r\nkadmin.local:  " {
+	    fail "kadmin.local xst $keytab (unmatched output: $expect_out(1,string)"
+	    catch "expect_after"
+	    return 0
+	}
+	timeout {
+	    fail "kadmin.local xst $keytab (timeout)"
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    fail "kadmin.local xst $keytab (eof)"
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect "kadmin.local:  "
+    send "xst -k $keytab $name\r"
+    expect -re "xst -k \[^\r\n\]*\r\n.*Entry for principal .* added to keytab WRFILE:.*\r\nkadmin.local:  "
+    send "quit\r"
+    expect eof
+    catch expect_after
+    if ![check_exit_status "kadmin.local $keytab"] {
+	perror "kadmin.local xst $keytab exited abnormally"
+	return 0
+    }
+    return 1
+}
+
+# v4_compatible_enctype
+# Returns 1 if v4 testing is enabled this passes encryption types are compatable with kerberos 4 work
+proc v4_compatible_enctype {} {
+    global supported_enctypes
+    global KRBIV
+
+    if ![info exists KRBIV] {
+	return 0;
+    }
+
+    if { $KRBIV && [string first des-cbc-crc:v4 "$supported_enctypes"] >= 0} {
+	return 1
+    } else {
+	return 0
+    }
+}
+
+# Set up a root shell using rlogin $hostname -l root.  This is used
+# when testing the daemons that must be run as root, such as telnetd
+# or rlogind.  This sets the global variables rlogin_spawn_id and
+# rlogin_pid.  Returns 1 on success, 0 on failure.
+#
+# This procedure will only succeed if the person running the test has
+# a valid ticket for a name listed in the /.klogin file.  Naturally,
+# Kerberos must already be installed on this machine.  It's a pain,
+# but I can't think of a better approach.
+
+if ![info exists can_get_root] { set can_get_root yes }
+
+proc setup_root_shell { testname } {
+    global BINSH
+    global ROOT_PROMPT
+    global KEY
+    global RLOGIN
+    global RLOGIN_FLAGS
+    global hostname
+    global rlogin_spawn_id
+    global rlogin_pid
+    global tmppwd
+    global env
+    global krb5_init_vars
+    global can_get_root
+
+    global timeout
+
+    if [string match $can_get_root no] {
+	note "$testname test requires ability to log in as root"
+	unsupported $testname
+	return 0
+    }
+
+    # Make sure we are using the original values of the environment
+    # variables.  This means that the caller must call
+    # setup_kerberos_env after calling this procedure.
+
+    # XXX fixme to deal with envstack
+    restore_kerberos_env
+
+    set me [exec whoami]
+    if [string match root $me] {
+	return [setup_root_shell_noremote $testname]
+    }
+
+    if ![get_hostname] {
+	set can_get_root no
+	return 0
+    }
+
+    # If you have not installed Kerberos on your system, and you want
+    # to run these tests, you can do it if you are willing to put your
+    # root password in this file (this is not a very good idea, but
+    # it's safe enough if you disconnect from the network and remember
+    # to remove the password later).  Change the rlogin in the next
+    # line to be /usr/ucb/rlogin (or whatever is appropriate for your
+    # system).  Then change the lines after "word:" a few lines
+    # farther down to be
+    #    send "rootpassword\r"
+    #    exp_continue
+
+    eval spawn $RLOGIN $hostname -l root $RLOGIN_FLAGS
+    set rlogin_spawn_id $spawn_id
+    set rlogin_pid [exp_pid]
+    set old_timeout $timeout
+    set timeout 300
+    set got_refused 0
+
+    expect {
+	-re {connect to address [0-9a-fA-F.:]*: Connection refused} {
+	    note $expect_out(buffer)
+	    set got_refused 1
+	    exp_continue
+	}
+	-re "word:|erberos rlogin failed|ection refused|ection reset by peer|not authorized|Ticket expired|authenticity of" {
+	    note "$testname test requires ability to rlogin as root"
+	    unsupported "$testname"
+	    set timeout $old_timeout
+	    stop_root_shell
+	    set can_get_root no
+	    return 0
+	}
+	"Cannot assign requested address" {
+	    note "$testname: rlogin as root 'cannot assign requested address'"
+	    unsupported "$testname"
+	    set timeout $old_timeout
+	    stop_root_shell
+	    set can_get_root no
+	    return 0
+	}
+	-re "usage: rlogin|illegal option -- x|invalid option -- x" {
+	    note "$testname: rlogin doesn't like command-line flags"
+	    unsupported "$testname"
+	    set timeout $old_timeout
+	    stop_root_shell
+	    set can_get_root no
+	    return 0
+	}
+	-re "$ROOT_PROMPT" { }
+	timeout {
+	    perror "timeout from rlogin $hostname -l root"
+	    perror "If you have an unusual root prompt,"
+	    perror "try running with ROOT_PROMPT=\"regexp\""
+	    set timeout $old_timeout
+	    stop_root_shell
+	    set can_get_root no
+	    return 0
+	}
+	eof {
+	    if {$got_refused} {
+		# reported some errors, continued, and failed
+		note "$testname test requires ability to log in as root"
+		unsupported $testname
+	    } else {
+		# unknown problem?
+#		perror "eof from rlogin $hostname -l root"
+		note "eof (and unrecognized messages?) from rlogin $hostname -l root"
+		note "$testname test requires ability to log in as root"
+		unsupported $testname
+	    }
+	    stop_root_shell
+	    set timeout $old_timeout
+	    catch "expect_after"
+	    set can_get_root no
+	    return 0
+	}
+    }
+
+    expect_after {
+	timeout {
+	    perror "timeout from rlogin $hostname -l root"
+	    stop_root_shell
+	    set timeout $old_timeout
+	    catch "expect_after"
+	    set can_get_root no
+	    return 0
+	}
+	eof {
+	    perror "eof from rlogin $hostname -l root"
+	    stop_root_shell
+	    set timeout $old_timeout
+	    catch "expect_after"
+	    set can_get_root no
+	    return 0
+	}
+    }
+
+    # Make sure the root shell is using /bin/sh.
+    send "$BINSH\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+
+    # Set up a shell variable tmppwd.  The callers use this to keep
+    # command line lengths down.  The command line length is important
+    # because we are feeding input to a shell via a pty.  On some
+    # systems a pty will only accept 255 characters.
+    send "tmppwd=$tmppwd\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+
+    # Set up our krb5.conf
+    send "KRB5_CONFIG=$tmppwd/krb5.server.conf\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+    send "export KRB5_CONFIG\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+
+    # Move over to the right directory.
+    set dir [pwd]
+    send "cd $dir\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+	"$dir:" {
+	    perror "root shell can not cd to $dir"
+	    set timeout $old_timeout
+	    stop_root_shell
+	    set can_get_root no
+	    return 0
+	}
+    }
+
+    expect_after
+    set timeout $old_timeout
+
+    return 1
+}
+
+proc setup_root_shell_noremote { testname } {
+    global BINSH
+    global ROOT_PROMPT
+    global KEY
+    global hostname
+    global rlogin_spawn_id
+    global rlogin_pid
+    global tmppwd
+    global env
+
+    eval spawn $BINSH
+    set rlogin_spawn_id $spawn_id
+    set rlogin_pid [exp_pid]
+
+    expect_after {
+	timeout {
+	    perror "timeout from root shell"
+	    stop_root_shell
+	    catch "expect_after"
+	    return 0
+	}
+	eof {
+	    perror "eof from root shell"
+	    stop_root_shell
+	    catch "expect_after"
+	    return 0
+	}
+    }
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+
+    # Set up a shell variable tmppwd.  The callers use this to keep
+    # command line lengths down.  The command line length is important
+    # because we are feeding input to a shell via a pty.  On some
+    # systems a pty will only accept 255 characters.
+    send "tmppwd=$tmppwd\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+
+    # Set up our krb5.conf
+    send "KRB5_CONFIG=$tmppwd/krb5.server.conf\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+    send "export KRB5_CONFIG\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+    }
+
+    # Move over to the right directory.
+    set dir [pwd]
+    send "cd $dir\r"
+    expect {
+	-re "$ROOT_PROMPT" { }
+	"$dir:" {
+	    perror "root shell can not cd to $dir"
+	    stop_root_shell
+	    return 0
+	}
+    }
+
+    expect_after
+
+    return 1
+}
+
+# Kill off a root shell started by setup_root_shell.
+
+proc stop_root_shell { } {
+    global rlogin_spawn_id
+    global rlogin_pid
+
+    catch "close -i $rlogin_spawn_id"
+    catch "exec kill $rlogin_pid"
+    sleep 1
+    catch "exec kill -9 $rlogin_pid"
+    catch "wait -i $rlogin_spawn_id"
+}
+
+# Check the date.  The string will be the output of date on this
+# system, and we must make sure that it is in the same timezone as the
+# output of date run a second time.  The first date will be run on an
+# rlogin or some such connection to the local system.  This is to test
+# to make sure that the TZ environment variable is handled correctly.
+# Returns 1 on sucess, 0 on failure.
+
+proc check_date { date } {
+    catch "exec date" ndate
+    set atz ""
+    set ntz ""
+    scan $date "%s %s %d %d:%d:%d %s %d" adow amon adom ahr amn asc atz ayr
+    scan $ndate "%s %s %d %d:%d:%d %s %d" ndow nmon ndom nhr nmn nsc ntz nyr
+    if { $atz != $ntz } {
+	verbose -log "date check failed: $atz != $ntz"
+	return 0
+    }
+    return 1
+}
+
+proc touch { file } {
+    set f [open $file "a"]
+    puts $f ""
+    close $f
+}
+
+# Implement this in tcl someday?
+proc tail1 { file } {
+    exec tail -1 $file
+}
+
+# setup_wrapper
+# Sets up a wraper script to set the runtime shared library environment 
+# variables and then executes a specific command. This is used to allow
+# a "rsh klist" or telnetd to execute login.krb5. 
+proc setup_wrapper { file command } {
+    global BINSH
+    global env
+
+    # We will start with a BINSH script
+    file delete $file
+
+    set f [open $file "w" 0777]
+    puts $f "#!$BINSH"
+    puts $f "KRB5_CONFIG=$env(KRB5_CONFIG)"
+    puts $f "export KRB5_CONFIG"
+    puts $f "exec $command"
+    close $f
+    
+    return 1
+}
+
+proc krb_exit { } {
+    stop_kerberos_daemons
+}
+
+# helpful sometimes for debugging the test suite
+proc export_debug_envvars { } {
+    global env
+    foreach i {KDB5_UTIL KRB5KDC KADMIND KADMIN KADMIN_LOCAL KINIT KTUTIL KLIST RLOGIN RLOGIN_FLAGS RLOGIND FTP FTPD KPASSWD REALMNAME GSSCLIENT KPROPLOG} {
+	global $i
+	if [info exists $i] { set env($i) [set $i] }
+    }
+}
+proc spawn_xterm { } {
+    export_debug_envvars
+    exec "xterm"
+}
+proc spawn_shell { } {
+    export_debug_envvars
+    spawn "sh"
+    exp_interact
+}

Added: trunk/tests/deps
===================================================================
--- trunk/tests/deps	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/deps	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,5 @@
+# 
+# Generated makefile dependencies follow.
+#
+$(OUTPRE)t_inetd.$(OBJEXT): $(BUILDTOP)/autoconf.h \
+  t_inetd.c

Added: trunk/tests/krb-root/rlogin.exp
===================================================================
--- trunk/tests/krb-root/rlogin.exp	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/krb-root/rlogin.exp	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,322 @@
+# Kerberos rlogin test.
+# This is a DejaGnu test script.
+# This script tests Kerberos rlogin.
+# Written by Ian Lance Taylor, Cygnus Support, <ian at cygnus.com>.
+
+# Find the programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be .../kerberos/src.
+
+if ![info exists KRLOGIN] {
+    set KRLOGIN [findfile $objdir/../bsd/rlogin]
+}
+
+if ![info exists KRLOGIND] {
+    set KRLOGIND [findfile $objdir/../bsd/klogind]
+}
+
+if ![info exists LOGINKRB5] {
+    set LOGINKRB5 [findfile $objdir/../bsd/login.krb5]
+}
+
+# Start up a root shell.
+if ![setup_root_shell rlogin] {
+    return
+}
+
+# Make sure .k5login is reasonable.
+if ![check_k5login rlogin] {
+    stop_root_shell
+    return
+}
+
+# Set up the kerberos database.
+if {![get_hostname] \
+    || ![setup_kerberos_files] \
+    || ![setup_kerberos_env] \
+    || ![setup_kerberos_db 0]} {
+    stop_root_shell
+    return
+}
+
+# A procedure to start up the rlogin daemon.
+
+proc start_rlogin_daemon { option } {
+    global REALMNAME
+    global KRLOGIND
+    global LOGINKRB5
+    global ROOT_PROMPT
+    global tmppwd
+    global hostname
+    global rlogin_spawn_id
+    global krlogind_pid
+    global portbase
+
+    # The -p argument tells it to accept a single connection, so we
+    # don't need to use inetd.  The 3543 is the port to listen at.
+    # Note that tmppwd here is a shell variable, which is set in
+    # setup_root_shell, not a TCL variable.  The sh -c is to workaround
+    # the broken controlling tty handling in hpux, and shouldn't hurt
+    # anything else.
+    send -i $rlogin_spawn_id "sh -c \"$KRLOGIND -k -c -D [expr 8 + $portbase] -S \$tmppwd/srvtab -M $REALMNAME -L $LOGINKRB5 $option\" &\r"
+    expect {
+	-i $rlogin_spawn_id 
+	-re "$ROOT_PROMPT" { }
+	timeout {
+	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
+	    return
+	}
+	eof {
+	    send_error "ERROR: eof from rlogin $hostname -l root\n"
+	    return
+	}
+    }
+    send -i $rlogin_spawn_id "echo \$!\r"
+    expect {
+	-i $rlogin_spawn_id
+	-re "\[0-9\]+" {
+	    set krlogind_pid $expect_out(0,string)
+	    verbose "krlogind process ID is $krlogind_pid"
+	}
+	timeout {
+	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
+	    return
+	}
+	eof {
+	    send_error "ERROR: eof from rlogin $hostname -l root\n"
+	    return
+	}
+    }
+    expect {
+	-i $rlogin_spawn_id
+	-re "$ROOT_PROMPT" { }
+	timeout {
+	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
+	    return
+	}
+	eof {
+	    send_error "ERROR: eof from rlogin $hostname -l root\n"
+	    return
+	}
+    }
+
+    # Give the rlogin daemon a few seconds to get set up.
+    sleep 2
+}
+
+# A procedure to stop the rlogin daemon.
+
+proc stop_rlogin_daemon { } {
+    global krlogind_pid
+
+    if [info exists krlogind_pid] {
+	catch "exec kill $krlogind_pid"
+	unset krlogind_pid
+    }
+}
+
+# Wrap the tests in a procedure, so that we can kill the daemons if
+# we get some sort of error.
+
+proc rlogin_test { } {
+    global REALMNAME
+    global KRLOGIN
+    global BINSH
+    global SHELL_PROMPT
+    global KEY
+    global hostname
+    global hostname
+    global env
+    global portbase
+
+    # Start up the kerberos and kadmind daemons and get a srvtab and a
+    # ticket file.
+    if {![start_kerberos_daemons 0] \
+        || ![add_kerberos_key host/$hostname 0] \
+        || ![setup_srvtab 0] \
+	|| ![add_kerberos_key $env(USER) 0] \
+	|| ![kinit $env(USER) $env(USER)$KEY 0]} {
+	return
+    }
+
+    # Start up the rlogin daemon.
+    start_rlogin_daemon -k
+
+    # Make an rlogin connection.
+    spawn $KRLOGIN $hostname -k $REALMNAME -D [expr 8 + $portbase]
+
+    expect_after {
+	timeout {
+	    fail "$testname (timeout)"
+	    catch "expect_after"
+	    return
+	}
+	"onnection closed." {
+	    fail "$testname (connection closed)"
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "rlogin"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    # Switch to /bin/sh to try to avoid confusion from the shell
+    # prompt.
+    set testname "shell"
+    send "$BINSH\r"
+    expect "$BINSH"
+    expect -re "$SHELL_PROMPT"
+
+    set testname "date"
+    send "date\r"
+    expect "date"
+    expect {
+	-re "\[A-Za-z0-9 :\]+\[\r\n\]+" {
+	    if [check_date $expect_out(0,string)] {
+		pass "date"
+	    } else {
+		fail "date"
+	    }
+	}
+    }
+    expect -re "$SHELL_PROMPT"
+
+    set testname "exit"
+    send "exit\r"
+    expect -re "$SHELL_PROMPT"
+    send "exit\r"
+    expect {
+	"onnection closed." {
+	    pass $testname
+	}
+    }
+    # This last expect seems useless, but without it the rlogin process
+    # sometimes hangs on HP-UX, in a tcsetattr call with TCSADRAIN.
+    expect {
+        "\r" { }
+    }
+
+    expect_after
+
+    if [check_exit_status "exit status"] {
+	pass "exit status"
+    }
+
+    # The rlogin daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_rlogin_daemon
+
+    # Try an encrypted connection.
+    start_rlogin_daemon -e
+    spawn $KRLOGIN $hostname -x -k $REALMNAME -D [expr 8 + $portbase]
+
+    expect_after {
+	timeout {
+	    fail "$testname (timeout)"
+	    catch "expect_after"
+	    return
+	}
+	"onnection closed" {
+	    fail "$testname (connection closed)"
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "encrypted rlogin"
+    expect -re "encrypting .* transmissions"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    # Switch to /bin/sh to try to avoid confusion from the shell
+    # prompt.
+    set testname "shell"
+    send "$BINSH\r"
+    expect "$BINSH"
+    expect -re "$SHELL_PROMPT"
+
+    # Make sure the encryption is not destroying the text.
+    set testname "echo"
+    send "echo hello\r"
+    expect "echo hello"
+    expect "hello"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    # Send some characters which might cause an interrupt, and then
+    # make sure we can still talk to the shell.
+    set testname "interrupt characters"
+    send "\003\177\034\r"
+    expect -re "$SHELL_PROMPT"
+    send "echo hello\r"
+    expect "echo hello"
+    expect "hello"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    set testname "~."
+    send "~."
+    expect {
+	"Closed connection.\r" {
+	    pass $testname
+	}
+	"onnection closed" {
+	    pass $testname
+	}
+    }
+
+    expect_after
+
+    if [check_exit_status "exit status"] {
+	pass "exit status"
+    }
+
+    # The rlogin daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_rlogin_daemon
+}
+
+# Run the test.  Logging in sometimes takes a while, so increase the
+# timeout.
+set oldtimeout $timeout
+set timeout 60
+set status [catch rlogin_test msg]
+set timeout $oldtimeout
+
+# Shut down the kerberos daemons, the rlogin daemon, and the root
+# process.
+stop_kerberos_daemons
+
+stop_rlogin_daemon
+
+stop_root_shell
+
+if { $status != 0 } {
+    send_error "ERROR: error in rlogin.exp\n"
+    send_error "$msg\n"
+    exit 1
+}

Added: trunk/tests/krb-root/telnet.exp
===================================================================
--- trunk/tests/krb-root/telnet.exp	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/krb-root/telnet.exp	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,451 @@
+# Kerberos telnet test.
+# This is a DejaGnu test script.
+# This script tests Kerberos telnet.
+# Written by Ian Lance Taylor, Cygnus Support, <ian at cygnus.com>.
+
+# Find the programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be .../kerberos/src.
+
+if ![info exists TELNET] {
+    set TELNET [findfile $objdir/../telnet/telnet/telnet]
+}
+
+if ![info exists TELNETD] {
+    set TELNETD [findfile $objdir/../telnet/telnetd/telnetd]
+}
+
+if ![info exists LOGINKRB5] {
+    set LOGINKRB5 [findfile $objdir/../bsd/login.krb5]
+}
+
+if ![regexp des- $supported_enctypes] {
+    # Telnet needs a DES enctype.
+    verbose "Skipping telnet tests for lack of DES support."
+    return
+}
+
+# A procedure to start up the telnet daemon.
+
+proc start_telnet_daemon { args } {
+    global REALMNAME
+    global TELNETD
+    global LOGINKRB5
+    global ROOT_PROMPT
+    global tmppwd
+    global hostname
+    global rlogin_spawn_id
+    global telnetd_pid
+    global portbase
+
+    # Setup the shared library wrapper for login.krb5
+    if ![file exists $tmppwd/login.wrap] {
+	    setup_wrapper $tmppwd/login.wrap "$LOGINKRB5 $*"
+    }
+
+    # The -debug argument tells it to accept a single connection, so
+    # we don't need to use inetd.  The portbase+8 is the port to listen at.
+    # Note that tmppwd here is a shell variable, which is set in
+    # setup_root_shell, not a TCL variable.
+    send -i $rlogin_spawn_id "sh -c \"$TELNETD $args -debug -t \$tmppwd/srvtab -R $REALMNAME -L $tmppwd/login.wrap [expr 8 + $portbase]\" &\r"
+    expect {
+	-i $rlogin_spawn_id 
+	-re "$ROOT_PROMPT" { }
+	timeout {
+	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
+	    return
+	}
+	eof {
+	    send_error "ERROR: eof from rlogin $hostname -l root\n"
+	    return
+	}
+    }
+    send -i $rlogin_spawn_id "echo \$!\r"
+    expect {
+	-i $rlogin_spawn_id
+	-re "\[0-9\]+" {
+	    set telnetd_pid $expect_out(0,string)
+	    verbose "telnetd process ID is $telnetd_pid"
+	}
+	timeout {
+	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
+	    return
+	}
+	eof {
+	    send_error "ERROR: eof from rlogin $hostname -l root\n"
+	    return
+	}
+    }
+    expect {
+	-i $rlogin_spawn_id
+	-re "$ROOT_PROMPT" { }
+	timeout {
+	    send_error "ERROR: timeout from rlogin $hostname -l root\n"
+	    return
+	}
+	eof {
+	    send_error "ERROR: eof from rlogin $hostname -l root\n"
+	    return
+	}
+    }
+
+    # Give the telnet daemon a few seconds to get set up.
+    sleep 2
+}
+
+# A procedure to stop the telnet daemon.
+
+proc stop_telnet_daemon { } {
+    global telnetd_pid
+
+    if [info exists telnetd_pid] {
+	catch "exec kill $telnetd_pid"
+	unset telnetd_pid
+    }
+}
+
+# Wrap the tests in a procedure, so that we can kill the daemons if
+# we get some sort of error.
+
+proc telnet_test { } {
+    global REALMNAME
+    global TELNET
+    global BINSH
+    global SHELL_PROMPT
+    global KEY
+    global hostname
+    global localhostname
+    global env
+    global portbase
+
+    # Start up the kerberos and kadmind daemons and get a srvtab and a
+    # ticket file.
+    if {![start_kerberos_daemons 0] \
+        || ![add_kerberos_key host/$hostname 0] \
+        || ![setup_srvtab 0] \
+	|| ![add_kerberos_key $env(USER) 0] \
+	|| ![kinit $env(USER) $env(USER)$KEY 0]} {
+	return
+    }
+
+    # Start up the telnet daemon.
+    start_telnet_daemon
+
+    # Start up our telnet connection.  We first try it without
+    # authentication, so the daemon should prompt for a login.
+    spawn $TELNET -- $hostname -[expr 8 + $portbase]
+    set telnet_pid [exp_pid]
+
+    expect_after {
+	timeout {
+	    fail "$testname (timeout)"
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "simple telnet"
+    expect {
+	"ogin: " {
+	    pass $testname
+	}
+    }
+
+    # Move back to telnet command mode and make sure it seems
+    # reasonable.
+    set testname "telnet command mode"
+    send "\035"
+    expect {
+	"telnet> " {
+	    pass $testname
+	}
+    }
+
+    set testname "telnet status"
+    send "status\r"
+    # use -nocase because telnet may output the fqdn in upper-case;
+    # however, -nocase requires the whole pattern to be in lower case
+    expect {
+	-nocase -re "connected to $localhostname.*operating in single character mode.*catching signals locally.*remote character echo.*flow control.*escape character is '.\]'" {
+	    pass $testname
+	}
+    }
+
+    set testname "back to command mode"
+
+    # For some reason, the telnet client doesn't necessarily reset the
+    # terminal mode back to raw after exiting command mode.
+    # Kick it somewhat by sending a CR.
+    send "\r"
+    expect "ogin: "
+
+    send "\035"
+    expect {
+	"telnet> " {
+	    pass $testname
+	}
+    }
+
+    set testname "quit"
+    send "quit\r"
+    expect {
+	"Connection closed.\r" {
+	    pass $testname
+	}
+    }
+
+    expect_after
+
+# on hpux 10.x, the child telnet will hang in an ioctl().  This will
+# wait a while for an EOF, and kill the process if it doesn't exit by
+# itself.  The hang doesn't happen when telnet is run at the shell.
+
+    expect {
+	eof { }
+	timeout {
+	    stop_telnet_daemon
+	}
+    }
+
+    if ![check_exit_status "exit status"] {
+	return
+    }
+
+    pass "exit status"
+
+    # The telnet daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_telnet_daemon
+
+    # Try an authenticated connection.
+    start_telnet_daemon
+    spawn $TELNET -a -k $REALMNAME -- $hostname -[expr 8 + $portbase]
+
+    expect_after {
+	timeout {
+	    fail "$testname (timeout)"
+	    catch "expect_after"
+	    return
+	}
+	"Connection closed by foreign host.\r" {
+	    fail "$testname (connection closed)"
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "authenticated telnet"
+    expect "Kerberos V5 accepts you"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    # Switch to /bin/sh to try to avoid confusion from the shell
+    # prompt.
+    set testname "shell"
+    send "$BINSH\r"
+    expect -re "$SHELL_PROMPT"
+
+    set testname "date"
+    send "date\r"
+    expect "date"
+    expect {
+	-re "\[A-Za-z0-9 :\]+\[\r\n\]+" {
+	    if [check_date $expect_out(0,string)] {
+		pass "date"
+	    } else {
+		fail "date"
+	    }
+	}
+    }
+    expect -re "$SHELL_PROMPT"
+
+    set testname "exit"
+    send "exit\r"
+    expect -re "$SHELL_PROMPT"
+    send "exit\r"
+    expect {
+	"Connection closed by foreign host.\r" {
+	    pass $testname
+	}
+    }
+
+    expect_after
+    catch "expect eof"
+
+    # We can't use check_exit_status, because we expect an exit status
+    # of 1.
+    set status_list [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $status_list (klist)"
+    if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 1 } {
+	send_log "exit status: $status_list\n"
+	verbose "exit status: $status_list"
+	fail "exit status"
+    } else {
+	pass "exit status"
+    }
+
+    # The telnet daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_telnet_daemon
+
+    # Try an authenticated encrypted connection.
+    start_telnet_daemon
+    spawn $TELNET -a -x -k $REALMNAME -- $hostname -[expr 8 + $portbase]
+
+    expect_after {
+	timeout {
+	    fail $testname
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail $testname
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "encrypted telnet"
+    expect "Kerberos V5 accepts you"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    # Make sure the encryption is not destroying the text.
+    set testname "echo"
+    send "echo hello\r"
+    expect "echo hello"
+    expect "hello"
+    expect {
+	-re "$SHELL_PROMPT" {
+	    pass $testname
+	}
+    }
+
+    # Move back to telnet command mode and check the encryption status.
+    set testname "encryption status"
+    send "\035"
+    expect "telnet> "
+    send "status\r"
+    expect {
+	-re "Currently encrypting output with DES_CFB64.*Currently decrypting input with DES_CFB64" {
+	    pass $testname
+	}
+    }
+
+    set testname "exit status"
+    send "exit\r"
+    expect "Connection closed by foreign host.\r"
+
+    expect_after
+    catch "expect eof"
+
+    # We can't use check_exit_status, because we expect an exit status
+    # of 1.
+    set status_list [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $status_list (klist)"
+    if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 1 } {
+	send_log "exit status: $status_list\n"
+	verbose "exit status: $status_list"
+	fail "exit status"
+    } else {
+	pass "exit status"
+    }
+
+    # The telnet daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_telnet_daemon
+
+    set testname "reject unencrypted telnet"
+    # Check rejection of unencrypted client when encryption is required
+    start_telnet_daemon -e
+
+    # unencrypted, unauthenticated
+    spawn $TELNET -- $hostname -[expr 8 + $portbase]
+    expect_after {
+	timeout {
+	    fail $testname
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail $testname
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    expect {
+	-re "Unencrypted connection refused.*\n" {
+	    pass $testname
+	}
+    }
+    catch "expect_after"
+    catch "expect eof"
+    catch wait
+
+    # The telnet daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_telnet_daemon
+}
+
+run_once telnet {
+    # Remove old wrapper script
+    catch "exec rm -f $tmppwd/login.wrap"
+
+    # Start up a root shell.
+    if ![setup_root_shell telnet] {
+	return
+    }
+
+    # Make sure .k5login is reasonable.
+    if ![check_k5login rlogin] {
+	stop_root_shell
+	return
+    }
+
+    # Set up the kerberos database.
+    if {![get_hostname] \
+	    || ![setup_kerberos_files] \
+	    || ![setup_kerberos_env] \
+	    || ![setup_kerberos_db 0]} {
+	stop_root_shell
+	return
+    }
+
+    # Run the test.  Logging in sometimes takes a while, so increase the
+    # timeout.
+    set oldtimeout $timeout
+    set timeout 60
+    set status [catch telnet_test msg]
+    set timeout $oldtimeout
+
+    # Shut down the kerberos daemons, the telnet daemon, and the rlogin
+    # process.
+    stop_kerberos_daemons
+
+    stop_telnet_daemon
+
+    stop_root_shell
+
+    if { $status != 0 } {
+	send_error "ERROR: error in telnet.exp\n"
+	send_error "$msg\n"
+	exit 1
+    }
+}

Added: trunk/tests/krb-standalone/gssftp.exp
===================================================================
--- trunk/tests/krb-standalone/gssftp.exp	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/krb-standalone/gssftp.exp	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,507 @@
+# Kerberos ftp test.
+# This is a DejaGnu test script.
+# This script tests Kerberos ftp.
+# Originally written by Ian Lance Taylor, Cygnus Support, <ian at cygnus.com>.
+# Modified bye Ezra Peisach for GSSAPI support.
+
+# Find the programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be .../kerberos/build/tests/dejagnu
+
+if ![info exists FTP] {
+    set FTP [findfile $objdir/../gssftp/ftp/ftp]
+}
+
+if ![info exists FTPD] {
+    set FTPD [findfile $objdir/../gssftp/ftpd/ftpd]
+}
+
+# A procedure to start up the ftp daemon.
+
+proc start_ftp_daemon { } {
+    global FTPD
+    global tmppwd
+    global ftpd_spawn_id
+    global ftpd_pid
+    global portbase
+
+    # The -p argument tells it to accept a single connection, so we
+    # don't need to use inetd.  Portbase+8 is the port to listen at.
+    # We rely on KRB5_KTNAME being set to the proper keyfile as there is
+    # no way to cleanly set it with the gssapi API.
+    # The -U argument tells it to use an alternate ftpusers file (using
+    # /dev/null will allow root to login regardless of /etc/ftpusers).
+    # The -a argument requires authorization, to mitigate any
+    # vulnerability introduced by circumventing ftpusers.
+    spawn $FTPD -p [expr 8 + $portbase] -a -U /dev/null -r $tmppwd/krb5.conf
+    set ftpd_spawn_id $spawn_id
+    set ftpd_pid [exp_pid]
+
+    # Give the ftp daemon a few seconds to get set up.
+    sleep 2
+}
+
+# A procedure to stop the ftp daemon.
+
+proc stop_ftp_daemon { } {
+    global ftpd_spawn_id
+    global ftpd_pid
+
+    if [info exists ftpd_pid] {
+	catch "close -i $ftpd_spawn_id"
+	catch "exec kill $ftpd_pid"
+	catch "wait -i $ftpd_spawn_id"
+	unset ftpd_pid
+    }
+}
+
+# Test that a file was copied correctly.
+proc check_file { filename {bigfile 0}} {
+    if ![file exists $filename] {
+	verbose "$filename does not exist"
+	send_log "$filename does not exist\n"
+	return 0
+    }
+
+    set file [open $filename r]
+    if { [gets $file line] == -1 } {
+	verbose "$filename is empty"
+	send_log "$filename is empty\n"
+	close $file
+	return 0
+    }
+
+    if ![string match "This file is used for ftp testing." $line] {
+	verbose "$filename contains $line"
+	send_log "$filename contains $line\n"
+	close $file
+	return 0
+    }
+
+    if {$bigfile} {
+	# + 1 for the newline
+	seek $file 1048577 current
+	if { [gets $file line] == -1 } {
+	    verbose "$filename is truncated"
+	    send_log "$filename is truncated\n"
+	    close $file
+	    return 0
+	}
+
+	if ![string match "This file is used for ftp testing." $line] {
+	    verbose "$filename contains $line"
+	    send_log "$filename contains $line\n"
+	    close $file
+	    return 0
+	}
+    }
+
+    if { [gets $file line] != -1} {
+	verbose "$filename is too long ($line)"
+	send_log "$filename is too long ($line)\n"
+	close $file
+	return 0
+    }
+
+    close $file
+
+    return 1
+}
+
+#
+# Restore environment variables possibly set.
+#
+proc ftp_restore_env { } {
+    global env
+    global ftp_save_ktname
+
+    catch "unset env(KRB5_KTNAME)"
+    if [info exists ftp_save_ktname] {
+	set env(KRB5_KTNAME) $ftp_save_ktname
+	unset ftp_save_ktname
+    }
+}
+
+# Wrap the tests in a procedure, so that we can kill the daemons if
+# we get some sort of error.
+
+proc ftp_test { } {
+    global FTP
+    global KEY
+    global REALMNAME
+    global hostname
+    global localhostname
+    global env
+    global ftpd_spawn_id
+    global ftpd_pid
+    global spawn_id
+    global tmppwd
+    global ftp_save_ktname
+    global portbase
+
+    # Start up the kerberos and kadmind daemons and get a srvtab and a
+    # ticket file.
+    if {![start_kerberos_daemons 0] \
+        || ![add_random_key ftp/$hostname 0] \
+	|| ![modify_principal ftp/$hostname -kvno 254] \
+        || ![setup_srvtab 0 ftp] \
+	|| ![xst $tmppwd/srvtab ftp/$hostname]
+	|| ![xst $tmppwd/srvtab ftp/$hostname]
+	|| ![xst $tmppwd/srvtab ftp/$hostname]
+	|| ![do_klist_kt $tmppwd/srvtab "gssftp keytab list"]
+	|| ![add_kerberos_key $env(USER) 0] \
+	|| ![kinit $env(USER) $env(USER)$KEY 0]} {
+	return
+    }
+    # Force the host key to exist, so we get consistent errors below.
+    catch "add_random_key host/$hostname 0"
+
+    #
+    # Save settings of KRB5_KTNAME
+    #
+    if [info exists env(KRB5_KTNAME)] {
+	set ftp_save_ktname $env(KRB5_KTNAME)
+    }
+
+    #
+    # set KRB5_KTNAME *incorrectly*
+    #
+    set env(KRB5_KTNAME) FILE:$tmppwd/srvtabxx
+    verbose "KRB5_KTNAME=$env(KRB5_KTNAME)"
+
+    # Force some auth errors.
+    set testname "ftp auth errors"
+
+    # Start the ftp daemon.
+    start_ftp_daemon
+
+    # Try connecting.
+    spawn $FTP -d -v $hostname [expr 8 + $portbase]
+    expect_after {
+	-re "--->\[^\r\n\]*\r\n" { exp_continue }
+	-re "encoding \[0-9\]* bytes MIC \[a-zA-Z0-9/+=\]*\r\n" { exp_continue }
+	-re "sealed \[A-Z()\]*" { exp_continue }
+	-re "secure_command\[A-Z()\]*" { exp_continue }
+	timeout {
+	    fail "$testname (timeout)"
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    catch "expect_after"
+	    return
+	}
+    }
+    expect -nocase "connected to $hostname"
+    expect -nocase -re "$localhostname.*ftp server .version \[0-9.\]*. ready."
+    expect -re "Using authentication type GSSAPI; ADAT must follow"
+    expect "GSSAPI accepted as authentication type"
+    expect -re "Trying to authenticate to <ftp at .*>"
+    # The ftp client doesn't print the gssapi error except on the last attempt.
+#    expect "GSSAPI error major: Unspecified GSS failure."
+#    expect -re "GSSAPI error minor: Key table file '.*' not found"
+    expect -re "Trying to authenticate to <host at .*>"
+    expect "GSSAPI error major: Unspecified GSS failure."
+    expect -re "GSSAPI error minor: Key table file '.*' not found"
+    expect -re "Name (.*): "
+    close -i $spawn_id
+    wait -i $spawn_id
+    wait -i $ftpd_spawn_id
+    catch "close -i $ftpd_spawn_id"
+
+    #
+    # set KRB5_KTNAME correctly now
+    #
+    set env(KRB5_KTNAME) FILE:$tmppwd/srvtab
+    verbose "KRB5_KTNAME=$env(KRB5_KTNAME)"
+
+    # Start the ftp daemon.
+    start_ftp_daemon
+
+    # Make an ftp client connection to it.
+    spawn $FTP -d -v $hostname [expr 8 + $portbase]
+
+    expect_after {
+	"GSSAPI authentication failed" {
+	    fail "$testname (auth failed)"
+	    catch "expect_after"
+	    return
+	}
+	-re "--->\[^\r\n\]*\r\n" { exp_continue }
+	-re "encoding \[0-9\]* bytes MIC \[a-zA-Z0-9/+=\]*\r\n" { exp_continue }
+	-re "sealed \[A-Z()\]*" { exp_continue }
+	-re "secure_command\[A-Z()\]*" { exp_continue }
+	timeout {
+	    fail "$testname (timeout)"
+	    catch "expect_after"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    catch "expect_after"
+	    return
+	}
+    }
+
+    set testname "ftp connection"
+    expect -nocase "connected to $hostname"
+    expect -nocase -re "$localhostname.*ftp server .version \[0-9.\]*. ready."
+    expect -re "Using authentication type GSSAPI; ADAT must follow"
+    expect "GSSAPI accepted as authentication type"
+    expect {
+	"GSSAPI authentication succeeded" { pass "ftp authentication" }
+	eof	{ fail "ftp authentication" ; catch "expect_after" ; return }
+    }
+    expect -nocase "name ($hostname:$env(USER)): "
+    send "$env(USER)\r"
+    expect "GSSAPI user $env(USER)@$REALMNAME is authorized as $env(USER)"
+    expect "Remote system type is UNIX."
+    expect "Using binary mode to transfer files."
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "binary"
+    send "binary\r"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "status"
+    send "status\r"
+    expect -nocase "connected to $hostname."
+    expect "Authentication type: GSSAPI"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "ls"
+    send "ls $tmppwd/ftp-test\r"
+    expect -re "Opening ASCII mode data connection for .*ls."
+    expect -re ".* $tmppwd/ftp-test"
+    expect "ftp> " {
+	pass $testname
+    } 
+
+    set testname "nlist"
+    send "nlist $tmppwd/ftp-test\r"
+    expect -re "Opening ASCII mode data connection for file list."
+    expect -re "$tmppwd/ftp-test"
+    expect -re ".* Transfer complete."
+    expect "ftp> " {
+	pass $testname
+    } 
+
+    set testname "ls missing"
+    send "ls $tmppwd/ftp-testmiss\r"
+    expect -re "Opening ASCII mode data connection for .*ls."
+    expect {
+	-re "$tmppwd/ftp-testmiss not found" {}
+	-re "$tmppwd/ftp-testmiss: No such file or directory"
+    }
+    expect "ftp> " {
+	pass $testname
+    } 
+
+
+    set testname "get"
+    catch "exec rm -f $tmppwd/copy"
+    send "get $tmppwd/ftp-test $tmppwd/copy\r"
+    expect "Opening BINARY mode data connection for $tmppwd/ftp-test"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes received in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "put"
+    catch "exec rm -f $tmppwd/copy"
+    send "put $tmppwd/ftp-test $tmppwd/copy\r"
+    expect "Opening BINARY mode data connection for $tmppwd/copy"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes sent in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "cd"
+    send "cd $tmppwd\r"
+    expect "CWD command successful."
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "lcd"
+    send "lcd $tmppwd\r"
+    expect "Local directory now $tmppwd"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "local get"
+    catch "exec rm -f $tmppwd/copy"
+    send "get ftp-test copy\r"
+    expect "Opening BINARY mode data connection for ftp-test"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes received in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "big local get"
+    catch "exec rm -f $tmppwd/copy"
+    send "get bigftp-test copy\r"
+    expect "Opening BINARY mode data connection for bigftp-test"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes received in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy 1] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "start encryption"
+    send "private\r"
+    expect "Data channel protection level set to private"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "status"
+    send "status\r"
+    expect "Protection Level: private"
+    expect "ftp> " {
+	pass $testname
+    }
+
+    set testname "encrypted get"
+    catch "exec rm -f $tmppwd/copy"
+    send "get ftp-test copy\r"
+    expect "Opening BINARY mode data connection for ftp-test"
+    expect "Transfer complete"
+    expect -re "\[0-9\]+ bytes received in \[0-9.e-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    set testname "big encrypted get"
+    catch "exec rm -f $tmppwd/copy"
+    send "get bigftp-test copy\r"
+    expect "Opening BINARY mode data connection for bigftp-test"
+    expect {
+	-timeout 300
+	"Transfer complete" {}
+	-re "Length .* of PROT buffer > PBSZ" {
+	    fail "$testname (PBSZ)"
+	    return 0
+	}
+    }
+    expect -re "\[0-9\]+ bytes received in \[0-9.e+-\]+ seconds"
+    expect "ftp> "
+    if [check_file $tmppwd/copy 1] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+    
+    set testname "close"
+    send "close\r"
+    expect "Goodbye."
+    expect "ftp> "
+    set status_list [wait -i $ftpd_spawn_id]
+    verbose "wait -i $ftpd_spawn_id returned $status_list ($testname)"
+    catch "close -i $ftpd_spawn_id"
+    if { [lindex $status_list 2] != 0 || [lindex $status_list 3] != 0 } {
+	send_log "exit status: $status_list\n"
+	verbose "exit status: $status_list"
+	fail $testname
+    } else {
+	pass $testname
+	unset ftpd_pid
+    }
+
+    set testname "quit"
+    send "quit\r"
+    expect_after
+    expect eof
+    if [check_exit_status $testname] {
+	pass $testname
+    }
+}
+
+run_once gssftp {
+    # Make sure .klogin is reasonable.
+    if ![check_k5login ftp] {
+	return
+    }
+
+    # Set up the kerberos database.
+    if {![get_hostname] \
+	    || ![setup_kerberos_files] \
+	    || ![setup_kerberos_env] \
+	    || ![setup_kerberos_db 0]} {
+	return
+    }
+
+    # Create a file to use for ftp testing.
+    set file [open $tmppwd/ftp-test w]
+    puts $file "This file is used for ftp testing."
+    close $file
+
+    # Create a large file to use for ftp testing. File needs to be 
+    # larger that 2^20 or 1MB for PBSZ testing.
+    set file [open $tmppwd/bigftp-test w]
+    puts $file "This file is used for ftp testing.\n"
+    seek $file 1048576 current
+    puts $file "This file is used for ftp testing."
+    close $file
+
+    # The ftp client will look in $HOME/.netrc for the user name to use.
+    # To avoid confusing the testsuite, point $HOME at a directory where
+    # we know there is no .netrc file.
+    if [info exists env(HOME)] {
+	set home $env(HOME)
+    } elseif [info exists home] {
+	unset home
+    }
+    set env(HOME) $tmppwd
+
+    # Run the test.  Logging in sometimes takes a while, so increase the
+    # timeout.
+    set oldtimeout $timeout
+    set timeout 60
+    set status [catch ftp_test msg]
+    set timeout $oldtimeout
+
+    # Shut down the kerberos daemons and the ftp daemon.
+    stop_kerberos_daemons
+
+    stop_ftp_daemon
+
+    ftp_restore_env
+
+    # Reset $HOME, for safety in case we are going to run more tests.
+    if [info exists home] {
+	set env(HOME) $home
+    } else {
+	unset env(HOME)
+    }
+
+    if { $status != 0 } {
+	perror "error in gssftp.exp: $msg"
+    }
+}

Added: trunk/tests/krb-standalone/rcp.exp
===================================================================
--- trunk/tests/krb-standalone/rcp.exp	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/krb-standalone/rcp.exp	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,231 @@
+# Kerberos rcp test.
+# This is a DejaGnu test script.
+# This script tests Kerberos rcp.
+# Written by Ian Lance Taylor, Cygnus Support, <ian at cygnus.com>.
+
+# Find the programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be .../kerberos/src.
+
+if ![info exists RCP] {
+    set RCP [findfile $objdir/../bsd/rcp]
+}
+
+if ![info exists KRSHD] {
+    set KRSHD [findfile $objdir/../bsd/kshd]
+}
+
+# Remove old wrapper script
+    catch "exec rm -f $tmppwd/rcp"
+
+# Make sure .k5login is reasonable.
+if ![check_k5login rcp] {
+    return
+}
+
+# Set up the kerberos database.
+if {![get_hostname] \
+    || ![setup_kerberos_files] \
+    || ![setup_kerberos_env] \
+    || ![setup_kerberos_db 0]} {
+    return
+}
+
+# A procedure to start up the rsh daemon (rcp talks to the rsh
+# daemon).
+
+proc start_rsh_daemon { } {
+    global REALMNAME
+    global KRSHD T_INETD
+    global RCP
+    global tmppwd
+    global krshd_spawn_id
+    global krshd_pid
+    global portbase
+
+    # Setup the shared library wrapper for login.krb5
+    if ![file exists $tmppwd/rcp] {
+	    setup_wrapper $tmppwd/rcp "$RCP $*"
+    }
+
+
+    # The -L ENV_SET is for the I/S Athena brokeness in dot files where
+    #	LD_LIBRARY_PATH will be overridden causing the "exec csh -c rcp ..." 
+    #	to fail as the .cshrc is read in. We do not use the -f option as
+    #	a users shell might be sh...
+    #	Later a proper fix would be to have kshd exec rcp directly
+    #   shell indirection...
+    spawn $T_INETD [expr 8 + $portbase] $KRSHD $KRSHD -k -c -P $tmppwd -S $tmppwd/srvtab -M $REALMNAME -L ENV_SET
+    set krshd_spawn_id $spawn_id
+    set krshd_pid [exp_pid]
+
+    expect {
+	-ex "Ready!"	{ }
+	eof		{ error "couldn't start t_inetd helper" }
+    }
+}
+
+# A procedure to stop the rsh daemon.
+
+proc stop_rsh_daemon { } {
+    global krshd_spawn_id
+    global krshd_pid
+
+    if [info exists krshd_pid] {
+	catch "exec kill $krshd_pid"
+	catch {
+	    expect {
+		-i $krshd_spawn_id
+		-re ..*	{ exp_continue }
+		eof	{}
+	    }
+	}
+	catch "close -i $krshd_spawn_id"
+	catch "wait -i $krshd_spawn_id"
+	unset krshd_pid
+    }
+}
+
+# Create a file to use for rcp testing.
+set file [open $tmppwd/rcp-test w]
+puts $file "This file is used for rcp testing."
+close $file
+
+# Test that a file was copied correctly.
+proc check_file { filename } {
+    if ![file exists $filename] {
+	verbose "$filename does not exist"
+	send_log "$filename does not exist\n"
+	return 0
+    }
+
+    set file [open $filename r]
+    if { [gets $file line] == -1 } {
+	verbose "$filename is empty"
+	send_log "$filename is empty\n"
+	close $file
+	return 0
+    }
+
+    if ![string match "This file is used for rcp testing." $line] {
+	verbose "$filename contains $line"
+	send_log "$filename contains $line\n"
+	close $file
+	return 0
+    }
+
+    if { [gets $file line] != -1} {
+	verbose "$filename is too long ($line)"
+	send_log "$filename is too long ($line)\n"
+	close $file
+	return 0
+    }
+
+    close $file
+
+    return 1
+}
+
+# Test copying one file to another.
+proc rcp_one_test { testname options frompref topref } {
+    global REALMNAME
+    global RCP
+    global tmppwd
+    global portbase
+
+    send_log "rm -f $tmppwd/copy\n"
+    verbose "exec rm -f $tmppwd/copy"
+    catch "exec rm -f $tmppwd/copy"
+
+    set from [format "%s%s" $frompref $tmppwd/rcp-test]
+    set to [format "%s%s" $topref $tmppwd/copy]
+
+    send_log "$RCP $options -D [expr 8 + $portbase] -N -k $REALMNAME $from $to\n"
+    verbose "$RCP $options -D [expr 8 + $portbase] -N -k $REALMNAME $from $to"
+    catch "exec $RCP $options -D [expr 8 + $portbase] -N -k $REALMNAME $from $to" exec_output
+
+    if ![string match "" $exec_output] {
+	send_log "$exec_output\n"
+	verbose "$exec_output"
+	fail $testname
+	return 0
+    }
+
+    if ![check_file $tmppwd/copy] {
+	fail $testname
+	return 0
+    }
+
+    pass $testname
+
+    return 1
+}
+
+# Wrap the tests in a procedure, so that we can kill the daemons if
+# we get some sort of error.
+
+proc rcp_test { } {
+    global RCP
+    global KEY
+    global hostname
+    global hostname
+    global env
+
+    # Start up the kerberos and kadmind daemons and get a srvtab and a
+    # ticket file.
+    if {![start_kerberos_daemons 0] \
+        || ![add_kerberos_key host/$hostname 0] \
+        || ![setup_srvtab 0] \
+	|| ![add_kerberos_key $env(USER) 0] \
+	|| ![kinit $env(USER) $env(USER)$KEY 0]} {
+	return
+    }
+
+    rcp_one_test "local rcp" "" "" ""
+
+    start_rsh_daemon
+    rcp_one_test "rcp from" "" "$hostname:" ""
+    stop_rsh_daemon
+
+    start_rsh_daemon
+    rcp_one_test "rcp to" "" "" "$hostname:"
+    stop_rsh_daemon
+
+    # Doing rcp between two hosts actually just executes rsh rcp on
+    # the source.  We could test this, but we're not set up for it
+    # right now.  Also, it's pretty much covered by the other rcp
+    # tests and by the rsh tests.
+    # start_rsh_daemon
+    # rcp_one_test "rcp between" "" "$hostname:" "$hostname:"
+    # stop_rsh_daemon
+
+    start_rsh_daemon
+    rcp_one_test "encrypted rcp from" "-x -c $env(KRB5CCNAME) -C $env(KRB5_CONFIG)" "$hostname:" ""
+    stop_rsh_daemon
+
+    start_rsh_daemon
+    rcp_one_test "encrypted rcp to" "-x -c $env(KRB5CCNAME) -C $env(KRB5_CONFIG)" "" "$hostname:"
+    stop_rsh_daemon
+
+    # Doing rcp between two hosts actually just executes rsh rcp on
+    # the source.  We could test this, but we're not set up for it
+    # right now.  Also, it's pretty much covered by the other rcp
+    # tests and by the rsh tests.
+    # start_rsh_daemon
+    # rcp_one_test "encrypted rcp between" "-x" "$hostname:" "$hostname:"
+    # stop_rsh_daemon
+}
+
+# Run the test.
+set status [catch rcp_test msg]
+
+# Shut down the kerberos daemons and the rsh daemon.
+stop_kerberos_daemons
+
+stop_rsh_daemon
+
+if { $status != 0 } {
+    send_error "ERROR: error in rcp.exp\n"
+    send_error "$msg\n"
+    exit 1
+}

Added: trunk/tests/krb-standalone/rsh.exp
===================================================================
--- trunk/tests/krb-standalone/rsh.exp	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/krb-standalone/rsh.exp	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,290 @@
+# Kerberos rsh test.
+# This is a DejaGnu test script.
+# This script tests Kerberos rsh.
+# Written by Ian Lance Taylor, Cygnus Support, <ian at cygnus.com>.
+
+# Find the programs we need.  We use the binaries from the build tree
+# if they exist.  If they do not, then they must be in PATH.  We
+# expect $objdir to be .../kerberos/src.
+
+if ![info exists RSH] {
+    set RSH [findfile $objdir/../bsd/rsh]
+}
+
+if ![info exists KRSHD] {
+    set KRSHD [findfile $objdir/../bsd/kshd]
+}
+
+# Make sure .k5login is reasonable.
+if ![check_k5login rsh] {
+    return
+}
+
+# Set up the kerberos database.
+if {![get_hostname] \
+    || ![setup_kerberos_files] \
+    || ![setup_kerberos_db 0]} {
+    return
+}
+
+# A procedure to start up the rsh daemon.
+
+proc start_rsh_daemon { option } {
+    global REALMNAME
+    global KRSHD T_INETD
+    global tmppwd
+    global krshd_spawn_id
+    global krshd_pid
+    global portbase
+
+    spawn $T_INETD [expr 8 + $portbase] $KRSHD $KRSHD -k -c -S $tmppwd/srvtab -M $REALMNAME -A $option
+    set krshd_spawn_id $spawn_id
+    set krshd_pid [exp_pid]
+
+    expect {
+	-ex "Ready!"	{ }
+	eof		{ error "couldn't start t_inetd helper" }
+    }
+}
+
+# A procedure to stop the rsh daemon.
+
+proc stop_rsh_daemon { } {
+    global krshd_spawn_id
+    global krshd_pid
+
+    if [info exists krshd_pid] {
+	catch "exec kill $krshd_pid"
+	catch {
+	    expect {
+		-i $krshd_spawn_id
+		-re ..*	{ exp_continue }
+		eof	{}
+	    }
+	}
+	catch "close -i $krshd_spawn_id"
+	catch "wait -i $krshd_spawn_id"
+	unset krshd_pid
+    }
+}
+
+# Wrap the tests in a procedure, so that we can kill the daemons if
+# we get some sort of error.
+
+proc rsh_test { } {
+    global REALMNAME
+    global KLIST
+    global RSH
+    global KEY
+    global BINSH
+    global hostname
+    global env
+    global spawn_id
+    global tmppwd
+    global portbase
+
+    # Start up the kerberos and kadmind daemons and get a srvtab and a
+    # ticket file.
+    if {![start_kerberos_daemons 0] \
+        || ![add_kerberos_key host/$hostname 0] \
+        || ![setup_srvtab 0] \
+	|| ![add_kerberos_key $env(USER) 0] \
+	|| ![setup_kerberos_env client] \
+	|| ![kinit $env(USER) $env(USER)$KEY 0]} {
+	return
+    }
+
+    # Start up the rsh daemon.
+    start_rsh_daemon -k
+
+    # Run rsh date.
+    set testname "date"
+    spawn $RSH $hostname -k $REALMNAME -D [expr 8 + $portbase] -A date
+    expect {
+	-re "\[A-Za-z0-9\]+ \[A-Za-z0-9\]+ +\[0-9\]+ \[0-9\]+:\[0-9\]+:\[0-9\]+ \[A-Za-z0-9\]+ \[0-9\]+\r\n" {
+	    set result $expect_out(0,string)
+	}
+	timeout {
+	    fail "$testname (timeout)"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    return
+	}
+    }
+    expect eof
+    if ![check_exit_status $testname] {
+	return
+    }
+
+    if [check_date $result] {
+	pass $testname
+    } else {
+	fail $testname
+    }
+
+    # The rsh daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_rsh_daemon
+
+    # Check encrypted rsh.
+    set failed no
+    start_rsh_daemon -ek
+    set testname "encrypted rsh"
+    spawn $RSH $hostname -x -k $REALMNAME -D [expr 8 + $portbase] -A echo hello
+    expect {
+	"hello" { expect eof }
+	timeout {
+	    fail "$testname (timeout)"
+	    set failed yes
+	}
+	eof {
+	    fail "$testname (eof)"
+	    set failed yes
+	}
+    }
+
+    catch "expect eof"
+    if { $failed == "no" } {
+	if ![check_exit_status $testname] {
+	    return
+	}
+	pass $testname
+	stop_rsh_daemon
+    } else {
+	catch "wait -i $spawn_id"
+	catch "close -i $spawn_id"
+	stop_rsh_daemon
+    }
+
+    # Check ticket forwarding
+    set failed no
+    start_rsh_daemon -k
+    set testname "rsh forwarding tickets"
+
+    # We need a wrapper for klist in order to setup for shared library 
+    # runtime environment
+    setup_wrapper $tmppwd/klist.wrap $KLIST
+
+    spawn $RSH $hostname -f -k $REALMNAME -D [expr 8 + $portbase] -A $BINSH -c $tmppwd/klist.wrap 
+    expect {
+	"Ticket cache:*\r" {
+	    expect eof
+	}
+ 	"klist: No credentials cache file found" {
+	    fail "$testname (not forwarded)"
+	    return
+	}
+	timeout {
+	    fail "$testname (timeout)"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    return
+	}
+    }
+
+    if ![check_exit_status $testname] {
+	return
+    }
+
+    pass $testname
+
+    stop_rsh_daemon
+
+    # Check encrypted ticket forwarding
+    set failed no
+    start_rsh_daemon -e
+    set testname "encrypted rsh forwarding tickets"
+    spawn $RSH $hostname -x -f -k $REALMNAME -D [expr 8 + $portbase] -A $BINSH -c $tmppwd/klist.wrap 
+    expect {
+	"Ticket cache:*\r" {
+	    expect eof
+	}
+ 	"klist: No credentials cache file found" {
+	    fail "$testname (not forwarded)"
+	    return
+	}
+	timeout {
+	    fail "$testname (timeout)"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    return
+	}
+    }
+
+    if ![check_exit_status $testname] {
+	return
+    }
+
+    pass $testname
+
+    stop_rsh_daemon
+
+    # Check stderr
+    start_rsh_daemon -k
+    set testname "rsh to stderr"
+    spawn $RSH $hostname -k $REALMNAME -D [expr 8 + $portbase] -A $BINSH -c "'echo hello 1>&2'"
+    expect {
+	"hello" { expect eof }
+	timeout {
+	    fail "$testname (timeout)"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    return
+	}
+    }
+
+    if ![check_exit_status $testname] {
+	return
+    }
+
+    pass $testname
+
+    stop_rsh_daemon
+
+    start_rsh_daemon -e
+    set testname "encrypted rsh to stderr"
+    spawn $RSH $hostname -x -k $REALMNAME -D [expr 8 + $portbase] -A $BINSH -c "'echo hello 1>&2'"
+    expect {
+	"hello" { expect eof }
+	timeout {
+	    fail "$testname (timeout)"
+	    return
+	}
+	eof {
+	    fail "$testname (eof)"
+	    return
+	}
+    }
+
+    if ![check_exit_status $testname] {
+	return
+    }
+
+    pass $testname
+
+    # The rsh daemon should have stopped, but we have no easy way
+    # of checking whether it actually did.  Kill it just in case.
+    stop_rsh_daemon
+}
+
+# Run the test.
+set status [catch rsh_test msg]
+
+# Shut down the kerberos daemons and the rsh daemon.
+stop_kerberos_daemons
+
+stop_rsh_daemon
+
+if { $status != 0 } {
+    send_error "ERROR: error in rsh.exp\n"
+    send_error "$msg\n"
+    exit 1
+}

Added: trunk/tests/resolve/Makefile.in
===================================================================
--- trunk/tests/resolve/Makefile.in	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/resolve/Makefile.in	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,30 @@
+mydir=tests/resolve
+BUILDTOP=$(REL)..$(S)..
+PROG_LIBPATH=-L$(TOPLIBD)
+PROG_RPATH=$(KRB5_LIBDIR)
+
+OBJS=resolve.o addrinfo-test.o fake-addrinfo-test.o
+SRCS=$(srcdir)/resolve.c $(srcdir)/addrinfo-test.c \
+	$(srcdir)/fake-addrinfo-test.c
+
+all:: resolve addrinfo-test fake-addrinfo-test
+
+resolve: resolve.o
+	$(CC_LINK) -o $@ resolve.o $(LIBS)
+
+addrinfo-test: addrinfo-test.o
+	$(CC_LINK) -o $@ addrinfo-test.o $(KRB5_BASE_LIBS) $(LIBS)
+
+fake-addrinfo-test: fake-addrinfo-test.o
+	$(CC_LINK) -o $@ fake-addrinfo-test.o $(KRB5_BASE_LIBS) $(LIBS)
+
+check:: resolve addrinfo-test fake-addrinfo-test
+	$(VALGRIND) ./resolve
+	$(VALGRIND) ./addrinfo-test -p telnet
+	$(VALGRIND) ./fake-addrinfo-test -p telnet
+
+install::
+
+clean::
+	$(RM) resolve addrinfo-test fake-addrinfo-test
+

Added: trunk/tests/resolve/addrinfo-test.c
===================================================================
--- trunk/tests/resolve/addrinfo-test.c	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/resolve/addrinfo-test.c	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,316 @@
+/*
+ * test/resolve/addrinfo-test.c
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * A simple program to test the functionality of the getaddrinfo function.
+ *
+ * Usage:
+ *   addrinfo-test [-t|-u|-R|-I] [-d|-s|-r] [-p port] [-P] [hostname]
+ *
+ *   When invoked with no arguments, NULL is used for the node name,
+ *   which (at least with a non-null "port") means a socket address
+ *   is desired that can be used with connect() or bind() (depending
+ *   on whether "-P" is given).
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h> /* needed for IPPROTO_* on NetBSD */
+#include <k5-platform.h>
+#ifdef USE_FAKE_ADDRINFO
+#include "fake-addrinfo.h"
+#endif
+
+static const char *protoname (int p) {
+    static char buf[30];
+
+#define X(N) if (p == IPPROTO_ ## N) return #N
+
+    X(TCP);
+    X(UDP);
+    X(ICMP);
+#ifdef IPPROTO_IPV6
+    X(IPV6);
+#endif
+#ifdef IPPROTO_GRE
+    X(GRE);
+#endif
+#ifdef IPPROTO_NONE
+    X(NONE);
+#endif
+    X(RAW);
+#ifdef IPPROTO_COMP
+    X(COMP);
+#endif
+
+    snprintf(buf, sizeof(buf), " %-2d", p);
+    return buf;
+}	
+
+static const char *socktypename (int t) {
+    static char buf[30];
+    switch (t) {
+    case SOCK_DGRAM: return "DGRAM";
+    case SOCK_STREAM: return "STREAM";
+    case SOCK_RAW: return "RAW";
+    case SOCK_RDM: return "RDM";
+    case SOCK_SEQPACKET: return "SEQPACKET";
+    }
+    snprintf(buf, sizeof(buf), " %-2d", t);
+    return buf;
+}
+
+static char *whoami;
+
+static void usage () {
+    fprintf(stderr,
+	    "usage:\n"
+	    "\t%s [ options ] [host]\n"
+	    "options:\n"
+	    "\t-t\tspecify protocol IPPROTO_TCP\n"
+	    "\t-u\tspecify protocol IPPROTO_UDP\n"
+	    "\t-R\tspecify protocol IPPROTO_RAW\n"
+	    "\t-I\tspecify protocol IPPROTO_ICMP\n"
+	    "\n"
+	    "\t-d\tspecify socket type SOCK_DGRAM\n"
+	    "\t-s\tspecify socket type SOCK_STREAM\n"
+	    "\t-r\tspecify socket type SOCK_RAW\n"
+	    "\n"
+	    "\t-4\tspecify address family AF_INET\n"
+#ifdef AF_INET6
+	    "\t-6\tspecify address family AF_INET6\n"
+#endif
+	    "\n"
+	    "\t-p P\tspecify port P (service name or port number)\n"
+	    "\t-N\thostname is numeric, skip DNS query\n"
+	    "\t-n\tservice/port is numeric (sets AI_NUMERICSERV)\n"
+	    "\t-P\tset AI_PASSIVE\n"
+	    "\n"
+	    "default: protocol 0, socket type 0, address family 0, null port\n"
+	    ,
+	    whoami);
+    /* [ -t | -u | -R | -I ] [ -d | -s | -r ] [ -p port ] */
+    exit (1);
+}
+
+static const char *familyname (int f) {
+    static char buf[30];
+    switch (f) {
+    default:
+	snprintf(buf, sizeof(buf), "AF %d", f);
+	return buf;
+    case AF_INET: return "AF_INET";
+#ifdef AF_INET6
+    case AF_INET6: return "AF_INET6";
+#endif
+    }
+}
+
+#define eaistr(X) (X == EAI_SYSTEM ? strerror(errno) : gai_strerror(X))
+
+int main (int argc, char *argv[])
+{
+    struct addrinfo *ap, *ap2;
+    int err, numerichost = 0, numericserv = 0;
+    char *hname, *port = 0, *sep;
+    struct addrinfo hints;
+
+    whoami = strrchr(argv[0], '/');
+    if (whoami == 0)
+	whoami = argv[0];
+    else
+	whoami = whoami+1;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = 0;
+    hints.ai_socktype = 0;
+
+    hname = 0;
+    hints.ai_family = 0;
+
+    if (argc == 1)
+	usage ();
+
+    while (++argv, --argc > 0) {
+	char *arg;
+	arg = *argv;
+
+	if (*arg != '-')
+	    hname = arg;
+	else if (arg[1] == 0 || arg[2] != 0)
+	    usage ();
+	else
+	    switch (arg[1]) {
+	    case 'u':
+		hints.ai_protocol = IPPROTO_UDP;
+		break;
+	    case 't':
+		hints.ai_protocol = IPPROTO_TCP;
+		break;
+	    case 'R':
+		hints.ai_protocol = IPPROTO_RAW;
+		break;
+	    case 'I':
+		hints.ai_protocol = IPPROTO_ICMP;
+		break;
+	    case 'd':
+		hints.ai_socktype = SOCK_DGRAM;
+		break;
+	    case 's':
+		hints.ai_socktype = SOCK_STREAM;
+		break;
+	    case 'r':
+		hints.ai_socktype = SOCK_RAW;
+		break;
+	    case 'p':
+		if (argv[1] == 0 || argv[1][0] == 0 || argv[1][0] == '-')
+		    usage ();
+		port = argv[1];
+		argc--, argv++;
+		break;
+	    case '4':
+		hints.ai_family = AF_INET;
+		break;
+#ifdef AF_INET6
+	    case '6':
+		hints.ai_family = AF_INET6;
+		break;
+#endif
+	    case 'N':
+		numerichost = 1;
+		break;
+	    case 'n':
+		numericserv = 1;
+		break;
+	    case 'P':
+		hints.ai_flags |= AI_PASSIVE;
+		break;
+	    default:
+		usage ();
+	    }
+    }
+
+    if (hname && !numerichost)
+	hints.ai_flags |= AI_CANONNAME;
+    if (numerichost) {
+#ifdef AI_NUMERICHOST
+	hints.ai_flags |= AI_NUMERICHOST;
+#else
+	fprintf(stderr, "AI_NUMERICHOST not defined on this platform\n");
+	exit(1);
+#endif
+    }
+    if (numericserv) {
+#ifdef AI_NUMERICSERV
+	hints.ai_flags |= AI_NUMERICSERV;
+#else
+	fprintf(stderr, "AI_NUMERICSERV not defined on this platform\n");
+	exit(1);
+#endif
+    }
+
+    printf("getaddrinfo(hostname %s, service %s,\n"
+	   "            hints { ",
+	   hname ? hname : "(null)", port ? port : "(null)");
+    sep = "";
+#define Z(FLAG) if (hints.ai_flags & AI_##FLAG) printf("%s%s", sep, #FLAG), sep = "|"
+    Z(CANONNAME);
+    Z(PASSIVE);
+#ifdef AI_NUMERICHOST
+    Z(NUMERICHOST);
+#endif
+#ifdef AI_NUMERICSERV
+    Z(NUMERICSERV);
+#endif
+    if (sep[0] == 0)
+	printf ("no-flags");
+    if (hints.ai_family)
+	printf(" %s", familyname(hints.ai_family));
+    if (hints.ai_socktype)
+	printf(" SOCK_%s", socktypename(hints.ai_socktype));
+    if (hints.ai_protocol)
+	printf(" IPPROTO_%s", protoname(hints.ai_protocol));
+    printf(" }):\n");
+
+    err = getaddrinfo(hname, port, &hints, &ap);
+    if (err) {
+	printf("\terror => %s\n", eaistr(err));
+	return 1;
+    }
+
+#if defined(SIN6_LEN)
+    if (ap->ai_addr->sa_len == 0)
+	printf ("BAD: sa_len not set!\n");
+#endif
+
+
+    for (ap2 = ap; ap2; ap2 = ap2->ai_next) {
+	char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+	/* If we don't do this, even AIX's own getnameinfo will reject
+	   the sockaddr structures.  The sa_len field doesn't get set
+	   either, on AIX, but getnameinfo won't complain.  */
+	if (ap2->ai_addr->sa_family == 0) {
+	    printf("BAD: sa_family zero! fixing...\n");
+	    ap2->ai_addr->sa_family = ap2->ai_family;
+	} else if (ap2->ai_addr->sa_family != ap2->ai_family) {
+	    printf("BAD: sa_family != ai_family! fixing...\n");
+	    ap2->ai_addr->sa_family = ap2->ai_family;
+	}
+	if (getnameinfo(ap2->ai_addr, ap2->ai_addrlen, hbuf, sizeof(hbuf),
+			pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
+	    strlcpy(hbuf, "...", sizeof(hbuf));
+	    strlcpy(pbuf, "...", sizeof(pbuf));
+	}
+	printf("%p:\n"
+	       "\tfamily = %s\tproto = %-4s\tsocktype = %s\n",
+	       ap2, familyname(ap2->ai_family),
+	       protoname (ap2->ai_protocol),
+	       socktypename (ap2->ai_socktype));
+	if (ap2->ai_canonname) {
+	    if (ap2->ai_canonname[0])
+		printf("\tcanonname = %s\n", ap2->ai_canonname);
+	    else
+		printf("BAD: ai_canonname is set but empty!\n");
+	} else if (ap2 == ap && (hints.ai_flags & AI_CANONNAME)) {
+	    printf("BAD: first ai_canonname is null!\n");
+	}
+	printf("\taddr = %-28s\tport = %s\n", hbuf, pbuf);
+
+	err = getnameinfo(ap2->ai_addr, ap2->ai_addrlen, hbuf, sizeof (hbuf),
+			  pbuf, sizeof(pbuf), NI_NAMEREQD);
+	if (err)
+	    printf("\tgetnameinfo(NI_NAMEREQD): %s\n", eaistr(err));
+	else
+	    printf("\tgetnameinfo => %s, %s\n", hbuf, pbuf);
+    }
+    freeaddrinfo(ap);
+    return 0;
+}

Added: trunk/tests/resolve/deps
===================================================================
--- trunk/tests/resolve/deps	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/resolve/deps	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,10 @@
+# 
+# Generated makefile dependencies follow.
+#
+$(OUTPRE)resolve.$(OBJEXT): $(BUILDTOP)/autoconf.h \
+  resolve.c
+$(OUTPRE)addrinfo-test.$(OBJEXT): $(BUILDTOP)/autoconf.h \
+  $(SRCTOP)/k5-platform.h addrinfo-test.c
+$(OUTPRE)fake-addrinfo-test.$(OBJEXT): $(BUILDTOP)/autoconf.h \
+  $(SRCTOP)/fake-addrinfo.h $(SRCTOP)/k5-platform.h $(SRCTOP)/port-sockets.h \
+  $(SRCTOP)/socket-utils.h addrinfo-test.c fake-addrinfo-test.c

Added: trunk/tests/resolve/fake-addrinfo-test.c
===================================================================
--- trunk/tests/resolve/fake-addrinfo-test.c	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/resolve/fake-addrinfo-test.c	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,2 @@
+#define USE_FAKE_ADDRINFO
+#include "addrinfo-test.c"

Added: trunk/tests/resolve/resolve.c
===================================================================
--- trunk/tests/resolve/resolve.c	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/resolve/resolve.c	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,172 @@
+/*
+ * test/resolve/resolve.c
+ *
+ * Copyright 1995 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * A simple program to test the functionality of the resolver library.
+ * It simply will try to get the IP address of the host, and then look 
+ * up the name from the address. If the resulting name does not contain the
+ * domain name, then the resolve library is broken.
+ *
+ * Warning: It is possible to fool this program into thinking everything is 
+ * alright byt a clever use of /etc/hosts - but this is better than nothing.
+ *
+ * Usage:
+ *   resolve [hostname]
+ *
+ *   When invoked with no arguments, gethostname is used for the local host.
+ *
+ */
+
+/* This program tests the resolve library and sees if it is broken... */
+
+#include "autoconf.h"
+#include <stdio.h>
+
+#if STDC_HEADERS
+#include <string.h>
+#else
+#ifndef HAVE_STRCHR
+#define strchr index
+#endif
+char *strchr();
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <netinet/in.h>
+#include <netdb.h>
+
+int
+main(argc, argv)
+     int argc;
+     char **argv;
+{
+	char myname[MAXHOSTNAMELEN+1];
+	char *ptr;
+	struct in_addr addrcopy;
+	struct hostent *host;
+	int quiet = 0;
+
+	argc--; argv++;
+	while (argc) {
+	    if ((strcmp(*argv, "--quiet") == 0) ||
+		(strcmp(*argv, "-q") == 0)) {
+		quiet++;
+	    } else 
+		break;
+	    argc--; argv++;
+	}
+
+	if (argc >= 1) {
+		strncpy(myname, *argv, MAXHOSTNAMELEN);
+	} else {
+		if(gethostname(myname, MAXHOSTNAMELEN)) {
+			perror("gethostname failure");
+			exit(1);
+		}
+	}
+	
+	myname[MAXHOSTNAMELEN] = '\0';	/* for safety */
+	
+	/* Look up the address... */
+	if (!quiet)
+	    printf("Hostname:  %s\n", myname);
+	
+
+	/* Set the hosts db to close each time - effectively rewinding file */
+	sethostent(0);
+
+	if((host = gethostbyname (myname)) == NULL) {
+		fprintf(stderr,
+			"Could not look up address for hostname '%s' - fatal\n",
+			myname);
+		exit(2);
+	}
+	
+	ptr = host->h_addr_list[0];
+#define UC(a) (((int)a)&0xff)
+	if (!quiet)
+	    printf("Host address: %d.%d.%d.%d\n", 
+		   UC(ptr[0]), UC(ptr[1]), UC(ptr[2]), UC(ptr[3]));
+
+	memcpy(&addrcopy.s_addr, ptr, 4);
+
+	/* Convert back to full name */
+	if((host = gethostbyaddr(&addrcopy.s_addr, 4, AF_INET)) == NULL) {
+		fprintf(stderr, "Error looking up IP address - fatal\n");
+		exit(2);
+	}
+	
+	if (quiet)
+	    printf("%s\n", host->h_name);
+	else
+	    printf("FQDN: %s\n", host->h_name);
+	
+	/*
+	 * The host name must have at least one '.' in the name, and
+	 * if there is only one '.', it must not be at the end of the
+	 * string.  (i.e., "foo." is not a FQDN)
+	 */
+	ptr = strchr(host->h_name, '.');
+	if (ptr == NULL || ptr[1] == '\0') {
+		fprintf(stderr,
+			"\nResolve library did not return a "
+			"fully qualified domain name.\n\n"
+			"If you are using /etc/hosts before DNS, "
+			"e.g. \"files\" is listed first\n"
+			"for \"hosts:\" in nsswitch.conf, ensure that "
+			"you have listed the FQDN\n"
+			"as the first name for the local host.\n\n"
+			"If this does not correct the problem, "
+			"you may have to reconfigure the kerberos\n"
+			"distribution to select a "
+			"different set of libraries using \n"
+			"--with-netlib[=libs]\n");
+		exit(3);
+	}
+
+	if (!quiet)
+	    printf("Resolve library appears to have passed the test\n");
+
+	/* All ok */
+	exit(0);
+
+}
+
+

Added: trunk/tests/t_inetd.c
===================================================================
--- trunk/tests/t_inetd.c	2009-07-09 16:19:16 UTC (rev 3258)
+++ trunk/tests/t_inetd.c	2009-07-10 20:35:46 UTC (rev 3259)
@@ -0,0 +1,140 @@
+/*
+ * tests/dejagnu/t_inetd.c
+ *
+ * Copyright 1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * A simple program to simulate starting a process from inetd.
+ *
+ * Unlike a proper inetd situation, environment variables are passed 
+ * to the client.
+ *
+ * usage: t_inetd port program argv0 ...
+ *		
+ */
+
+#include "autoconf.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "com_err.h"
+
+
+char *progname;
+
+static void usage()
+{
+	fprintf(stderr, "%s: port program argv0 argv1 ...\n", progname);
+	exit(1);
+}
+
+int
+main(argc, argv)
+    int argc;
+    char **argv;
+{
+	unsigned short port;
+	char *path;
+	int sock, acc;
+	int one = 1;
+	struct sockaddr_in l_inaddr, f_inaddr;	/* local, foreign address */
+	int namelen = sizeof(f_inaddr);
+#ifdef POSIX_SIGNALS
+	struct sigaction csig;
+#endif
+
+	progname = argv[0];
+
+	if(argc <= 3) usage();
+
+	if(atoi(argv[1]) == 0) usage();
+
+	port = htons(atoi(argv[1]));
+	path = argv[2];
+
+	if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+	    com_err(progname, errno, "creating socket");
+	    exit(3);
+	}
+
+	(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one,
+			  sizeof (one));
+
+	l_inaddr.sin_family = AF_INET;
+	l_inaddr.sin_addr.s_addr = 0;
+	l_inaddr.sin_port = port;
+
+	if (bind(sock, (struct sockaddr *)&l_inaddr, sizeof(l_inaddr))) {
+	    com_err(progname, errno, "binding socket");
+	    exit(3);
+	}
+
+	if (listen(sock, 1) == -1) {
+	    com_err(progname, errno, "listening");
+	    exit(3);
+	}
+
+	printf("Ready!\n");
+	if ((acc = accept(sock, (struct sockaddr *)&f_inaddr,
+			  &namelen)) == -1) {
+	    com_err(progname, errno, "accepting");
+	    exit(3);
+	}
+
+	dup2(acc, 0);
+	dup2(acc, 1);
+	dup2(acc, 2);
+	close(sock);
+	sock = 0;
+
+	/* Don't wait for a child signal... Otherwise dejagnu gets confused */
+#ifdef POSIX_SIGNALS
+	csig.sa_handler = (RETSIGTYPE (*)())0;
+	sigemptyset(&csig.sa_mask);
+	csig.sa_flags = 0;
+	sigaction(SIGCHLD, &csig, (struct sigaction *)0);
+#else
+	signal(SIGCHLD, SIG_IGN);
+#endif
+
+	if(execv(path, &argv[3]))
+		fprintf(stderr, "t_inetd: Could not exec %s\n", path);
+	exit(1);
+}
+




More information about the Krb5-appl-commits mailing list