Index: README
diff -c /dev/null krb5/README:1.21
*** /dev/null	Thu Sep 23 15:40:14 1999
--- krb5/README	Fri Aug 27 19:34:13 1999
***************
*** 0 ****
--- 1,192 ----
+ Notes on the NRL Kerberos CVS tree:
+ 
+ This is a working copy of the sources I use for Kerberos development.
+ Changes I (and others) make to Kerberos are made available via this
+ CVS tree.
+ 
+ If you're not familiar with CVS, the documentation that comes with
+ the distribution is a good starting point.  The important things you
+ need to know are:
+ 
+ 	cvs checkout - Gets the initial copy of the source tree
+ 	cvs update   - Brings external changes into your local working
+ 		       directory.
+ 	cvs commit   - Puts changes you made in your working directory
+ 		       into the revision control directory.
+ 
+ This distribution is set up as a "development" distribution, which means
+ it differs slightly from the normal distribution from MIT.  For example,
+ there are no configure scripts included in the CVS tree.  This is because
+ they are automatically generated, and it makes no sense to put automatically
+ generated files under revision control.
+ 
+ To build the distribution from the CVS tree, you will need:
+ 
+ - The latest copy of GNU m4.
+ - The latest copy of GNU make.
+ 
+ Steps for building the distribution:
+ 
+ 1) First, you will need to build Autoconf.  Note that you _must_ use the
+    copy of Autoconf that comes with Kerberos - not the standard GNU
+    Autoconf.  This requires GNU m4.  To build Autoconf, do (from the top
+    of the Kerberos source tree):
+ 
+    cd util/autoconf
+    ./configure
+    make
+ 
+ 2) Generate all of the configure scripts and automatically generated
+    header files.
+ 
+    cd <top of source tree>
+    ./util/reconf
+ 
+ 3) Run configure.  I _highly_ recommend that you build Kerberos in an
+    object directory.  This makes CVS management a lot easier and gives
+    you the ability to build for multiple architectures from the same
+    source code tree.  To do this:
+ 
+    mkdir <object-directory>
+    cd <object-directory>
+    <source-directory>/configure <... your configure options ...>
+ 
+ 4) Build the distribution.  This requires GNU make.
+ 
+    cd <object-directory>
+    gmake (or whatever you call GNU make)
+ 
+ 
+ In addition to the standard configure options, this distribution has
+ a number of extra ones:
+ 
+ --with-afs=AFSDIR
+ 
+ 	Enable AFS compatibility.  This will make the application daemons
+ 	create PAGs and run aklog at the appropriate places.  AFSDIR
+ 	is the location of the AFS client libraries.
+ 
+ --with-afs-setpag-always
+ 
+ 	Always create a PAG at login time, even for root.  Only useful
+ 	with the --with-afs option.
+ 
+ --enable-irix-project-init
+ 
+ 	Have login.krb5 call the right functions to set up the array
+ 	session and project id for Irix 6.4 and newer systems.
+ 
+ --without-session-encrypt
+ 
+ 	Disable session encryption in the client programs.  Should only
+ 	be enabled to create exportable binaries.
+ 
+ --with-afs-name-change
+ 
+ 	Enable extra code to support an AFS cell with a different name
+ 	than your Kerberos realm.
+ 
+ --with-securid-preauth=DIR
+ 
+ 	Enable code to support SecurID cards as a hardware preauthentication
+ 	mechanism.  DIR is the directory containing sdiclient.a and
+ 	the SecurID client include files.  Note: this is very buggy,
+ 	mostly due to the _extremely_ poor interface to the SecurID
+ 	cards.  Not recommended.
+ 
+ --without-strptime
+ 
+ 	Never use the native strptime() library function, but always
+ 	use the one included in the Kerberos library.  Only useful
+ 	for Irix 6.x systems, which have a buggy strptime().
+ 
+ --enable-app-proxy
+ 
+ 	Enable code to support application proxy gateways by allowing
+ 	the addition of extra IP addresses into the ticket.  Experimental.
+ 
+ --enable-btree-db
+ 
+ 	Use a btree database for the KDC instead of a hash database.
+ 	Highly recommended.
+ 
+ --with-cracklib=<full path to cracklib source tree>
+ 
+ 	Use cracklib instead of a flat dictionary file for password checking.
+ 	See lib/kadm5/srv/cracklib/README for details.
+ 
+ --with-hp-exemplar-krshd-hack
+ 
+ 	This hack allows krshd to run consistantly on the HP Exemplar.
+ 	Under HP-UX 10.01 I was seeing a bug (I believe in HP's networking
+ 	code) that caused krshd to fail every other time. This hack allows
+ 	krshd to work, at the cost of being able to do encryption and
+ 	handle signals via the second port.
+ 
+ --with-multihomed-fixes
+ 
+ 	This enables code in some application servers (klogind, kshd, and
+ 	ftpd) that help Kerberos to work in environments with multi-homed
+ 	hosts. In the case of klogind and kshd it caused them not to check
+ 	the IP address in a received ticket against the IP address the
+ 	ticket came from. For ftpd it causes ftpd to use the name of
+ 	interface the connection was received on instead of the local
+ 	hostname to build the name of the service principal to use.
+ 
+ --with-login-conf=<full path to conf file>
+ 
+ 	This enables code in login to parse and use options in a login
+ 	configuration file (e.g. /etc/default/login under IRIX).
+ 	Currently the only option that is used is the CONSOLE
+ 	value which specifies where root may log in using a password.
+ 
+ --with-kadmin-cryptocard
+ 
+ 	Support programming a CRYPTOCard RB-1 token via a special
+ 	interface in kadmin.  This will either generate the front
+ 	panel programming information or talk to a RB-1 Token
+ 	Initializer.
+ 
+ --with-cryptocard-validate
+ 
+ 	This enables KDC code to allow the validation of a CRYPTOCard
+ 	RB-1 token without the entering of a user's password (it
+ 	requires a host key or other encryption key to send the
+ 	response, however).  Note that the utilization of this code
+ 	requires changes to the client libraries that are not in this
+ 	distribution.
+ 
+ --with-krb524-remapping
+ 
+ 	This enables code in the 524 ticket converter to map principals
+ 	in foreign realms to principals in the local realm when getting
+ 	tickets for the AFS service.  This is used to solve the problem
+ 	of foreign cross-realm users having PTS IDs that don't match
+ 	their Unix userid.  Note that this code has a number of
+ 	interesting security implications, so do not enable it unless
+ 	you know what you're doing!
+ 
+ --enable-login-print-issue
+ 
+ 	This enables code that causes login.krb5 to print /etc/issue,
+ 	if it is present, before the use logs in.
+ 
+ --enable-log-preauth-logins
+ 
+ 	This enables code in login.krb5 and ftpd that changes the syslog
+ 	messages generated so that they indicate whether a user login is
+ 	done with a password or if it is preauthenticated.
+ 
+ --enable-dns-lookup
+ 
+ 	This enables code to look up KDC location in DNS (via DNS SRV
+ 	records).  The local file is still looked at first.  For
+ 	more information, see RFC 2052 (note that this code complies
+ 	with the new Internet-Draft and and uses _ to prefix the service
+ 	and protocol labels).  This code also enables the mapping of
+ 	hosts/domains to Kerberos realm via TXT records.  Some examples:
+ 
+ 	_kerberos._udp.my.realm.	IN	SRV	0 0 88 kdc1.my.domain.
+ 	_kerberos._udp.my.realm.	IN	SRV	1 0 88 kdc2.my.domain.
+ 
+ 	_kerberos.my.domain.		IN	TXT	"MY.REALM"
Index: aclocal.m4
diff -c krb5/aclocal.m4:1.1.1.2 krb5/aclocal.m4:1.7
*** krb5/aclocal.m4:1.1.1.2	Wed May 12 13:20:52 1999
--- krb5/aclocal.m4	Fri Aug 27 19:34:14 1999
***************
*** 84,89 ****
--- 84,90 ----
  AC_CONST dnl
  WITH_NETLIB dnl
  KRB_INCLUDE dnl
+ CHECK_64BIT dnl
  AC_ARG_PROGRAM dnl
  AC_SUBST(ALL_RECURSE)
  AC_SUBST(CLEAN_RECURSE)
***************
*** 643,648 ****
--- 644,660 ----
  if test $krb5_cv_struct_ut_exit = no; then
    AC_DEFINE(NO_UT_EXIT)
  fi
+ AC_MSG_CHECKING([ut_exit in struct utmpx])
+ AC_CACHE_VAL(krb5_cv_struct_utx_exit,
+ [AC_TRY_COMPILE(
+ [#include <sys/types.h>
+ #include <utmpx.h>],
+ [struct utmpx ut; ut.ut_exit;],
+ krb5_cv_struct_utx_exit=yes, krb5_cv_struct_utx_exit=no)])
+ AC_MSG_RESULT($krb5_cv_struct_utx_exit)
+ if test $krb5_cv_struct_utx_exit = no; then
+   AC_DEFINE(NO_UTX_EXIT)
+ fi
  AC_FUNC_CHECK(setutent,AC_DEFINE(HAVE_SETUTENT))
  AC_FUNC_CHECK(setutxent,AC_DEFINE(HAVE_SETUTXENT))
  AC_FUNC_CHECK(updwtmp,AC_DEFINE(HAVE_UPDWTMP))
***************
*** 697,702 ****
--- 709,740 ----
  AC_MSG_RESULT($krb5_cv_has_ansi_volatile)
  if test $krb5_cv_has_ansi_volatile = no; then
  ADD_DEF(-Dvolatile=)
+ fi
+ ])dnl
+ dnl
+ dnl This rule checks for special compilation flags needed for 64 bit
+ dnl operation on some systems (like Solaris).
+ dnl
+ define(CHECK_64BIT,[
+ if test -n "$krb5_cv_host"; then
+ AC_CACHE_CHECK([for 64-bit compile flags], krb5_cv_64bit_flags,
+ [case "$krb5_cv_host" in
+ 	sparc-sun-solaris2.5* | sparc-sun-solaris2.6* | sparc-sun-solaris2.7*)
+ 		AC_PATH_PROG(GETCONF, getconf)
+ 		if test -n "$ac_cv_path_GETCONF"; then
+ 			krb5_cv_64bit_flags=`$ac_cv_path_GETCONF LFS_CFLAGS`
+ 		fi
+ 		;;
+ 	*)
+ 		;;
+ esac
+ if test -z "$krb5_cv_64bit_flags"; then
+ 	krb5_cv_64bit_flags=no;
+ fi])
+ if test "$krb5_cv_64bit_flags" != "no"; then
+ 	AC_MSG_RESULT([Adding $krb5_cv_64bit_flags to CFLAGS])
+ 	CFLAGS="$CFLAGS $krb5_cv_64bit_flags"
+ fi
  fi
  ])dnl
  dnl
Index: configure.in
diff -c krb5/configure.in:1.1.1.1 krb5/configure.in:1.2
*** krb5/configure.in:1.1.1.1	Mon Jun  2 17:54:06 1997
--- krb5/configure.in	Thu Jun 12 00:03:21 1997
***************
*** 223,228 ****
--- 223,250 ----
  	krb5_cv_shlibs_run_libpath=no
  	krb5_cv_shlibs_run_rldroot=no
    	;;
+ mips-*-irix*)
+ 	echo "Enabling shared libraries for Irix ..."
+ 	krb5_cv_shlibs_cflags=
+ 	krb5_cv_shlibs_ext=so
+ 	krb5_cv_noshlibs_ext=a
+ 	krb5_cv_shlibs_versioned_filenames=yes
+ 	krb5_cv_shlibs_need_nover=yes
+ 	krb5_cv_shlibs_dir=
+ 	krb5_cv_shlibs_ldflag=
+ 	krb5_cv_noshlibs_ldflag="-Bstatic"
+ 	krb5_cv_shlibs_sym_ufo="-U "
+ 	krb5_cv_shlibs_dirhead="-rpath "
+ 	krb5_cv_exe_need_dirs=yes
+ 	krb5_cv_shlibs_use_dirs=yes
+ 	krb5_cv_shlibs_use_colon_dirs=no
+ 	krb5_cv_shlibs_tail_comp=
+ 	krb5_cv_staticlibs_enabled=yes
+ 	krb5_cv_shlibs_enabled=yes
+ 	krb5_cv_shlibs_run_ldpath=default
+ 	krb5_cv_shlibs_run_libpath=no
+ 	krb5_cv_shlibs_run_rldroot=no
+ 	;;
  *) 
  	echo " "
  	echo "Shared libraries not supported on $krb5_cv_host"
Index: appl/bsd/configure.in
diff -c krb5/appl/bsd/configure.in:1.1.1.2 krb5/appl/bsd/configure.in:1.16
*** krb5/appl/bsd/configure.in:1.1.1.2	Wed May 12 13:20:55 1999
--- krb5/appl/bsd/configure.in	Fri Aug 27 19:30:57 1999
***************
*** 2,14 ****
  CONFIG_RULES
  LOGINLIBS=
  AC_ARG_WITH([afs],
! [  --without-afs        don't have afs libraries to build against (default)
!   --with-afs=AFSDIR    use preinstalled AFS library tree],
  ,with_afs=no)dnl
  if test $with_afs != no; then
  	AC_DEFINE(SETPAG)
! 	LOGINLIBS="$LOGINLIBS -L$with_afs/lib -L$with_afs/lib/afs -lauth -lsys -lrx -llwp"
! fi
  AC_PROG_INSTALL
  dnl dbm libs for use of an_to_ln
  AC_CHECK_LIB(util,main)
--- 2,65 ----
  CONFIG_RULES
  LOGINLIBS=
  AC_ARG_WITH([afs],
! [  --without-afs           don't have afs libraries to build against (default)
!   --with-afs=AFSDIR       use preinstalled AFS library tree],
  ,with_afs=no)dnl
  if test $with_afs != no; then
  	AC_DEFINE(SETPAG)
! 	LOGINLIBS="$LOGINLIBS -L$with_afs/lib -L$with_afs/lib/afs -lauth -lsys -lrx -llwp -lsys"
! 	case $krb5_cv_host in
! 	*-*-solaris*)
! 		LOGINLIBS="$LOGINLIBS -lc -L/usr/ucblib -lucb -R/usr/ucblib"
! 		;;
! 	*-*-hpux*)
! 		LOGINLIBS="$LOGINLIBS -lBSD -lm"
! 		;;
! 	*-*-netbsd*)
! 		LOGINLIBS="$LOGINLIBS -lcompat"
! 		;;
! 	esac
! fi
! AC_ARG_ENABLE([irix-project-init],
! [  --enable-irix-project-init   Initialize the IRIX project id at login
!   --disable-irix-project-init  Don't do IRIX project setup (default)],[
! AC_MSG_RESULT(Enabling IRIX project initialization support)
! AC_DEFINE(IRIX_PROJECT_INIT)
! ])
! AC_ARG_WITH([multihomed_fixes],
! [  --with-multihomed-fixes  Includes fixes to help deal with multihomed hosts],
! AC_DEFINE(KRB5_MULTIHOMED_FIXES))
! dnl
! dnl Check for --with-login-conf
! AC_ARG_WITH([login_conf],
! [  --with-login-conf=file   Login should use defaults in file],[
! AC_MSG_RESULT(Enabling login configuration file parsing)
! AC_DEFINE(USE_LOGIN_CONF)
! AC_DEFINE_UNQUOTED(LOGIN_CONF_FILE, "${withval}")
! ])
! dnl
! dnl Check for --with-login-print-issue[=<file>]
! AC_ARG_ENABLE([login-print-issue],
! [  --enable-login-print-issue  Have login print /etc/issue before login prompt],[
! AC_MSG_RESULT(Enable printing of /etc/issue by login)
! AC_DEFINE(PRINT_ISSUE)
! AC_DEFINE_UNQUOTED(ISSUE_FILE, "/etc/issue")
! ])
! dnl
! dnl Check for --enable-log-preauth-logins
! AC_ARG_ENABLE([log-preauth-logins],
! [  --enable-log-preauth-logins  Log whether logins are password or preauthenticated],[
! AC_MSG_RESULT(Enable logging of preauthenticated logins)
! AC_DEFINE(LOG_PREAUTH_LOGINS)
! ])
! dnl
! dnl Enable forcing login to always allocate a pag
! AC_ARG_WITH([afs-setpag-always],
! [  --with-afs-setpag-always    Always allocate a PAG, even for root],[
! AC_MSG_RESULT([Always allocate a PAG, even for root])
! AC_DEFINE(SETPAG_ALWAYS)
! ])
! dnl
  AC_PROG_INSTALL
  dnl dbm libs for use of an_to_ln
  AC_CHECK_LIB(util,main)
***************
*** 173,178 ****
--- 224,252 ----
  AC_DEFINE(HAVE_SHADOW)
  fi
  dnl
+ dnl Check for HPUX Protected password support
+ AC_MSG_CHECKING([libsec])
+ AC_CACHE_VAL(krb5_cv_have_libsec,
+ [AC_CHECK_LIB(sec, getprpwent,
+ krb5_cv_have_libsec=yes, krb5_cv_have_libsec=no)])
+ AC_MSG_RESULT($krb5_cv_have_libsec)
+ dnl
+ AC_MSG_CHECKING([HP-UX protected password support])
+ AC_CACHE_VAL(krb5_cv_protected_pwd,
+ [krb5_cv_protected_pwd=$krb5_cv_have_libsec])
+ AC_MSG_RESULT($krb5_cv_protected_pwd)
+ dnl
+ if test $krb5_cv_protected_pwd = yes; then
+ AC_DEFINE(HAVE_PRPASSWD)
+ LOGINLIBS="$LOGINLIBS -lsec"
+ fi
+ dnl
+ dnl Check for capabilities
+ AC_FUNC_CHECK(cap_set_proc,[
+ 	AC_DEFINE(HAS_CAP_SET_PROC)
+ 	AC_CHECK_HEADERS(sys/capability.h)
+ ])
+ dnl
  dnl
  AC_MSG_CHECKING([/etc/environment])
  AC_CACHE_VAL(krb5_cv_etc_environment,
***************
*** 212,217 ****
--- 286,327 ----
  if test $krb5_cv_etc_timezone = yes; then
  AC_DEFINE(HAVE_ETC_TIMEZONE)
  fi
+ AC_MSG_CHECKING([/var/adm/lastlog])
+ AC_CACHE_VAL(krb5_cv_var_adm_lastlog,
+ [AC_C_CROSS
+ if test $ac_cv_c_cross = yes; then
+ errprint(__file__:__line__: warning: Cannot check for file existence when cross compiling
+ )dnl
+ AC_MSG_ERROR(Cannot check for file existence when cross compiling)
+ else
+ if test -r /var/adm/lastlog; then
+ krb5_cv_var_adm_lastlog=yes
+ else
+ krb5_cv_var_adm_lastlog=no
+ fi
+ fi])
+ AC_MSG_RESULT($krb5_cv_var_adm_lastlog)
+ if test $krb5_cv_var_adm_lastlog = yes; then
+ AC_DEFINE(HAVE_VAR_ADM_LASTLOG)
+ AC_MSG_CHECKING(if /var/adm/lastlog is a directory)
+ AC_CACHE_VAL(krb5_cv_lastlog_directory,
+ [AC_C_CROSS
+ if test $ac_cv_c_cross = yes; then
+ errprint(__file__:__line__: warning: Cannot check for file existence when cross compiling
+ )dnl
+ AC_MSG_ERROR(Cannot check for file existence when cross compiling)
+ else
+ if test -d /var/adm/lastlog; then
+ krb5_cv_lastlog_directory=yes
+ else
+ krb5_cv_lastlog_directory=no
+ fi
+ fi])
+ AC_MSG_RESULT($krb5_cv_lastlog_directory)
+ if test $krb5_cv_lastlog_directory = yes; then
+ AC_DEFINE(HAVE_LASTLOG_DIRECTORY)
+ fi
+ fi
  dnl
  dnl
  KRB5_CHECK_PROTOS
***************
*** 231,236 ****
--- 341,365 ----
  	AC_CHECK_FUNCS(krb_get_err_text krb_save_credentials)
  	LIBS=$oldlibs
  fi
+ 
+ dnl Do we want to exclude session encryption?
+ do_encrypt=yes
+ AC_ARG_WITH([session-encrypt],
+ [  --with-session-encrypt     Support session encryption (default)
+   --without-session-encrypt  Disable session encryption],do_encrypt=$withval)
+ if test $do_encrypt = no; then
+ 	AC_DEFINE(NOENCRYPTION)
+ fi
+ dnl
+ dnl Include big hack to make krshd work on HP exemplar
+ AC_ARG_WITH([hp-exemplar-krshd-hack],
+ 	[  --with-hp-exemplar-krshd-hack  Include hack to make rshd/rlogind work right on exemplar],
+ 	hp_exemplar_krshd_hack=$withval,
+ 	hp_exemplar_krshd_hack=no)
+ if test "$hp_exemplar_krshd_hack" = "yes"; then
+ 	AC_DEFINE(HP_EXEMPLAR_KRSHD_HACK)
+ fi
+ 
  
  AC_CHECK_HEADERS(krb4-proto.h)
  V5_AC_OUTPUT_MAKEFILE
Index: appl/bsd/kcmd.c
diff -c krb5/appl/bsd/kcmd.c:1.1.1.2 krb5/appl/bsd/kcmd.c:1.7
*** krb5/appl/bsd/kcmd.c:1.1.1.2	Wed May 12 13:20:56 1999
--- krb5/appl/bsd/kcmd.c	Wed May 12 14:55:43 1999
***************
*** 37,43 ****
  #define _TYPES_
  #endif
  #include <fcntl.h>
!      
  #ifndef MAXPATHLEN
  #define MAXPATHLEN 1024
  #endif
--- 37,47 ----
  #define _TYPES_
  #endif
  #include <fcntl.h>
! 
! #ifdef HAVE_SYS_TIME_H
! #include <sys/time.h>
! #endif
! 
  #ifndef MAXPATHLEN
  #define MAXPATHLEN 1024
  #endif
***************
*** 46,51 ****
--- 50,59 ----
  #include <sys/socket.h>
  #include <sys/stat.h>
  
+ #ifdef HAVE_SYS_SELECT_H
+ #include <sys/select.h>
+ #endif
+ 
  #ifndef POSIX_SIGNALS
  #ifndef sigmask
  #define sigmask(m)    (1 << ((m)-1))
***************
*** 60,65 ****
--- 68,76 ----
  
  #include "defines.h"
  
+ #ifndef max
+ #define max(a, b)	((a > b) ? a : b)
+ #endif
  
  #define START_PORT      5120     /* arbitrary */
  char *default_service = "host";
***************
*** 83,89 ****
       krb5_flags authopts;
       int anyport;
  {
!     int i, s, timo = 1, pid;
  #ifdef POSIX_SIGNALS
      sigset_t oldmask, urgmask;
  #else
--- 94,100 ----
       krb5_flags authopts;
       int anyport;
  {
!     int i, s, timo = 1, pid, numaddrs;
  #ifdef POSIX_SIGNALS
      sigset_t oldmask, urgmask;
  #else
***************
*** 107,112 ****
--- 118,125 ----
      krb5_auth_context auth_context = NULL;
      char *cksumbuf;
      krb5_data cksumdat;
+     char **save_addr_list;
+     char **addr;
  
      if ((cksumbuf = malloc(strlen(cmd)+strlen(remuser)+64)) == 0 ) {
  	fprintf(stderr, "Unable to allocate memory for checksum buffer.\n");
***************
*** 124,130 ****
--- 137,195 ----
  	fprintf(stderr, "%s: unknown host\n", *ahost);
  	return (-1);
      }
+     
+     if ((host_save = (char *) malloc(strlen(hp->h_name) + 1)) == NULL) {
+         fprintf(stderr,"kcmd: no memory\n");
+         return(-1);
+     }
+     strcpy(host_save, hp->h_name);
+ 
+     /*
+      * Save the list of IP address too, for later
+      */
+ 
+     for (addr = hp->h_addr_list, numaddrs = 0; *addr; addr++)
+ 	numaddrs++;
+ 
+     if ((save_addr_list = (char **) malloc(sizeof(char *) * (numaddrs + 1))) ==
+ 									NULL) {
+ 	fprintf(stderr, "kcmd: no memory\n");
+ 	return(-1);
+     }
+ 
+     for (i = 0; i < numaddrs; i++) {
+ 	if ((save_addr_list[i] = (char *) malloc(hp->h_length)) == NULL) {
+ 	    fprintf(stderr, "kcmd: no memory\n");
+ 	    return(-1);
+ 	}
+ 	memcpy(save_addr_list[i], hp->h_addr_list[i], hp->h_length);
+     }
+     save_addr_list[numaddrs] = NULL;
+ 
+     /* If no service is given set to the default service */
+     if (!service) service = default_service;
+     
+     sin_len = strlen(host_save) + strlen(service)
+       + (realm ? strlen(realm): 0) + 3;
+     if ( sin_len < 20 ) sin_len = 20;
+     
+     if (!(get_cred = (krb5_creds *)calloc(1, sizeof(krb5_creds)))) {
+         fprintf(stderr,"kcmd: no memory\n");
+         return(-1);
+     }
+     status = krb5_sname_to_principal(bsd_context, host_save, service,
+ 				     KRB5_NT_SRV_HST, &get_cred->server);
+     if (status) {
+ 	    fprintf(stderr, "kcmd: krb5_sname_to_principal failed: %s\n",
+ 		    error_message(status));
+ 	    return(-1);
+     }
  
+     if (realm && *realm) {
+ 	(void) krb5_xfree(krb5_princ_realm(bsd_context,get_cred->server)->data);
+ 	krb5_princ_set_realm_length(bsd_context,get_cred->server,strlen(realm));
+ 	krb5_princ_set_realm_data(bsd_context,get_cred->server,strdup(realm));
+    }
  #ifdef POSIX_SIGNALS
      sigemptyset(&urgmask);
      sigaddset(&urgmask, SIGURG);
***************
*** 132,138 ****
  #else
      oldmask = sigblock(sigmask(SIGURG));
  #endif /* POSIX_SIGNALS */
!     
      for (;;) {
          s = getport(&lport);
      	if (s < 0) {
--- 197,205 ----
  #else
      oldmask = sigblock(sigmask(SIGURG));
  #endif /* POSIX_SIGNALS */
! 
!     addr = save_addr_list;
! 
      for (;;) {
          s = getport(&lport);
      	if (s < 0) {
***************
*** 145,154 ****
  #else
  	    sigsetmask(oldmask);
  #endif /* POSIX_SIGNALS */
  	    return (-1);
      	}
      	sin.sin_family = hp->h_addrtype;
!     	memcpy((caddr_t)&sin.sin_addr,hp->h_addr, sizeof(sin.sin_addr));
      	sin.sin_port = rport;
      	if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
  	  break;
--- 212,225 ----
  #else
  	    sigsetmask(oldmask);
  #endif /* POSIX_SIGNALS */
+ 	    krb5_free_creds(bsd_context, get_cred);
+ 	    for (addr = save_addr_list; *addr; addr++)
+ 		free(*addr);
+ 	    free(save_addr_list);
  	    return (-1);
      	}
      	sin.sin_family = hp->h_addrtype;
!     	memcpy((caddr_t)&sin.sin_addr,addr[0], sizeof(sin.sin_addr));
      	sin.sin_port = rport;
      	if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
  	  break;
***************
*** 158,187 ****
  	    continue;
      	}
  
! #if !(defined(tek) || defined(ultrix) || defined(sun) || defined(SYSV))
!     	if (hp->h_addr_list[1] != NULL) {
  	    int oerrno = errno;
  	    
  	    fprintf(stderr,
      		    "connect to address %s: ", inet_ntoa(sin.sin_addr));
  	    errno = oerrno;
  	    perror(0);
! 	    hp->h_addr_list++;
! 	    memcpy((caddr_t)&sin.sin_addr,hp->h_addr_list[0],
  		   sizeof(sin.sin_addr));
  	    fprintf(stderr, "Trying %s...\n",
  		    inet_ntoa(sin.sin_addr));
  	    continue;
      	}
! #endif /* !(defined(ultrix) || defined(sun)) */
!     	perror(hp->h_name);
  #ifdef POSIX_SIGNALS
  	sigprocmask(SIG_SETMASK, &oldmask, (sigset_t*)0);
  #else
      	sigsetmask(oldmask);
  #endif /* POSIX_SIGNALS */
      	return (-1);
      }
      lport--;
      /* If no service is given set to the default service */
      if (!service) service = default_service;
--- 229,263 ----
  	    continue;
      	}
  
!     	if (addr[1] != NULL) {
  	    int oerrno = errno;
  	    
  	    fprintf(stderr,
      		    "connect to address %s: ", inet_ntoa(sin.sin_addr));
  	    errno = oerrno;
  	    perror(0);
! 	    addr++;
! 	    memcpy((caddr_t)&sin.sin_addr,addr[0],
  		   sizeof(sin.sin_addr));
  	    fprintf(stderr, "Trying %s...\n",
  		    inet_ntoa(sin.sin_addr));
  	    continue;
      	}
!     	perror(host_save);
  #ifdef POSIX_SIGNALS
  	sigprocmask(SIG_SETMASK, &oldmask, (sigset_t*)0);
  #else
      	sigsetmask(oldmask);
  #endif /* POSIX_SIGNALS */
+ 	krb5_free_creds(bsd_context, get_cred);
+ 	for (addr = save_addr_list; *addr; addr++)
+ 	    free(*addr);
+ 	free(save_addr_list);
      	return (-1);
      }
+     for (addr = save_addr_list; *addr; addr++)
+ 	free(*addr);
+     free(save_addr_list);
      lport--;
      /* If no service is given set to the default service */
      if (!service) service = default_service;
***************
*** 219,224 ****
--- 295,302 ----
      	char num[8];
      	int s2 = getport(&lport), s3;
      	int len = sizeof (from);
+ 	int nfds;
+ 	fd_set reads;
  	
      	if (s2 < 0) {
  	    status = -1;
***************
*** 232,237 ****
--- 310,339 ----
  	    status = -1;
  	    goto bad;
      	}
+ 	nfds = max(s, s2)+1;
+ 	if(nfds > FD_SETSIZE) {
+ 	    fprintf(stderr, "rcmd: too many files\n");
+ 	    (void)close(s2);
+ 	    status = -1;
+ 	    goto bad;
+ 	}
+     again:
+ 	FD_ZERO(&reads);
+ 	FD_SET(s, &reads);
+ 	FD_SET(s2, &reads);
+ 	errno = 0;
+ 	if (select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){
+ 	    if (errno != 0)
+ 		(void)fprintf(stderr,
+ 			      "rcmd: select (setting up stderr): %s\n",
+ 			      strerror(errno));
+ 	    else
+ 		(void)fprintf(stderr,
+ 			      "select: protocol failure in circuit setup\n");
+ 	    (void)close(s2);
+ 	    status = -1;
+ 	    goto bad;
+ 	}
      	s3 = accept(s2, (struct sockaddr *)&from, &len);
      	(void) close(s2);
      	if (s3 < 0) {
***************
*** 329,335 ****
  					ret_cred->client, ret_cred->server,
  					0, options & OPTS_FORWARDABLE_CREDS,
  					&outbuf)) {
! 	    fprintf(stderr, "kcmd: Error getting forwarded creds\n");
  	    goto bad2;
  	}
  
--- 431,438 ----
  					ret_cred->client, ret_cred->server,
  					0, options & OPTS_FORWARDABLE_CREDS,
  					&outbuf)) {
! 	    fprintf(stderr, "kcmd: Error getting forwarded creds (%s)\n",
! 		error_message(status));
  	    goto bad2;
  	}
  
Index: appl/bsd/klogind.M
diff -c krb5/appl/bsd/klogind.M:1.1.1.2 krb5/appl/bsd/klogind.M:1.3
*** krb5/appl/bsd/klogind.M:1.1.1.2	Wed May 12 13:20:56 1999
--- krb5/appl/bsd/klogind.M	Wed May 12 14:55:43 1999
***************
*** 36,43 ****
  .IP 2)
  Check authorization via the access-control files \fI.k5login\fP, \fI.klogin\fP 
  and \fI.rhosts\fP in the user's home directory.
- .IP 3)
- Prompt for password if any checks fail and the \fI-p\fP option was supplied.
  .PP
  If the authentication succeeds, login the user by calling the accompanying 
  login.krb5 or /bin/login, according to the definition of 
--- 36,41 ----
***************
*** 61,72 ****
  Allow Kerberos V5 and Kerberos V4 as acceptable authentication
  mechanisms.  This is the same as including \fB\-4\fP and \fB\-5\fP.
  
- 
- .IP \fB\-p\fP
-  If all other authorization checks fail, prompt the user
- for a password If this option is not included, access is denied
- without successful authentication and authorization using one of the
- previous mechanisms.
  
  .IP \fB\-P\fP
  Prompt the user for a password.
--- 59,64 ----
Index: appl/bsd/krcp.c
diff -c krb5/appl/bsd/krcp.c:1.1.1.2 krb5/appl/bsd/krcp.c:1.6
*** krb5/appl/bsd/krcp.c:1.1.1.2	Wed May 12 13:20:57 1999
--- krb5/appl/bsd/krcp.c	Fri Aug 27 19:34:42 1999
***************
*** 79,84 ****
--- 79,85 ----
  #ifdef KERBEROS
  #include "krb5.h"
  #include "com_err.h"
+ #include "defines.h"
       
  #define RCP_BUFSIZ 4096
       
***************
*** 103,108 ****
--- 104,111 ----
  void 	usage(), sink(), source(), rsource(), verifydir(), answer_auth();
  int	response(), hosteq(), okname(), susystem();
  int	encryptflag = 0;
+ int	encrypt_option_flag = -1;
+ int	forward_flag = -1;
  
  #ifndef UCB_RCP
  #define	UCB_RCP	"/bin/rcp"
***************
*** 113,118 ****
--- 116,126 ----
  #define	des_write	write
  #endif /* KERBEROS */
  
+ #ifdef NOENCRYPTION
+ #define	des_read	read
+ #define	des_write	write
+ #endif /* NOENCRYPTION */
+ 
  int	rem;
  char	*colon();
  int	errs;
***************
*** 152,157 ****
--- 160,166 ----
      char buf[RCP_BUFSIZ], cmdbuf[30];
      char *cmd = cmdbuf;
      struct servent *sp;
+     struct servent defaultservent;
      static char curhost[256];
  #ifdef POSIX_SIGNALS
      struct sigaction sa;
***************
*** 196,208 ****
  	    port = htons(atoi(*argv));
  	    goto next_arg;
  
! 	  case 'N':
  	    forcenet++;
  	    break;
  
  #ifdef KERBEROS
  	  case 'x':
! 	    encryptflag++;
  	    break;
  	  case 'k':		/* Change kerberos realm */
  	    argc--, argv++;
--- 205,225 ----
  	    port = htons(atoi(*argv));
  	    goto next_arg;
  
! 	  case 'n':
  	    forcenet++;
  	    break;
  
  #ifdef KERBEROS
  	  case 'x':
! #ifdef NOENCRYPTION
! 			fprintf(stderr, "rcp: encryption not supported\n");
! 	     usage(); /* Does not return */
! #else /* NOENCRYPTION */
! 	    encrypt_option_flag = 1;
! 	    break;
! #endif /* NOENCRYPTION */
! 	  case 'X':
! 	    encrypt_option_flag = 0;
  	    break;
  	  case 'k':		/* Change kerberos realm */
  	    argc--, argv++;
***************
*** 234,239 ****
--- 251,270 ----
  	    }
  	    strcpy(krb_config, *argv);	
  	    goto next_arg;
+ 	  case 'F':		/* Forward credentials */
+ 	    if (forward_flag != -1) {
+ 		fprintf(stderr, "Cannot use both -F and -n.\n");
+ 		exit(1);
+ 	    }
+ 	    forward_flag = 1;
+ 	    break;
+ 	  case 'N':		/* Don't forward credentials */
+ 	    if (forward_flag != -1) {
+ 		fprintf(stderr, "Cannot use both -F and -n.\n");
+ 		exit(1);
+ 	    }
+ 	    forward_flag = 0;
+ 	    break;
  #endif /* KERBEROS */
  	    /* The rest of these are not for users. */
  	  case 'd':
***************
*** 242,251 ****
  	    
  	  case 'f':		/* "from" */
  	    iamremote = 1;
! #if defined(KERBEROS)
! 	    if (encryptflag)
  	      answer_auth(krb_config, krb_cache);
! #endif /* KERBEROS */
  
  	    (void) response();
  	    source(--argc, ++argv);
--- 273,282 ----
  	    
  	  case 'f':		/* "from" */
  	    iamremote = 1;
! #if defined(KERBEROS) && !defined(NOENCRYPTION)
! 	    if (encryptflag || encrypt_option_flag == 1)
  	      answer_auth(krb_config, krb_cache);
! #endif /* KERBEROS && !NOENCRYPTION */
  
  	    (void) response();
  	    source(--argc, ++argv);
***************
*** 253,262 ****
  	    
  	  case 't':		/* "to" */
  	    iamremote = 1;
! #if defined(KERBEROS)
! 	    if (encryptflag)
  	      answer_auth(krb_config, krb_cache);
! #endif /* KERBEROS */
  
  	    sink(--argc, ++argv);
  	    exit(errs);
--- 284,293 ----
  	    
  	  case 't':		/* "to" */
  	    iamremote = 1;
! #if defined(KERBEROS) && !defined(NOENCRYPTION)
! 	    if (encryptflag || encrypt_option_flag == 1)
  	      answer_auth(krb_config, krb_cache);
! #endif /* KERBEROS && !NOENCRYPTION */
  
  	    sink(--argc, ++argv);
  	    exit(errs);
***************
*** 283,290 ****
      
        if (sp == NULL) {
  #ifdef KERBEROS
! 	fprintf(stderr, "rcp: kshell/tcp: unknown service\n");
! 	try_normal(orig_argv);
  #else
  	fprintf(stderr, "rcp: shell/tcp: unknown service\n");
  	exit(1);
--- 314,321 ----
      
        if (sp == NULL) {
  #ifdef KERBEROS
! 	sp = &defaultservent;
! 	sp->s_port = htons(544);
  #else
  	fprintf(stderr, "rcp: shell/tcp: unknown service\n");
  	exit(1);
***************
*** 294,299 ****
--- 325,356 ----
      }
  
  #ifdef KERBEROS
+ 
+     {
+ 	krb5_data realm;
+ 
+ 	if (krb_realm) {
+ 		realm.data = krb_realm;
+ 	} else {
+ 		krb5_get_default_realm(bsd_context, &realm.data);
+ 	}
+ 
+ 	if (encrypt_option_flag == -1) {
+ 		krb5_appdefault_boolean(bsd_context, "rcp", &realm, "encrypt",
+ 					0, &encryptflag);
+ 	} else {
+ 		encryptflag = encrypt_option_flag;
+ 	}
+ 
+ 	if (forward_flag == -1) {
+ 		krb5_appdefault_boolean(bsd_context, "rcp", &realm, "forward",
+ 					0, &forward_flag);
+ 	}
+ 
+ 	if (! krb_realm)
+ 		free(realm.data);
+     }
+ 
      if (krb_realm != NULL)
  	cmdsiz += strlen(krb_realm);
      if (krb_cache != NULL)
***************
*** 411,417 ****
  				   cmd, targ);
  		    host = thost;
  #ifdef KERBEROS
! 		    authopts = AP_OPTS_MUTUAL_REQUIRED;
  		    status = kcmd(&sock, &host,
  				  port,
  				  pwd->pw_name,
--- 468,475 ----
  				   cmd, targ);
  		    host = thost;
  #ifdef KERBEROS
! 		    authopts = AP_OPTS_MUTUAL_REQUIRED |
! 			       (forward_flag ? OPTS_FORWARD_CREDS : 0);
  		    status = kcmd(&sock, &host,
  				  port,
  				  pwd->pw_name,
***************
*** 510,516 ****
  		}
  		(void) sprintf(buf, "%s -f %s", cmd, src);
  #ifdef KERBEROS
! 		authopts = AP_OPTS_MUTUAL_REQUIRED;
  		status = kcmd(&sock, &host,
  			      port,
  			      pwd->pw_name,  suser,
--- 568,575 ----
  		}
  		(void) sprintf(buf, "%s -f %s", cmd, src);
  #ifdef KERBEROS
! 		authopts = AP_OPTS_MUTUAL_REQUIRED |
! 			   (forward_flag ? OPTS_FORWARD_CREDS : 0);
  		status = kcmd(&sock, &host,
  			      port,
  			      pwd->pw_name,  suser,
***************
*** 752,759 ****
--- 811,823 ----
  		continue;
  	    }
  	}
+ #if _FILE_OFFSET_BITS==64
+ 	(void) sprintf(buf, "C%04o %llu %s\n",
+ 		       (int) stb.st_mode&07777, (off_t) stb.st_size, last);
+ #else /* _FILE_OFFSET_BITS==32 */
  	(void) sprintf(buf, "C%04o %ld %s\n",
  		       (int) stb.st_mode&07777, (long ) stb.st_size, last);
+ #endif /* _FILE_OFFSET_BITS==64 */
  	(void) des_write(rem, buf, strlen(buf));
  	if (response() < 0) {
  	    (void) close(f);
***************
*** 917,925 ****
  {
      mode_t mode;
      mode_t mask = umask(0);
!     off_t i, j;
      char *targ, *whopp, *cp;
!     int of, wrerr, exists, first, count, amt, size;
      struct buffer *bp;
      static struct buffer buffer;
      struct stat stb;
--- 981,989 ----
  {
      mode_t mode;
      mode_t mask = umask(0);
!     off_t i, j, size;
      char *targ, *whopp, *cp;
!     int of, wrerr, exists, first, count, amt;
      struct buffer *bp;
      static struct buffer buffer;
      struct stat stb;
***************
*** 1179,1186 ****
--- 1243,1255 ----
  void usage()
  {
  #ifdef KERBEROS
+ #ifdef NOENCRYPTION
+     fprintf(stderr,
+ 	    "Usage: \trcp [-p] [-k realm] f1 f2; or:\n\trcp [-r] [-p] [-k realm] f1 ... fn d2\n");
+ #else /* NOENCRYPTION */
      fprintf(stderr,
  	    "Usage: \trcp [-p] [-x] [-k realm] f1 f2; or:\n\trcp [-r] [-p] [-x] [-k realm] f1 ... fn d2\n");
+ #endif /* NOENCRYPTION */
  #else
      fputs("usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n", stderr);
  #endif
***************
*** 1259,1264 ****
--- 1328,1335 ----
  #endif
  
  
+ #ifndef NOENCRYPTION
+ 
  /* This function is mostly vestigial, since under normal operation
   * the -x flag doesn't get set for the server process for encrypted
   * rcp.  It only gets called by beta clients attempting user-to-user
***************
*** 1468,1471 ****
--- 1539,1543 ----
      return(len);
  }
  
+ #endif /* NOENCRYPTION */
  #endif /* KERBEROS */
Index: appl/bsd/krlogin.c
diff -c krb5/appl/bsd/krlogin.c:1.1.1.2 krb5/appl/bsd/krlogin.c:1.9
*** krb5/appl/bsd/krlogin.c:1.1.1.2	Wed May 12 13:20:56 1999
--- krb5/appl/bsd/krlogin.c	Fri Jun 11 10:17:07 1999
***************
*** 156,161 ****
--- 156,163 ----
  void try_normal();
  char *krb_realm = (char *)0;
  int encrypt_flag = 0;
+ int encrypt_option_flag = -1;
+ int no_forward = 0;
  int fflag = 0, Fflag = 0;
  krb5_creds *cred;
  struct sockaddr_in local, foreign;
***************
*** 171,176 ****
--- 173,183 ----
  #define des_write write
  #endif /* KERBEROS */
  
+ #ifdef NOENCRYPTION
+ #define des_read read
+ #define des_write write
+ #endif /* NOENCRYPTION */
+ 
  # ifndef TIOCPKT_WINDOW
  # define TIOCPKT_WINDOW 0x80
  # endif /* TIOCPKT_WINDOW */
***************
*** 210,215 ****
--- 217,223 ----
  { "0", "50", "75", "110", "134", "150", "200", "300",
      "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
  #endif
+ const int maxspeed = sizeof(speeds) / sizeof(char *) - 1;
  char	term[256] = "network";
  
  #ifndef POSIX_SIGNALS
***************
*** 439,445 ****
  	goto another;
      }
      if (argc > 0 && !strcmp(*argv, "-x")) {
! 	encrypt_flag++;
  	argv++, argc--;
  	goto another;
      }
--- 447,463 ----
  	goto another;
      }
      if (argc > 0 && !strcmp(*argv, "-x")) {
! #ifdef NOENCRYPTION
! 	fprintf(stderr, "rlogin: encryption not supported\n");
! 	goto usage;
! #else /* NOENCRYPTION */
! 	encrypt_option_flag = 1;
! 	argv++, argc--;
! 	goto another;
! #endif /* NOENCRYPTION */
!     }
!     if (argc > 0 && !strcmp(*argv, "-X")) {
! 	encrypt_option_flag = 0;
  	argv++, argc--;
  	goto another;
      }
***************
*** 461,466 ****
--- 479,489 ----
  	argv++, argc--;
  	goto another;
      }
+     if (argc > 0 && !strcmp(*argv, "-N")) {
+ 	no_forward++;
+ 	argv++, argc--;
+ 	goto another;
+     }
  #endif /* KERBEROS */
      if (host == 0)
        goto usage;
***************
*** 479,484 ****
--- 502,526 ----
      }
      desinbuf.data = des_inbuf;
      desoutbuf.data = des_outpkt+4;	/* Set up des buffers */
+ 
+     {
+ 	krb5_data realm;
+ 	int eflag;
+ 
+ 	if (krb_realm) {
+ 		realm.data = krb_realm;
+ 	} else {
+ 		krb5_get_default_realm(bsd_context, &realm.data);
+ 	}
+ 
+ 	krb5_appdefault_boolean(bsd_context, "rlogin", &realm, "encrypt", 0,
+ 				&eflag);
+ 	
+ 	encrypt_flag = encrypt_option_flag == -1 ? eflag : encrypt_option_flag;
+ 
+ 	if (! krb_realm)
+ 		krb5_xfree(realm.data);
+     }
  #endif
  
  
***************
*** 516,521 ****
--- 558,565 ----
  	if (tcgetattr(0, &ttyb) == 0) {
  		int ospeed = cfgetospeed (&ttyb);
  
+ 		ospeed = ospeed > maxspeed ? maxspeed : ospeed;
+ 
  		(void) strcat(term, "/");
  		if (ospeed >= 50)
  			/* On some systems, ospeed is the baud rate itself,
***************
*** 536,542 ****
  #else
      if (ioctl(0, TIOCGETP, &ttyb) == 0) {
  	(void) strcat(term, "/");
! 	(void) strcat(term, speeds[ttyb.sg_ospeed]);
      }
  #endif
      (void) get_window_size(0, &winsize);
--- 580,586 ----
  #else
      if (ioctl(0, TIOCGETP, &ttyb) == 0) {
  	(void) strcat(term, "/");
! 	(void) strcat(term, speeds[ttyb.sg_ospeed > ttyb.sg_ospeed ? maxspeed : ttyb.sg_ospeed]);
      }
  #endif
      (void) get_window_size(0, &winsize);
***************
*** 577,582 ****
--- 621,644 ----
  #ifdef KERBEROS
      authopts = AP_OPTS_MUTUAL_REQUIRED;
  
+     if (! (fflag || Fflag) && ! no_forward) {
+ 	krb5_data realm;
+ 
+ 	if (krb_realm) {
+ 		realm.data = krb_realm;
+ 	} else {
+ 		krb5_get_default_realm(bsd_context, &realm.data);
+ 	}
+ 
+ 	krb5_appdefault_boolean(bsd_context, "rlogin", &realm, "forward", 0,
+ 				&fflag);
+ 	krb5_appdefault_boolean(bsd_context, "rlogin", &realm, "forwardable", 0,
+ 				&Fflag);
+ 	
+ 	if (! krb_realm)
+ 		krb5_xfree(realm.data);
+     }
+ 
      /* Piggy-back forwarding flags on top of authopts; */
      /* they will be reset in kcmd */
      if (fflag || Fflag)
***************
*** 636,642 ****
--- 698,708 ----
  #ifdef KERBEROS
      fprintf (stderr,
  	     "usage: rlogin host [-option] [-option...] [-k realm ] [-t ttytype] [-l username]\n");
+ #ifdef NOENCRYPTION
+     fprintf (stderr, "     where option is e, 7, 8, noflow, n, a, f, F, or c\n");
+ #else /* NOENCRYPTION */
      fprintf (stderr, "     where option is e, 7, 8, noflow, n, a, x, f, F, or c\n");
+ #endif /* NOENCRYPTION */
  #else /* !KERBEROS */
      fprintf (stderr,
  	     "usage: rlogin host [-option] [-option...] [-t ttytype] [-l username]\n");
***************
*** 1570,1575 ****
--- 1636,1645 ----
       char **argv;
  {
      register char *host;
+ #ifdef POSIX_SIGNALS
+     struct sigaction sa;
+     sigset_t mask;
+ #endif
      
  #ifndef KRB5_ATHENA_COMPAT
      if (encrypt_flag)
***************
*** 1579,1592 ****
  	    UCB_RLOGIN);
      fflush(stderr);
      
!     host = strrchr(argv[0], '/');
!     if (host)
!       host++;
!     else
!       host = argv[0];
!     if (!strcmp(host, "rlogin"))
!       argv++;
      
      execv(UCB_RLOGIN, argv);
      perror("exec");
      exit(1);
--- 1649,1661 ----
  	    UCB_RLOGIN);
      fflush(stderr);
      
!     argv[0] = "rlogin";
      
+ #ifdef POSIX_SIGNALS
+     sigemptyset(&mask);
+     sigprocmask(SIG_SETMASK, &mask, NULL);
+ #endif
+ 
      execv(UCB_RLOGIN, argv);
      perror("exec");
      exit(1);
***************
*** 1598,1603 ****
--- 1667,1673 ----
  int nstored = 0;
  char *store_ptr = storage;
  
+ #ifndef NOENCRYPTION
  #ifndef OLD_VERSION
  
  int des_read(fd, buf, len)
***************
*** 1891,1896 ****
--- 1961,1967 ----
  }
  
  #endif /* OLD_VERSION */
+ #endif /* NOENCRYPTION */
  #endif /* KERBEROS */
  
  
Index: appl/bsd/krlogind.c
diff -c krb5/appl/bsd/krlogind.c:1.1.1.5 krb5/appl/bsd/krlogind.c:1.12
*** krb5/appl/bsd/krlogind.c:1.1.1.5	Wed May 12 13:20:58 1999
--- krb5/appl/bsd/krlogind.c	Wed May 12 14:55:44 1999
***************
*** 213,218 ****
--- 213,219 ----
  
  int non_privileged = 0; /* set when connection is seen to be from */
  			/* a non-privileged port */
+ int retain_ccache = 0;
  
  AUTH_DAT	*v4_kdata;
  Key_schedule v4_schedule;
***************
*** 246,252 ****
  
  krb5_keytab keytab = NULL;
  
! #define ARGSTR	"k54ciepPD:S:M:L:w:?"
  #else /* !KERBEROS */
  #define ARGSTR	"rpPD:?"
  #define (*des_read)  read
--- 247,255 ----
  
  krb5_keytab keytab = NULL;
  
! int require_hwpreauth = 0;
! 
! #define ARGSTR	"k54ciepHPD:S:M:L:w:?"
  #else /* !KERBEROS */
  #define ARGSTR	"rpPD:?"
  #define (*des_read)  read
***************
*** 363,368 ****
--- 366,374 ----
  		   error_message(status));
  	    exit(1);
      }
+ 
+     /* Blow away any KRB5CCNAME passed from inetd */
+     unsetenv("KRB5CCNAME");
  #endif
      
      /* Analyse parameters. */
***************
*** 411,416 ****
--- 417,425 ----
  	case 'M':
  	  krb5_set_default_realm(bsd_context, optarg);
  	  break;
+ 	case 'H':
+ 	  require_hwpreauth = 1;
+ 	  break;
  #endif
  	case 'p':
  	  passwd_if_fail = 1; /* Passwd reqd if any check fails */
***************
*** 908,914 ****
      int on = 1;
  #endif
      
! #if defined(TIOCPKT) && !defined(__svr4__) || defined(solaris20)
      /* if system has TIOCPKT, try to turn it on. Some drivers
       * may not support it. Save flag for later. 
       */
--- 917,923 ----
      int on = 1;
  #endif
      
! #if defined(TIOCPKT) && (!defined(__svr4__) && !defined(__sgi)) || defined(solaris20)
      /* if system has TIOCPKT, try to turn it on. Some drivers
       * may not support it. Save flag for later. 
       */
***************
*** 1047,1053 ****
  {
      pty_cleanup (line, pid, 1);
      shutdown(netf, 2);
!     if (ccache)
  	krb5_cc_destroy(bsd_context, ccache);
      exit(1);
  }
--- 1056,1062 ----
  {
      pty_cleanup (line, pid, 1);
      shutdown(netf, 2);
!     if (ccache && ! retain_ccache)
  	krb5_cc_destroy(bsd_context, ccache);
      exit(1);
  }
***************
*** 1156,1162 ****
  	}
  #endif
  
!     
  
      if (checksum_required && !valid_checksum) {
  	if (auth_sent & AUTH_KRB5) {
--- 1165,1173 ----
  	}
  #endif
  
!     if (require_hwpreauth && auth_sent & AUTH_KRB5 &&
! 	!(ticket->enc_part2->flags & TKT_FLG_HW_AUTH))
! 	    fatal(netf, "Hardware preauthetication is required on this machine.");
  
      if (checksum_required && !valid_checksum) {
  	if (auth_sent & AUTH_KRB5) {
***************
*** 1461,1471 ****
  
      if ((status = krb5_auth_con_init(bsd_context, &auth_context)))
          return status;
!  
      /* Only need remote address for rd_cred() to verify client */
      if ((status = krb5_auth_con_genaddrs(bsd_context, auth_context, netf,
  		 KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)))
  	return status;
  
      status = krb5_auth_con_getrcache(bsd_context, auth_context, &rcache);
      if (status) return status;
--- 1472,1484 ----
  
      if ((status = krb5_auth_con_init(bsd_context, &auth_context)))
          return status;
! 
! #ifndef KRB5_MULTIHOMED_FIXES
      /* Only need remote address for rd_cred() to verify client */
      if ((status = krb5_auth_con_genaddrs(bsd_context, auth_context, netf,
  		 KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)))
  	return status;
+ #endif /* !KRB5_MULTIHOMED_FIXES */
  
      status = krb5_auth_con_getrcache(bsd_context, auth_context, &rcache);
      if (status) return status;
***************
*** 1514,1519 ****
--- 1527,1538 ----
  	}
  	return status;
      }
+  
+ #ifdef KRB5_MULTIHOMED_FIXES
+     if (status = krb5_auth_con_genaddrs(bsd_context, auth_context, netf,
+ 			KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR))
+ 	return status;
+ #endif /* KRB5_MULTIHOMED_FIXES */
  
      getstr(netf, lusername, sizeof (lusername), "locuser");
      getstr(netf, term, sizeof(term), "Terminal type");
***************
*** 1554,1559 ****
--- 1573,1582 ----
        krb5_free_authenticator(bsd_context, authenticator);
      }
  
+     /* Ok, now set addresses here so ticket forwarding will work */
+     if ((status = krb5_auth_con_genaddrs(bsd_context, auth_context, netf,
+ 		 KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)))
+ 	return status;
  
  #ifdef KRB5_KRB4_COMPAT
      if (auth_sys == KRB5_RECVAUTH_V4) {
***************
*** 1610,1615 ****
--- 1633,1643 ----
  					  ticket, &ccache))) {
           fatal(netf, "Can't get forwarded credentials");
      }
+ 
+     krb5_appdefault_boolean(bsd_context, "rlogind",
+ 			   krb5_princ_realm(bsd_context, client),
+ 			   "retain_ccache", retain_ccache, &retain_ccache);
+ 
      return 0;
  }
  
Index: appl/bsd/krsh.c
diff -c krb5/appl/bsd/krsh.c:1.1.1.1 krb5/appl/bsd/krsh.c:1.5
*** krb5/appl/bsd/krsh.c:1.1.1.1	Mon Jun  2 17:54:12 1997
--- krb5/appl/bsd/krsh.c	Wed Jun  2 22:16:13 1999
***************
*** 85,91 ****
  #define UCB_RSH "/usr/ucb/rsh"
  #endif
  
! #define RSH_BUFSIZ 4096
  
  char des_inbuf[2*RSH_BUFSIZ];       /* needs to be > largest read size */
  char des_outbuf[2*RSH_BUFSIZ];      /* needs to be > largest write size */
--- 85,91 ----
  #define UCB_RSH "/usr/ucb/rsh"
  #endif
  
! #define RSH_BUFSIZ 8192
  
  char des_inbuf[2*RSH_BUFSIZ];       /* needs to be > largest read size */
  char des_outbuf[2*RSH_BUFSIZ];      /* needs to be > largest write size */
***************
*** 95,100 ****
--- 95,101 ----
  krb5_creds *cred;
  
  int	encrypt_flag = 0;
+ int	encrypt_option_flag = -1;
  char	*krb_realm = (char *)0;
  void	try_normal();
  
***************
*** 105,110 ****
--- 106,116 ----
  
  #endif /* KERBEROS */
  
+ #ifdef NOENCRYPTION
+ #define des_read read
+ #define des_write write
+ #endif /* NOENCRYPTION */
+ 
  #ifndef RLOGIN_PROGRAM
  #ifdef KERBEROS
  #define RLOGIN_PROGRAM KRB5_PATH_RLOGIN
***************
*** 143,148 ****
--- 149,155 ----
      krb5_flags authopts;
      krb5_error_code status;
      int fflag = 0, Fflag = 0;
+     int no_forward = 0;
  #endif  /* KERBEROS */
      int debug_port = 0;
  
***************
*** 203,210 ****
       * Ignore -x from kerberos rlogin
       */
      if (argc > 0 && !strncmp(*argv, "-x", 2)) {
  	argv++, argc--;
! 	encrypt_flag++;
  	goto another;
      }
      if (argc > 0 && !strncmp(*argv, "-f", 2)) {
--- 210,227 ----
       * Ignore -x from kerberos rlogin
       */
      if (argc > 0 && !strncmp(*argv, "-x", 2)) {
+ #ifdef NOENCRYPTION
+ 	fprintf(stderr, "rsh: encryption not supported\n");
+ 	goto usage;
+ #else /* NOENCRYPTION */
+ 	argv++, argc--;
+ 	encrypt_option_flag = 1;
+ 	goto another;
+ #endif /* NOENCRYPTION */
+     }
+     if (argc > 0 && !strncmp(*argv, "-X", 2)) {
  	argv++, argc--;
! 	encrypt_option_flag = 0;
  	goto another;
      }
      if (argc > 0 && !strncmp(*argv, "-f", 2)) {
***************
*** 225,230 ****
--- 242,252 ----
  	argv++, argc--;
  	goto another;
      }
+     if (argc > 0 && !strncmp(*argv, "-N", 2)) {
+ 	no_forward++;
+ 	argv++, argc--;
+ 	goto another;
+     }
      if (argc > 0 && !strncmp(*argv, "-A", 2)) {
  	argv++, argc--;
  	goto another;
***************
*** 295,300 ****
--- 317,349 ----
  	fprintf(stderr, "who are you?\n");
  	exit(1);
      }
+ #ifdef KERBEROS
+     status = krb5_init_context(&bsd_context);
+     if (status) {
+ 	    com_err(argv[0], status, "while initializing krb5");
+ 	    exit(1);
+     }
+ 
+     {
+ 	krb5_data realm;
+ 	int eflag;
+ 
+ 	if (krb_realm) {
+ 		realm.data = krb_realm;
+ 	} else {
+ 		krb5_get_default_realm(bsd_context, &realm.data);
+ 	}
+ 
+ 	krb5_appdefault_boolean(bsd_context, "rsh", &realm, "encrypt", 0,
+ 				&eflag);
+ 
+ 	encrypt_flag = encrypt_option_flag == -1 ? eflag : encrypt_option_flag;
+ 
+ 	if (! krb_realm)
+ 		krb5_xfree(realm.data);
+     }
+ #endif
+ 
      cc = 0;
      for (ap = argv; *ap; ap++)
        cc += strlen(*ap) + 1;
***************
*** 333,345 ****
      }
  
  #ifdef KERBEROS
-     status = krb5_init_context(&bsd_context);
-     if (status) {
- 	    com_err(argv[0], status, "while initializing krb5");
- 	    exit(1);
-     }
      authopts = AP_OPTS_MUTUAL_REQUIRED;
  
      /* Piggy-back forwarding flags on top of authopts; */
      /* they will be reset in kcmd */
      if (fflag || Fflag)
--- 382,406 ----
      }
  
  #ifdef KERBEROS
      authopts = AP_OPTS_MUTUAL_REQUIRED;
  
+     if (! (fflag || Fflag) && !no_forward) {
+ 	krb5_data realm;
+ 
+ 	if (krb_realm) {
+ 		realm.data = krb_realm;
+ 	} else {
+ 		krb5_get_default_realm(bsd_context, &realm.data);
+ 	}
+ 
+ 	krb5_appdefault_boolean(bsd_context, "rsh", &realm, "forward", 0,
+ 				&fflag);
+ 	krb5_appdefault_boolean(bsd_context, "rsh", &realm, "forwardable", 0,
+ 				&Fflag);
+ 	if (!krb_realm)
+ 		krb5_xfree(realm.data);
+     }
+ 
      /* Piggy-back forwarding flags on top of authopts; */
      /* they will be reset in kcmd */
      if (fflag || Fflag)
***************
*** 527,536 ****
--- 588,604 ----
        (void) kill(pid, SIGKILL);
      exit(0);
    usage:
+ #ifndef NOENCRYPTION
      fprintf(stderr,
  	    "usage: \trsh host [ -l login ] [ -n ] [ -x ] [ -f / -F] command\n");
      fprintf(stderr,
  	    "OR \trsh [ -l login ] [-n ] [ -x ] [ -f / -F ] host command\n");
+ #else /* NOENCRYPTION */
+     fprintf(stderr,
+ 	    "usage: \trsh host [ -l login ] [ -n ] [ -f / -F] command\n");
+     fprintf(stderr,
+ 	    "OR \trsh [ -l login ] [-n ] [ -f / -F ] host command\n");
+ #endif /* NOENCRYPTION */
      exit(1);
  }
  
***************
*** 559,573 ****
       * from arglist.
       *
       * We always want to call the Berkeley rsh as 'host mumble'
       */
!     host = strrchr(argv[0], '/');
!     if (host)
!       host++;
!     else
!       host = argv[0];
!     
!     if (!strcmp(host, "rsh"))
!       argv++;
      
      fprintf(stderr,"trying normal rsh (%s)\n",
  	    UCB_RSH);
--- 627,637 ----
       * from arglist.
       *
       * We always want to call the Berkeley rsh as 'host mumble'
+      *
+      * This is broken!  Always invoke it as "rsh ..."
       */
! 
!     argv[0] = "rsh";
      
      fprintf(stderr,"trying normal rsh (%s)\n",
  	    UCB_RSH);
***************
*** 582,587 ****
--- 646,652 ----
  int nstored = 0;
  char *store_ptr = storage;
  
+ #ifndef NOENCRYPTION
  int des_read(fd, buf, len)
       int fd;
       register char *buf;
***************
*** 686,689 ****
--- 751,755 ----
      }
      else return(len); 
  }
+ #endif /* NOENCRYPTION */
  #endif /* KERBEROS */
Index: appl/bsd/krshd.c
diff -c krb5/appl/bsd/krshd.c:1.1.1.4 krb5/appl/bsd/krshd.c:1.12
*** krb5/appl/bsd/krshd.c:1.1.1.4	Wed May 12 13:20:58 1999
--- krb5/appl/bsd/krshd.c	Wed May 12 14:55:45 1999
***************
*** 71,76 ****
--- 71,77 ----
   */
       
  #define SERVE_NON_KRB     
+ #define LOG_ALL_LOGINS
  #define LOG_REMOTE_REALM
  #define LOG_CMD
       
***************
*** 106,111 ****
--- 107,113 ----
  #include <pwd.h>
  #include <ctype.h>
  #include <string.h>
+ #include <setjmp.h>
       
  #ifdef HAVE_SYS_LABEL_H
  /* only SunOS 4? */
***************
*** 181,186 ****
--- 183,191 ----
  int require_encrypt = 0;
  int do_encrypt = 0;
  int anyport = 0;
+ int retain_ccache = 0;
+ int afs_retain_token = 0;
+ int run_aklog = 0;
  char *kprogdir = KPROGDIR;
  int netf;
  int maxhostlen = 0;
***************
*** 243,248 ****
--- 248,324 ----
  }
  #endif
  
+ typedef krb5_sigtype sigtype;
+ 
+ #ifndef POSIX_SETJMP
+ #undef sigjmp_buf
+ #undef sigsetjmp
+ #undef siglongjmp
+ #define sigjmp_buf      jmp_buf
+ #define sigsetjmp(j,s)  setjmp(j)
+ #define siglongjmp      longjmp
+ #endif
+ 
+ #if !defined(SIGSYS) && defined(__linux__)
+ /* Linux doesn't seem to have SIGSYS */
+ #define SIGSYS	SIGUNUSED
+ #endif
+ 
+ #ifdef POSIX_SIGNALS
+ typedef struct sigaction handler;
+ #define handler_init(H,F)		(sigemptyset(&(H).sa_mask), \
+ 					 (H).sa_flags=0, \
+ 					 (H).sa_handler=(F))
+ #define handler_swap(S,NEW,OLD)		sigaction(S, &NEW, &OLD)
+ #define handler_set(S,OLD)		sigaction(S, &OLD, NULL)
+ #else
+ typedef sigtype (*handler)();
+ #define handler_init(H,F)		((H) = (F))
+ #define handler_swap(S,NEW,OLD)		((OLD) = signal ((S), (NEW)))
+ #define handler_set(S,OLD)		(signal ((S), (OLD)))
+ #endif
+ 
+ #ifdef SETPAG
+ extern setpag(), ktc_ForgetAllTokens();
+ 
+ static int pagflag = 0;
+ 
+ static sigjmp_buf setpag_buf;
+ 
+ static sigtype sigsys()
+ {
+ 	siglongjmp(setpag_buf, 1);
+ }
+ 
+ static int try_afscall(scall)
+ 	int (*scall)();
+ {
+ 	handler sa, osa;
+ 	volatile int retval = 0;
+ 
+ 	(void) &retval;
+ 	handler_init(sa, sigsys);
+ 	handler_swap(SIGSYS, sa, osa);
+ 	if (sigsetjmp(setpag_buf, 1) == 0) {
+ 	    (*scall)();
+ 	    retval = 1;
+ 	}
+ 	handler_set(SIGSYS, osa);
+ 	return retval;
+ }
+ 
+ #define try_setpag()	try_afscall(setpag)
+ #define try_unlog()	try_afscall(ktc_ForgetAllTokens)
+ #endif /* SETPAG */
+ 
+ static void
+ afs_cleanup()
+ {
+ #ifdef SETPAG
+     if (pagflag)
+ 	try_unlog();
+ #endif /* SETPAG */
+ }
  
  int main(argc, argv)
       int argc;
***************
*** 287,292 ****
--- 363,371 ----
  		   error_message(status));
  	    exit(1);
      }
+ 
+     /* Blow away any KRB5CCNAME passed from inetd */
+     unsetenv("KRB5CCNAME");
  #endif
      
      /* Analyze parameters. */
***************
*** 567,572 ****
--- 646,652 ----
      syslog(LOG_INFO ,"Daemon terminated via signal %d.", signumber);
      if (ccache)
  	krb5_cc_destroy(bsd_context, ccache);
+     afs_cleanup();
      exit(0);
  }
  
***************
*** 1124,1130 ****
  	error("Logins currently disabled.\n");
  	goto signout_please;
      }
!     
      /* Log access to account */
      pwd = (struct passwd *) getpwnam(locuser);
      if (pwd && (pwd->pw_uid == 0)) {
--- 1204,1239 ----
  	error("Logins currently disabled.\n");
  	goto signout_please;
      }
! 
! #ifdef HP_EXEMPLAR_KRSHD_HACK
!     /*
!      * BIG HACK ALERT! vwelch@ncsa.uiuc.edu 4/28/98
!      *
!      * As best that I can tell there is a bug in the HP exemplar's
!      * networking code (at least under 10.01) that gets tickled by
!      * the code that handles the second port and/or encryption.
!      * The symptoms of the bug are that it causes krshd to get
!      * confused on the sequence number state and send a TCP RST
!      * every other connection when the same ports are being reused
!      * on both the client and the server (which is what rsh does).
!      * The result is that a rsh will fail every other time with
!      * a "protocol failure in circuit setup error" when rsh'ing to
!      * the exemplar.
!      *
!      * So, what this hack does is work around this bug by (1) turning
!      * off the second port code and (2) disallowing encryption. This
!      * hamstrings kshd, but at least makes it reliable.
!      */
!     /* Disable second port code */
!     port = 0;
! 
!     /* Disallow encryption */
!     if (do_encrypt) {
!       error("Encryption not supported.\n");
!       goto signout_please;
!     }
! #endif /* HP_EXEMPLAR_KRSHD_HACK */
! 
      /* Log access to account */
      pwd = (struct passwd *) getpwnam(locuser);
      if (pwd && (pwd->pw_uid == 0)) {
***************
*** 1161,1167 ****
  #endif
        }
  #endif
!     
      (void) write(2, "", 1);
      
      if (port||do_encrypt) {
--- 1270,1286 ----
  #endif
        }
  #endif
! 
! #ifdef IRIX_PROJECT_INIT
!     /*
!      * Initialize the magical IRIX array session, and the
!      * default project id.
!      */
! 	
!     newarraysess();
!     setprid(getdfltprojuser(locuser));
! #endif /* IRIX_PROJECT_INIT */
!   
      (void) write(2, "", 1);
      
      if (port||do_encrypt) {
***************
*** 1246,1252 ****
  			shutdown(s, 1+1);
  			FD_CLR(pv[0], &readfrom);
  		    } else {
! 			(void) (*des_write)(s, buf, cc);
  		    }
  		}
  		if (FD_ISSET(pw[0], &ready)) {
--- 1365,1372 ----
  			shutdown(s, 1+1);
  			FD_CLR(pv[0], &readfrom);
  		    } else {
! 			if ((*des_write)(s, buf, cc) < 0)
! 			    break;
  		    }
  		}
  		if (FD_ISSET(pw[0], &ready)) {
***************
*** 1257,1263 ****
  			shutdown(f, 1+1);
  			FD_CLR(pw[0], &readfrom);
  		    } else {
! 			(void) (*des_write)(f, buf, cc);
  		    }
  		}
  		if (port&&FD_ISSET(s, &ready)) {
--- 1377,1384 ----
  			shutdown(f, 1+1);
  			FD_CLR(pw[0], &readfrom);
  		    } else {
! 			if ((*des_write)(f, buf, cc) < 0)
! 			    break;
  		    }
  		}
  		if (port&&FD_ISSET(s, &ready)) {
***************
*** 1306,1313 ****
  #endif
  	    /* Finish session in wmtp */
  	    pty_logwtmp(ttyn,"","");
! 	    if (ccache)
  		krb5_cc_destroy(bsd_context, ccache);
  	    exit(0);
  	}
  #if defined(HAVE_SETSID)&&(!defined(ULTRIX))
--- 1427,1436 ----
  #endif
  	    /* Finish session in wmtp */
  	    pty_logwtmp(ttyn,"","");
! 	    if (ccache && ! retain_ccache)
  		krb5_cc_destroy(bsd_context, ccache);
+ 	    if (! afs_retain_token)
+ 		afs_cleanup();
  	    exit(0);
  	}
  #if defined(HAVE_SETSID)&&(!defined(ULTRIX))
***************
*** 1349,1363 ****
        pwd->pw_shell = "/bin/sh";
      (void) close(f);
      (void) setgid((gid_t)pwd->pw_gid);
! #ifndef sgi
      if (getuid() == 0 || getuid() != pwd->pw_uid) {
          /* For testing purposes, we don't call initgroups if we
             already have the right uid, and it is not root.  This is
             because on some systems initgroups outputs an error message
             if not called by root.  */
          initgroups(pwd->pw_name, pwd->pw_gid);
!     }
  #endif
  #ifdef	HAVE_SETLUID
      /*
       * If we're on a system which keeps track of login uids, then
--- 1472,1491 ----
        pwd->pw_shell = "/bin/sh";
      (void) close(f);
      (void) setgid((gid_t)pwd->pw_gid);
! /* #ifndef sgi */
      if (getuid() == 0 || getuid() != pwd->pw_uid) {
          /* For testing purposes, we don't call initgroups if we
             already have the right uid, and it is not root.  This is
             because on some systems initgroups outputs an error message
             if not called by root.  */
          initgroups(pwd->pw_name, pwd->pw_gid);
! #ifdef KERBEROS
! #ifdef SETPAG
! 	    pagflag = try_setpag();
! #endif
  #endif
+     }
+ /* #endif */
  #ifdef	HAVE_SETLUID
      /*
       * If we're on a system which keeps track of login uids, then
***************
*** 1447,1452 ****
--- 1575,1606 ----
      environ = envinit;
      
  #ifdef KERBEROS
+ 
+     /*
+      * Since we have to run aklog as the user, _not_ root, we need to run
+      * it now (if we're supposed to.  Do The Right Thing if run_aklog is
+      * set
+      */
+     if (run_aklog) {
+ 	char *aklog_path;
+ 	struct stat st;
+ 
+ 	krb5_appdefault_string(bsd_context, "rshd",
+ 			       krb5_princ_realm(bsd_context, client),
+ 			       "krb5_aklog_path", KPROGDIR "/aklog",
+ 			       &aklog_path);
+ 		
+ 	/*
+ 	 * Make sure it exists before we try to run it
+ 	 */
+ 		
+ 	if (stat (aklog_path, &st) == 0) {
+ 	    system(aklog_path);
+ 	}
+ 
+ 	free(aklog_path);
+     }
+ 
      /* To make Kerberos rcp work correctly, we must ensure that we
         invoke Kerberos rcp on this end, not normal rcp, even if the
         shell startup files change PATH.  */
***************
*** 1501,1506 ****
--- 1655,1661 ----
    signout_please:
      if (ccache)
  	krb5_cc_destroy(bsd_context, ccache);
+     afs_cleanup();
      ccache = NULL;
      pty_logwtmp(ttyn,"","");
      exit(1);
***************
*** 1800,1808 ****
--- 1955,1965 ----
      if (status = krb5_auth_con_init(bsd_context, &auth_context))
  	return status;
  
+ #ifndef KRB5_MULTIHOMED_FIXES
      if (status = krb5_auth_con_genaddrs(bsd_context, auth_context, netf,
  			KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR))
  	return status;
+ #endif /* !KRB5_MULTIHOMED_FIXES */
  
      status = krb5_auth_con_getrcache(bsd_context, auth_context, &rcache);
      if (status) return status;
***************
*** 1852,1857 ****
--- 2009,2020 ----
  	return status;
      }
  
+ #ifdef KRB5_MULTIHOMED_FIXES
+     if (status = krb5_auth_con_genaddrs(bsd_context, auth_context, netf,
+ 			KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR))
+ 	return status;
+ #endif /* KRB5_MULTIHOMED_FIXES */
+ 
      getstr(netf, locuser, sizeof(locuser), "locuser");
      getstr(netf, cmdbuf, sizeof(cmdbuf), "command");
  
***************
*** 1955,1960 ****
--- 2118,2142 ----
  		  error_message(errno));
  	    exit(1);
  	}
+ 	/*
+ 	 * Check our appdefaults profile entry to see if we're supposed to
+ 	 * run aklog.  If so, then just set "run_aklog" for later; we
+ 	 * need to run aklog as the user, not as root
+ 	 */
+ 	
+ 	krb5_appdefault_boolean(bsd_context, "rshd",
+ 				krb5_princ_realm(bsd_context, client),
+ 				"krb5_run_aklog", 0, &run_aklog);
+ 	
+ 	krb5_appdefault_boolean(bsd_context, "rshd",
+ 				krb5_princ_realm(bsd_context, client),
+ 				"retain_ccache", retain_ccache,
+ 				&retain_ccache);
+ 	
+ 	krb5_appdefault_boolean(bsd_context, "rshd",
+ 				krb5_princ_realm(bsd_context, client),
+ 				"afs_retain_token", afs_retain_token,
+ 				&afs_retain_token);
      }
      krb5_free_ticket(bsd_context, ticket);
      return 0;
***************
*** 2061,2067 ****
       int len;
  {
      unsigned char len_buf[4];
!     
      if (!do_encrypt)
        return(write(fd, buf, len));
      
--- 2243,2250 ----
       int len;
  {
      unsigned char len_buf[4];
!     int rc;
! 
      if (!do_encrypt)
        return(write(fd, buf, len));
      
***************
*** 2083,2090 ****
      len_buf[3] = (len & 0xff);
      (void) write(fd, len_buf, 4);
  
!     if (write(fd, desoutbuf.data, desoutbuf.length) != desoutbuf.length){
! 	syslog(LOG_ERR,"Could not write out all data.");
  	return(-1);
      }
      else return(len);
--- 2266,2276 ----
      len_buf[3] = (len & 0xff);
      (void) write(fd, len_buf, 4);
  
!     rc = write(fd, desoutbuf.data, desoutbuf.length);
!     if (rc != desoutbuf.length){
! 	syslog(LOG_ERR,"Could not write out all data."
! 	       "(wrote %d/%d bytes - errno =  %d).",
! 	       rc, desoutbuf.length, errno);
  	return(-1);
      }
      else return(len);
Index: appl/bsd/login.c
diff -c krb5/appl/bsd/login.c:1.1.1.3 krb5/appl/bsd/login.c:1.22
*** krb5/appl/bsd/login.c:1.1.1.3	Wed May 12 13:21:00 1999
--- krb5/appl/bsd/login.c	Fri Aug 27 19:30:56 1999
***************
*** 39,53 ****
     # use password to get v4 tickets
     krb4_convert = 1
     # use kerberos conversion daemon to get v4 tickets
!    krb_run_aklog = 1
     # attempt to run aklog
     aklog_path = $(prefix)/bin/aklog
!    # where to find it [not yet implemented]
     accept_passwd = 0
     # don't accept plaintext passwords [not yet implemented]
  */
  #define KRB5_GET_TICKETS
  int login_krb5_get_tickets = 1;
  #ifdef KRB5_KRB4_COMPAT
  #define KRB4_GET_TICKETS
  int login_krb4_get_tickets = 0;
--- 39,73 ----
     # use password to get v4 tickets
     krb4_convert = 1
     # use kerberos conversion daemon to get v4 tickets
!    krb4_run_aklog = 1
     # attempt to run aklog
     aklog_path = $(prefix)/bin/aklog
!    # where to find it
     accept_passwd = 0
     # don't accept plaintext passwords [not yet implemented]
+    forwardable = 0
+    # The initial TGT is forwardable
+    krb5_run_aklog = 0
+    # Run a Kerberos 5 aklog (doesn't need Kerberos 4 credentials)
+    krb5_aklog_path = $(prefix)/bin/aklog
+    # Path to Kerberos 5 aklog
+    default_lifetime = (null)
+    # Default ticket lifetime (10 hours)
+    retain_ccache = 0
+    # Don't destroy the credential cache upon logout
+    afs_retain_token = 0
+    # Don't destroy AFS tokens upon logout
+    check_quota = 1
+    # Run "quota" to check the user's disk quota
  */
  #define KRB5_GET_TICKETS
  int login_krb5_get_tickets = 1;
+ int login_krb5_forwardable_tgt = 0;
+ int login_krb5_run_aklog = 0;
+ int login_krb5_retain_ccache = 0;
+ char *login_krb5_aklog_path = 0;
+ char *login_krb5_default_lifetime = 0;
+ int login_afs_retain_token = 0;
  #ifdef KRB5_KRB4_COMPAT
  #define KRB4_GET_TICKETS
  int login_krb4_get_tickets = 0;
***************
*** 57,62 ****
--- 77,83 ----
  int login_krb_run_aklog = 0;
  #endif /* KRB5_KRB4_COMPAT */
  int login_accept_passwd = 0;
+ int login_check_quota = 1;
  
  /*
   * login [ name ]
***************
*** 106,111 ****
--- 127,136 ----
  #include <lastlog.h>
  #endif
  
+ #ifdef HAVE_SYS_CAPABILITY_H
+ #include <sys/capability.h>
+ #endif
+ 
  #ifdef linux
  /* linux has V* but not C* in headers. Perhaps we shouldn't be
   * initializing these values anyway -- tcgetattr *should* give
***************
*** 113,118 ****
--- 138,150 ----
  #define NO_INIT_CC
  #endif
  
+ #ifdef sun
+ /* Under solaris: gcc defines __svr4__, cc doesn't define bsd */
+ #if defined(__svr4__) || !defined(bsd)
+ #define solaris
+ #endif /* __svr4 || !bsd */
+ #endif /* sun */
+ 
  #include <errno.h>
  #ifdef HAVE_TTYENT_H
  #include <ttyent.h>
***************
*** 133,138 ****
--- 165,175 ----
  #define siglongjmp	longjmp
  #endif
  
+ #if !defined(SIGSYS) && defined(__linux__)
+ /* Linux doesn't seem to have SIGSYS */
+ #define SIGSYS	SIGUNUSED
+ #endif
+ 
  #ifdef POSIX_SIGNALS
  typedef struct sigaction handler;
  #define handler_init(H,F)		(sigemptyset(&(H).sa_mask), \
***************
*** 152,157 ****
--- 189,213 ----
  #include <shadow.h>
  #endif
  
+ #ifdef HAVE_PRPASSWD
+ /*
+  * HPUX's protected (e.g. shadow) password database
+  * Note that the protected password database might exist, but
+  * be unused and have empty password fields! So if the password
+  * field in the protected password database is empty, fall back
+  * to the password field in the normal database.
+  */
+ #include <sys/types.h>
+ #include <hpsecurity.h>
+ /*
+  * Argh - this sucks. We need to include "/usr/include/prot.h" but
+  * specifying <prot.h> gets us kerberosIV/prot.h, so we have to use
+  * the full path name.
+  */
+ #include "/usr/include/prot.h"
+ 
+ #endif
+ 
  #ifdef KRB5_GET_TICKETS
  /* #include "krb5.h" */
  /* need k5-int.h to get ->profile from krb5_context */
***************
*** 234,239 ****
--- 290,299 ----
  #define TAB3 0
  #endif
  
+ #ifdef solaris
+ #include <dirent.h>
+ #endif /* solaris */
+ 
  #define	TTYGRPNAME	"tty"		/* name of group to own ttys */
  
  #if defined(_PATH_MAILDIR)
***************
*** 263,268 ****
--- 323,334 ----
  
  #define	MOTDFILE	"/etc/motd"
  #define	HUSHLOGIN	".hushlogin"
+ #ifdef HAVE_VAR_ADM_LASTLOG
+ #define	LASTLOG		"/var/adm/lastlog"
+ #else /* HAVE_VAR_ADM_LASTLOG */
+ #define	LASTLOG		"/usr/adm/lastlog"
+ #endif /* HAVE_VAR_ADM_LASTLOG */
+ #define	BSHELL		"/bin/sh"
  
  #if !defined(OQUOTA) && !defined(QUOTAWARN)
  #define QUOTAWARN	"/usr/ucb/quota" /* warn user about quotas */
***************
*** 306,322 ****
  					   passsword */
  #endif
  
! #ifdef __SVR4
  #define NO_MOTD
  #define NO_MAILCHECK
  #endif
  
  char *getenv();
  void dofork();
  
  int doremotelogin(), do_krb_login(), rootterm();
  void lgetstr(), getloginname(), checknologin(), sleepexit();
  void dolastlog(), motd(), check_mail();
  
  #ifndef HAVE_STRSAVE
  char * strsave();
--- 372,394 ----
  					   passsword */
  #endif
  
! #if defined(__SVR4) || defined(sgi) || defined(__svr4__) || defined(__hpux)
  #define NO_MOTD
  #define NO_MAILCHECK
  #endif
  
+ #ifdef USE_LOGIN_CONF
+ static char *get_login_conf();
+ static char **read_login_confs();
+ #endif /* USE_LOGIN_CONF */
+ 
  char *getenv();
  void dofork();
  
  int doremotelogin(), do_krb_login(), rootterm();
  void lgetstr(), getloginname(), checknologin(), sleepexit();
  void dolastlog(), motd(), check_mail();
+ void print_issue();
  
  #ifndef HAVE_STRSAVE
  char * strsave();
***************
*** 347,352 ****
--- 419,429 ----
  	"krb4_convert", &login_krb4_convert,
  	"krb4_run_aklog", &login_krb_run_aklog,
  #endif /* KRB5_KRB4_COMPAT */
+ 	"forwardable", &login_krb5_forwardable_tgt,
+ 	"krb5_run_aklog", &login_krb5_run_aklog,
+ 	"retain_ccache", &login_krb5_retain_ccache,
+ 	"afs_retain_token", &login_afs_retain_token,
+ 	"check_quota", &login_check_quota,
  };
  static char *conf_yes[] = {
  	"y", "yes", "true", "t", "1", "on",
***************
*** 356,361 ****
--- 433,446 ----
  	"n", "no", "false", "nil", "0", "off",
  	0
  };
+ 
+ static struct login_conf_strings {
+ 	char *confname;
+ 	char **varname;
+ } login_string_set[] = {
+ 	"krb5_aklog_path",	&login_krb5_aklog_path,
+ 	"default_lifetime",	&login_krb5_default_lifetime,
+ };
  /* 1 = true, 0 = false, -1 = ambiguous */
  static int conf_affirmative(s)
  	char *s;
***************
*** 388,423 ****
  	krb5_context k;
  {
  	int i, max_i;
- 	const char* kconf_names[3];
- 	char **kconf_val;
  	int retval;
  
  	max_i = sizeof(login_conf_set)/sizeof(struct login_confs);
  	for (i = 0; i<max_i; i++) {
! 		kconf_names[0] = "login";
! 		kconf_names[1] = login_conf_set[i].flagname;
! 		kconf_names[2] = 0;
! 		retval = profile_get_values(k->profile, 
! 					    kconf_names, &kconf_val);
! 		if (retval) {
! 		  /* ignore most (all?) errors */
! 		} else if (kconf_val) {
! 			switch(conf_affirmative(*kconf_val)) {
! 			case 1:
! 				*login_conf_set[i].flag = 1;
! 				break;
! 			case 0:
! 				*login_conf_set[i].flag = 0;
! 				break;
! 			default:
! 			case -1:
! 				com_err("login/kconf", 0,
! 					"invalid flag value %s for flag %s",
! 					*kconf_val, kconf_names[1]);
! 				break;
! 			}
  		}
  	}
  }
  #endif /* KRB5_GET_TICKETS */
  
--- 473,503 ----
  	krb5_context k;
  {
  	int i, max_i;
  	int retval;
+ 	krb5_data realm;
+ 
+ 	krb5_get_default_realm(k, &realm.data);
  
  	max_i = sizeof(login_conf_set)/sizeof(struct login_confs);
  	for (i = 0; i<max_i; i++) {
! 		krb5_appdefault_boolean(k, "login", &realm,
! 					login_conf_set[i].flagname,
! 					*login_conf_set[i].flag,
! 					login_conf_set[i].flag);
! 	}
! 
! 	max_i = sizeof(login_string_set) / sizeof(struct login_conf_strings);
! 	for (i = 0; i < max_i; i++) {
! 		krb5_appdefault_string(k, "login", &realm,
! 				       login_string_set[i].confname,
! 				       "", login_string_set[i].varname);
! 		if (!login_string_set[i].varname[0]) {
! 			free(login_string_set[i].varname);
! 			login_string_set[i].varname = NULL;
  		}
  	}
+ 
+ 	free(realm.data);
  }
  #endif /* KRB5_GET_TICKETS */
  
***************
*** 431,436 ****
--- 511,520 ----
  struct spwd *spwd;
  #endif
  
+ #ifdef HAVE_PRPASSWD
+ struct pr_passwd *prpwd = NULL;
+ #endif
+ 
  void lookup_user (name)
      char *name;
  {
***************
*** 441,450 ****
--- 525,548 ----
      if (spwd)
  	salt = spwd->sp_pwdp;
  #endif
+ #ifdef HAVE_PRPASSWD
+     prpwd = getprpwnam(name);
+     if (prpwd && (prpwd->ufld.fd_encrypt[0] != 0))
+ 	salt = prpwd->ufld.fd_encrypt;
+ #endif
  }
  
  int unix_needs_passwd ()
  {
+ #ifdef HAVE_PRPASSWD
+     /*
+      * If the password field in the protected password database
+      * is empty, there still might be a password in the normal
+      * password database, so fall through.
+      */
+     if (prpwd && (prpwd->ufld.fd_encrypt[0] != 0))
+ 	return 1;
+ #endif
  #ifdef HAVE_SHADOW
      if (spwd)
  	return spwd->sp_pwdp[0] != 0;
***************
*** 462,467 ****
--- 560,574 ----
  
      assert (pwd != 0);
  
+ #ifdef HAVE_PRPASSWD
+     /*
+      * If the protected password field is empty, fall through
+      * and use the password inthe normal password database.
+      */
+     if (prpwd && (prpwd->ufld.fd_encrypt[0] != 0))
+ 	return prpasswd_ok(pass, salt, prpwd);
+ #endif
+ 
      /* copy the first 8 chars of the password for unix crypt */
      strncpy(user_pwcopy, pass, sizeof(user_pwcopy));
      user_pwcopy[sizeof(user_pwcopy) - 1]='\0';
***************
*** 548,553 ****
--- 655,667 ----
      sprintf(prompt,"Password for %s: ", username);
  
      /* reduce opportunities to be swapped out */
+ #ifdef sgi
+     /*
+      * A bug on IRIX will occasionally eat the first character.  Write
+      * a NUl to fix this
+      */
+     putchar('\0');
+ #endif
      code = krb5_read_password(kcontext, prompt, 0, user_pwstring, &pwsize);
      if (code || pwsize == 0) {
  	fprintf(stderr, "Error while reading password for '%s'\n", username);
***************
*** 575,580 ****
--- 689,696 ----
      krb5_creds my_creds;
      krb5_timestamp now;
      krb5_deltat lifetime = krb5_ticket_lifetime;
+     krb5_kdc_rep *kdc_rep = 0;
+     krb5_last_req_entry **last_req;
  
      /* set up credential cache -- obeying KRB5_ENV_CCNAME 
         set earlier */
***************
*** 620,635 ****
  		"while getting time of day");
  	goto nuke_ccache;
      }
      my_creds.times.starttime = 0; /* start timer when 
  				     request gets to KDC */
      my_creds.times.endtime = now + lifetime;
      my_creds.times.renew_till = 0;
  
      code = krb5_get_in_tkt_with_password(kcontext, krb5_options,
  					 0, NULL, 0 /*preauth*/,
  					 pass,
  					 ccache,
! 					 &my_creds, 0);
  
      if (code) {
  	if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
--- 736,765 ----
  		"while getting time of day");
  	goto nuke_ccache;
      }
+ 
+     /*
+      * Use the lifetime from the profile if we were given one
+      */
+ 
+     if (login_krb5_default_lifetime && *login_krb5_default_lifetime) {
+        krb5_deltat tmplife;
+        if (! krb5_string_to_deltat(login_krb5_default_lifetime, &tmplife))
+ 	   lifetime = tmplife;
+     }
+ 
      my_creds.times.starttime = 0; /* start timer when 
  				     request gets to KDC */
      my_creds.times.endtime = now + lifetime;
      my_creds.times.renew_till = 0;
  
+     if (login_krb5_forwardable_tgt)
+ 	krb5_options |= KDC_OPT_FORWARDABLE;
+ 
      code = krb5_get_in_tkt_with_password(kcontext, krb5_options,
  					 0, NULL, 0 /*preauth*/,
  					 pass,
  					 ccache,
! 					 &my_creds, &kdc_rep);
  
      if (code) {
  	if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
***************
*** 648,653 ****
--- 778,820 ----
  	strncpy(ccfile, krb5_cc_get_name(kcontext, ccache), sizeof(ccfile));
  	ccfile[sizeof(ccfile) - 1] = '\0';
  	krbflag = got_v5_tickets = 1;
+ 	/*
+ 	 * Check for upcoming password expiration
+ 	 */
+ 	if (kdc_rep) {
+ 	    if (kdc_rep->enc_part2 && kdc_rep->enc_part2->last_req) {
+ 		for (last_req = kdc_rep->enc_part2->last_req; *last_req;
+ 		     last_req++)
+ 		    if ((*last_req)->lr_type == KRB5_LRQ_PW_EXPTIME) {
+ 			krb5_deltat delta;
+ 			char tempbuf[256];
+ 			float fdelta;
+ 
+ 			delta = (*last_req)->value - now;
+ 
+ 			/*
+ 			 * Different messages for hours and days
+ 			 */
+ 			
+ 			if (delta >= 60*60*24) {
+ 			    fdelta = ((float) delta) / ((float) 60*60*24);
+ 			} else {
+ 			    fdelta = ((float) delta) / ((float) 60*60);
+ 			}
+ 
+ 			if (krb5_timestamp_to_string((*last_req)->value,
+ 						     tempbuf, 256))
+ 			    goto fail_warn;
+ 			
+ 			printf("WARNING: Your password will expire in %.1f %s "
+ 				"on %s.\n", fdelta,
+ 				delta >= 60*60*24 ? "days" : "hours", tempbuf);
+ 		    }
+ 	    }
+ fail_warn:
+ 	    krb5_free_kdc_rep(kcontext, kdc_rep);
+ 	}
+ 
  	return 1;
      }
  }
***************
*** 918,924 ****
--- 1085,1093 ----
         says it is something about the starttime of the ticket and
         "now" being equal.  He thinks it is fixed, but isn't sure.
         */
+ #if 0
      sleep(2);
+ #endif
  
      /* get the server principal for the local host */
      /* (use defaults of "host" and canonicalized local name) */
***************
*** 1079,1096 ****
  #define try_unlog()	try_afscall(ktc_ForgetAllTokens)
  #endif /* SETPAG */
  
  void
! afs_login ()
  {
! #ifdef KRB4_GET_TICKETS
  #ifdef SETPAG
!     if (login_krb4_get_tickets && pwd->pw_uid) {
  	/* Only reset the pag for non-root users. */
  	/* This allows root to become anything. */
  	pagflag = try_setpag ();
      }
! #endif
! #endif /* KRB4_GET_TICKETS */
  #ifdef KRB_RUN_AKLOG
      if (got_v4_tickets && login_krb_run_aklog) {
  	/* KPROGDIR is $(prefix)/bin */
--- 1248,1292 ----
  #define try_unlog()	try_afscall(ktc_ForgetAllTokens)
  #endif /* SETPAG */
  
+ /*
+  * Since we have to allocate a PAG _before_ we fork, we need to move
+  * this into a separate function.
+  */
+ 
  void
! krb_afs_setpag()
  {
! 	/* Allocating a PAG isn't that harmful ... */
  #ifdef SETPAG
! #ifdef SETPAG_ALWAYS
! 	/* Always set a pag, even for root */
! 	pagflag = try_setpag ();
! #else /* SETPAG_ALWAYS */
!     if ( (
! #ifdef KRB4_GET_TICKETS
! 	login_krb4_get_tickets
! #else /* KRB4_GET_TICKETS */
! 	1
! #endif
! 	||
! #ifdef KRB5_GET_TICKETS
! 	login_krb5_get_tickets
! #else
! 	1
! #endif /* KRB5_GET_TICKETS */
! 	) && pwd->pw_uid) {
  	/* Only reset the pag for non-root users. */
  	/* This allows root to become anything. */
  	pagflag = try_setpag ();
      }
! #endif /* SETPAG_ALWAYS */
! #endif /* SETPAG */
! }
! 
! void
! krb_afs_login (me)
! 	krb5_principal me;
! {
  #ifdef KRB_RUN_AKLOG
      if (got_v4_tickets && login_krb_run_aklog) {
  	/* KPROGDIR is $(prefix)/bin */
***************
*** 1104,1115 ****
  	if (stat (aklog_path, &st) == 0) {
  	    system(aklog_path);
  	}
!     }
  #endif /* KRB_RUN_AKLOG */
  }
  
  void
! afs_cleanup ()
  {
  #ifdef SETPAG
      if (pagflag)
--- 1300,1340 ----
  	if (stat (aklog_path, &st) == 0) {
  	    system(aklog_path);
  	}
!     } else
  #endif /* KRB_RUN_AKLOG */
+ #ifdef KRB5_GET_TICKETS
+     /*
+      * Note that we check to see if we have valid credentials already
+      * in place here (because we might have forwarded them)
+      */
+     if (login_krb5_run_aklog && (got_v5_tickets || have_v5_tickets(me))) {
+ 	/*
+ 	 * Check the profile for a path to aklog, otherwise use the
+ 	 * default of KPROGDIR
+ 	 */
+ 	char aklog_path[MAXPATHLEN];
+ 	struct stat st;
+ 
+ 	if (login_krb5_aklog_path && *login_krb5_aklog_path) {
+ 		strcpy(aklog_path, login_krb5_aklog_path);
+ 	} else {
+ 		strcpy(aklog_path, KPROGDIR);
+ 		strcat(aklog_path, "/aklog");
+ 	}
+ 	/*
+ 	 * Make sure it's there
+ 	 */
+ 	if (stat (aklog_path, &st) == 0) {
+ 	    system(aklog_path);
+ 	}
+     }
+ #else
+ 	{ }
+ #endif /* KRB5_GET_TICKETS */
  }
  
  void
! krb_afs_cleanup ()
  {
  #ifdef SETPAG
      if (pagflag)
***************
*** 1235,1247 ****
  	 * -k is used by klogind to cause the Kerberos V4 autologin protocol;
  	 * -K is used by klogind to cause the Kerberos V4 autologin
  	 *    protocol with restricted access.
  	 */
  	(void)gethostname(tbuf, sizeof(tbuf));
  	domain = strchr(tbuf, '.');
  
  	 fflag = hflag = pflag = rflag = kflag = Kflag = eflag = 0;
  	passwd_req = 1;
! 	while ((ch = getopt(argc, argv, "Ffeh:pr:k:K:")) != EOF)
  		switch (ch) {
  		case 'f':
  			EXCL_AUTH_TEST;
--- 1460,1473 ----
  	 * -k is used by klogind to cause the Kerberos V4 autologin protocol;
  	 * -K is used by klogind to cause the Kerberos V4 autologin
  	 *    protocol with restricted access.
+ 	 * -d is used by Solaris to signal the device used; we ignore it.
  	 */
  	(void)gethostname(tbuf, sizeof(tbuf));
  	domain = strchr(tbuf, '.');
  
  	 fflag = hflag = pflag = rflag = kflag = Kflag = eflag = 0;
  	passwd_req = 1;
! 	while ((ch = getopt(argc, argv, "Ffeh:pr:k:K:d:")) != EOF)
  		switch (ch) {
  		case 'f':
  			EXCL_AUTH_TEST;
***************
*** 1324,1329 ****
--- 1550,1557 ----
  			eflag = 1;
  			passwd_req = 0;
  			break;
+ 		case 'd':
+ 			break;
  		case '?':
  		default:
  			fprintf(stderr, "usage: login [-fp] [username]\n");
***************
*** 1388,1393 ****
--- 1616,1624 ----
  	openlog("login", LOG_ODELAY, LOG_AUTH);
  #endif /* 4.2 syslog */
  
+ 	/* print /etc/issue */
+ 	print_issue();
+ 
  /******* begin askpw *******/
  	/* overall:
  	   ask for username if we don't have it already
***************
*** 1396,1402 ****
  	   try and get v4, v5 tickets with it
  	   try and use the tickets against the local srvtab
  	   if the password matches, always let them in
- 	   if the ticket decrypts, let them in.
  	   v5 needs to work, does v4?
  	   */
  
--- 1627,1632 ----
***************
*** 1524,1530 ****
  		    break;
  #endif /* OLD_PASSWD */
  		printf("Login incorrect\n");
! 		if (++cnt >= 5) {
  			log_repeated_failures (tty, hostname);
  /* irix has no tichpcl */
  #ifdef TIOCHPCL
--- 1754,1760 ----
  		    break;
  #endif /* OLD_PASSWD */
  		printf("Login incorrect\n");
! 		if (++cnt >= 2) {
  			log_repeated_failures (tty, hostname);
  /* irix has no tichpcl */
  #ifdef TIOCHPCL
***************
*** 1575,1588 ****
  		sleepexit(0);
  	}
  #endif
- 	if (chdir(pwd->pw_dir) < 0) {
- 		printf("No directory %s!\n", pwd->pw_dir);
- 		if (chdir("/"))
- 			exit(0);
- 		pwd->pw_dir = "/";
- 		printf("Logging in with home = \"/\".\n");
- 	}
- 
  	/* nothing else left to fail -- really log in */
  	{
  		struct utmp utmp;
--- 1805,1810 ----
***************
*** 1601,1606 ****
--- 1823,1833 ----
  		(void)ioctl(0, TIOCSWINSZ, (char *)&win);
  	}
  
+ #if defined(sun)
+ 	/* Set owner/group/permissions of framebuffer devices */
+ 	(void) set_fb_attrs(ttyn, pwd->pw_uid, pwd->pw_gid);
+ #endif
+ 
  	(void)chown(ttyn, pwd->pw_uid,
  	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
  
***************
*** 1623,1633 ****
  
  #if defined(KRB5_GET_TICKETS) || defined(KRB4_GET_TICKETS)
  #if defined(KRB5_GET_TICKETS) && defined(KRB4_GET_TICKETS)
! 	if (login_krb4_get_tickets || login_krb5_get_tickets) {
  #elif defined(KRB4_GET_TICKETS)
  	if (login_krb4_get_tickets) {
  #else
! 	if (login_krb5_get_tickets) {
  #endif
  	    /* Fork so that we can call kdestroy */
  	    dofork();
--- 1850,1862 ----
  
  #if defined(KRB5_GET_TICKETS) || defined(KRB4_GET_TICKETS)
  #if defined(KRB5_GET_TICKETS) && defined(KRB4_GET_TICKETS)
! 	if ((login_krb4_get_tickets || login_krb5_get_tickets) &&
! 	    (login_krb5_retain_ccache == 0 || login_afs_retain_token == 0)) {
  #elif defined(KRB4_GET_TICKETS)
  	if (login_krb4_get_tickets) {
  #else
! 	if (login_krb5_get_tickets &&
! 	    (login_krb5_retain_ccache == 0 || login_afs_retain_token == 0)) {
  #endif
  	    /* Fork so that we can call kdestroy */
  	    dofork();
***************
*** 1646,1657 ****
  
  	   /* this will set the PGID to the PID. */
  #ifdef HAVE_SETPGID
! 	   if (setpgid(p,p) < 0) perror("login.krb5: setpgid");
  #else
  #ifdef SETPGRP_TWOARG
! 	   if (setpgrp(p,p) < 0) perror("login.krb5: setpgrp");
  #else
! 	   if (setpgrp() < 0) perror("login.krb5: setpgrp");
  #endif
  #endif
  
--- 1875,1913 ----
  
  	   /* this will set the PGID to the PID. */
  #ifdef HAVE_SETPGID
! 	   if (setpgid(p,p) < 0) {
! 		/*
! 		 * Ignore errors if we didn't fork, since we're probably
! 		 * already a session leader
! 		 */
! 
! 		if ((login_krb5_retain_ccache == 0) ||
! 		    (login_afs_retain_token == 0))
! 			perror("login.krb5: setpgid");
! 	    }
  #else
  #ifdef SETPGRP_TWOARG
! 	   if (setpgrp(p,p) < 0) {
! 		/*
! 		 * Ignore errors if we didn't fork, since we're probably
! 		 * already a session leader
! 		 */
! 		
! 		if ((login_krb5_retain_ccache == 0) ||
! 		    (login_afs_retain_token == 0))
! 			perror("login.krb5: setpgrp");
! 	   }
  #else
! 	   if (setpgrp() < 0) {
! 		/*
! 		 * Ignore errors if we didn't fork, since we're probably
! 		 * already a session leader
! 		 */
! 		 
! 		if ((login_krb5_retain_ccache == 0) ||
! 		    (login_afs_retain_token == 0))
! 			perror("login.krb5: setpgrp");
! 	   }
  #endif
  #endif
  
***************
*** 1685,1690 ****
--- 1941,1988 ----
  	(void)setgid((gid_t) pwd->pw_gid);
  	(void) initgroups(username, pwd->pw_gid);
  
+ #ifdef IRIX_PROJECT_INIT
+ 	/*
+ 	 * Initialize the magical IRIX array session, and the
+ 	 * default project id.
+ 	 */
+ 	
+ 	newarraysess();
+ 	setprid(getdfltprojuser(username));
+ #endif /* IRIX_PROJECT_INIT */
+ 
+ #ifdef HAS_CAP_SET_PROC
+ 	/*
+ 	 * Initialize process capabilities
+ 	 *
+ 	 * Note that this is currently a hack. We really should read
+ 	 * /etc/capability and set based on it's contents. For now
+ 	 * though we just want to clear the capabilites if we're not
+ 	 * root so users don't run into problems.
+ 	 */
+ 	if (pwd->pw_uid != 0) {
+ 	    cap_set_t cap;
+ 
+ 	    cap.cap_effective = CAP_ALL_OFF;
+ 	    cap.cap_permitted = CAP_ALL_OFF;
+ 	    cap.cap_inheritable = CAP_ALL_OFF;
+ 
+ 	    if (cap_set_proc(&cap) == -1) {
+ 		
+ 		switch(errno) {
+ 		case ENOSYS:
+ 		    /* Function not implemented. Fail silently. */
+ 		    break;
+ 		       
+ 		default:
+ 		    perror("cap_set_proc()");
+ 		}
+ 	    }
+ 	}
+ #endif /* HAS_CAP_SET_PROC */
+ 
+ 	krb_afs_setpag();
+ 
  	/*
  	 * The V5 ccache and V4 ticket file are both created as root.
  	 * They need to be owned by the user, and chown (a) assumes
***************
*** 1875,1881 ****
--- 2173,2196 ----
  	if (ccname)
  		setenv("KRB5CCNAME", ccname, 1);
  
+ 	krb_afs_login (me);
+ 
+ 	if (chdir(pwd->pw_dir) < 0) {
+ 		printf("No directory %s!\n", pwd->pw_dir);
+ 		if (chdir("/")) {
+ 			printf("cannot chdir to /!\n");
+ 			sleepexit(1);
+ 		}
+ 		pwd->pw_dir = "/";
+ 		printf("Logging in with home = \"/\".\n");
+ 	}
+ 
  	setenv("HOME", pwd->pw_dir, 1);
+ #ifdef LPATH_root
+ 	if (pwd->pw_uid == (uid_t) 0)
+ 	    setenv("PATH", LPATH_root, 1);
+ 	else
+ #endif
  	setenv("PATH", LPATH, 1);
  	setenv("USER", pwd->pw_name, 1);
  	setenv("SHELL", pwd->pw_shell, 1);
***************
*** 1942,1949 ****
  #endif /* KRB4_KLOGIN */
  		else
  			syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
! 
! 	afs_login ();
  
  	if (!quietlog) {
  #ifdef KRB4_KLOGIN
--- 2257,2281 ----
  #endif /* KRB4_KLOGIN */
  		else
  			syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
! 	else
! 		if (hostname)
! 			syslog(LOG_INFO, "%s %slogin on %s from %s",
! 			       pwd->pw_name,
! #ifdef LOG_PREAUTH_LOGINS
! 			       fflag ? "preauthenticated " : "password ",
! #else /* LOG_PREAUTH_LOGINS */
! 			       "",
! #endif /* ! LOG_PREAUTH_LOGINS */
! 			       tty, hostname);
! 		else
! 			syslog(LOG_INFO, "%s %slogin on %s",
! 			       pwd->pw_name,
! #ifdef LOG_PREAUTH_LOGINS
! 			       fflag ? "preauthenticated " : "password ",
! #else /* LOG_PREAUTH_LOGINS */
! 			       "",
! #endif /* ! LOG_PREAUTH_LOGINS */
! 			       tty);
  
  	if (!quietlog) {
  #ifdef KRB4_KLOGIN
***************
*** 1955,1961 ****
  	}
  
  #ifndef OQUOTA
! 	if (! access( QUOTAWARN, X_OK)) (void) system(QUOTAWARN);
  #endif
  	handler_init (sa, SIG_DFL);
  	handler_set (SIGALRM, sa);
--- 2287,2294 ----
  	}
  
  #ifndef OQUOTA
! 	if (login_check_quota && ! access( QUOTAWARN, X_OK))
! 	    (void) system(QUOTAWARN);
  #endif
  	handler_init (sa, SIG_DFL);
  	handler_set (SIGALRM, sa);
***************
*** 2123,2130 ****
--- 2456,2492 ----
  	register int ch;
  	register char *p;
  	static char nbuf[UT_NAMESIZE + 1];
+ #ifdef solaris
+ 	char *ttyprompt = NULL;
+ 	static int firsttime = 1;
+ #endif
  
+ #ifdef sgi
+ 	/*
+ 	 * Seems to be a race condition in Irix that sometimes eats the
+ 	 * first character.  Write a null byte to fix this.
+ 	 */
+ 
+ 	putchar('\0');
+ #endif
  	for (;;) {
+ #ifdef solaris
+ 		/*
+ 		 * getty prints 'login:' for us, so we want to avoid printing
+ 		 * it again. getty also sets the environment variable TTYPROMPT
+ 		 * so if it is present, don't print the login prompt.
+ 		 *
+ 		 * However, we only want to do this the first time through.
+ 		 */
+ 		ttyprompt = getenv("TTYPROMPT");
+ 		
+ 		if ((ttyprompt) && (*ttyprompt != '\0')) {
+ 			if (! firsttime)
+ 				printf("%s", ttyprompt);
+ 			else
+ 				firsttime = 0;
+ 		} else
+ #endif /* solaris */
  		printf("login: ");
  		for (p = nbuf; (ch = getchar()) != '\n'; ) {
  			if (ch == EOF)
***************
*** 2157,2168 ****
  int rootterm(tty)
  	char *tty;
  {
  #ifndef HAVE_TTYENT_H
  	return(root_tty_security);
  #else
! 	struct ttyent *t;
  
! 	return((t = getttynam(tty)) && t->ty_status&TTY_SECURE);
  #endif /* HAVE_TTYENT_H */
  }
  
--- 2519,2556 ----
  int rootterm(tty)
  	char *tty;
  {
+ #ifdef USE_LOGIN_CONF
+ 	{
+ 		/*
+ 		 * Check to see if the tty matches the console tty
+ 		 * specified in the login configuration file
+ 		 */
+ 		char *console_tty;
+ 
+ 		console_tty = get_login_conf("CONSOLE");
+ 
+ 		if (console_tty != NULL) {
+ 		  /* Need to remove '/dev/' if it's there */
+ 		  if (strncmp(console_tty, "/dev/", 5) == 0)
+ 			console_tty += 5;
+ 
+ 		  return (strcmp(console_tty, tty) == 0);
+ 		}
+ 	}
+ #endif /* USE_LOGIN_CONF */
+ 
+ #ifdef __linux
+ 	 return check_securetty(tty);
+ #endif __linux
+ 
  #ifndef HAVE_TTYENT_H
  	return(root_tty_security);
  #else
! 	{
! 		struct ttyent *t;
  
! 		return((t = getttynam(tty)) && t->ty_status&TTY_SECURE);
! 	}
  #endif /* HAVE_TTYENT_H */
  }
  
***************
*** 2194,2199 ****
--- 2582,2615 ----
  void motd () { }
  #endif
  
+ #ifdef PRINT_ISSUE
+ sigjmp_buf issue_interrupt;
+ sigtype
+ issue_sigint()
+ {
+ 	siglongjmp(issue_interrupt, 1);
+ }
+ 
+ void print_issue()
+ {
+ 	register int fd, nchars;
+ 	char tbuf[8192];
+ 	handler sa, osa;
+ 
+ 	if ((fd = open(ISSUE_FILE, O_RDONLY, 0)) < 0)
+ 		return;
+ 	handler_init (sa, issue_sigint);
+ 	handler_swap (SIGINT, sa, osa);
+ 	if (sigsetjmp(issue_interrupt, 1) == 0)
+ 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+ 			(void)write(fileno(stdout), tbuf, nchars);
+ 	handler_set (SIGINT, osa);
+ 	(void)close(fd);
+ }
+ #else
+ void print_issue() { }
+ #endif
+ 
  #ifndef NO_MAILCHECK
  void check_mail ()
  {
***************
*** 2484,2491 ****
      
      /* Cleanup stuff */
      /* Run destroy_tickets to destroy tickets */
!     (void) destroy_tickets();		/* If this fails, we lose quietly */
!     afs_cleanup ();
  #ifdef _IBMR2
      update_ref_count(-1);
  #endif
--- 2900,2910 ----
      
      /* Cleanup stuff */
      /* Run destroy_tickets to destroy tickets */
!     if (! login_krb5_retain_ccache)
!         (void) destroy_tickets();	/* If this fails, we lose quietly */
! 
!     if (! login_afs_retain_token)
! 	krb_afs_cleanup();
  #ifdef _IBMR2
      update_ref_count(-1);
  #endif
***************
*** 2546,2548 ****
--- 2965,3359 ----
      enduserdb();
  }
  #endif
+ 
+ #if defined(sun)
+ /*
+  * set_fb_attrs -- change owner/group/permissions of framebuffers
+  *		   listed in /etc/fbtab.
+  *
+  * Note:
+  * Exiting from set_fb_attrs upon error is not advisable
+  * since it would disable logins on console devices.
+  *
+  * File format:
+  * console mode device_name[:device_name ...]
+  * # begins a comment and may appear anywhere on a line.
+  *
+  * Example:
+  * /dev/console 0660 /dev/fb:/dev/cgtwo0:/dev/bwtwo0
+  * /dev/console 0660 /dev/gpone0a:/dev/gpone0b
+  *
+  * Description:
+  * The example above sets the owner/group/permissions of the listed
+  * devices to uid/gid/0660 if ttyn is /dev/console
+  */
+ 
+ #define	FIELD_DELIMS 	" \t\n"
+ #define	COLON 		":"
+ #define COLON_C         ':'
+ #define WILDCARD        "/*"
+ #define WILDCARD_LEN    2
+ #define MAX_LINELEN     256
+ #ifdef solaris
+ #define FBTAB           "/etc/logindevperm"
+ #else /* solaris */
+ #define FBTAB           "/etc/fbtab"
+ #endif /* solaris */
+ 
+ 
+ set_fb_attrs(ttyn, uid, gid)
+ 	char *ttyn;
+ 	int uid;
+ 	int gid;
+ {
+ 	char line[MAX_LINELEN];
+ 	char *console;
+ 	char *mode_str;
+ 	char *dev_list;
+ 	char *device;
+ 	char *ptr;
+ 	int  mode;
+ 	long strtol();
+ 	FILE *fp;
+ 
+ 	if ((fp = fopen(FBTAB, "r")) == NULL)
+ 		return;
+ 	while (fgets(line, MAX_LINELEN, fp)) {
+ 		if (ptr = strchr(line, '#'))
+ 			*ptr = '\0';	/* handle comments */
+ 		if ((console = strtok(line, FIELD_DELIMS)) == NULL)
+ 			continue;	/* ignore blank lines */
+ 		if (strcmp(console, ttyn) != 0)
+ 			continue;	/* ignore non-consoles */
+ 		mode_str = strtok((char *)NULL, FIELD_DELIMS);
+ 		if (mode_str == NULL) {
+ 			(void) fprintf(stderr, "%s: invalid entry -- %s\n",
+ 				FBTAB, line);
+ 			continue;
+ 		}
+ 		/* convert string to octal value */
+ 		mode = (int) strtol(mode_str, (char **)NULL, 8);
+ 		if (mode < 0 || mode > 0777) {
+ 			(void) fprintf(stderr, "%s: invalid mode -- %s\n",
+ 				FBTAB, mode_str);
+ 			continue;
+ 		}
+ 		dev_list = strtok((char *)NULL, FIELD_DELIMS);
+ 		if (dev_list == NULL) {
+ 			(void) fprintf(stderr, "%s: %s -- empty device list\n",
+ 				FBTAB, console);
+ 			continue;
+ 		}
+ #ifdef solaris
+ 		device = strtok(dev_list, COLON);
+ 		while (device) {
+ 		    ptr = strstr(device, WILDCARD);
+ 		    if (ptr && 
+ 			(strlen(device) - (ptr - &device[0])) == WILDCARD_LEN){
+ 			/* The device was a (legally-specified) directory. */
+ 			DIR           *dev_dir;
+ 			struct dirent *dir_e;
+ 			char dev_file[MAXPATHLEN];
+ 			
+ 			*ptr = '\0'; /* Remove the wildcard from the dir name. */
+ 
+ 			if ((dev_dir = opendir(device)) == (DIR *) NULL) {
+ 			    syslog(LOG_ERR, "bad device %s%s in %s, ignored",
+ 				   device, WILDCARD, FBTAB);
+ 			    continue;
+ 			}
+ 			
+ 			/* Directory is open; alter its files. */
+ 			/* Must link with /usr/lib/libc.a before 
+ 			   /usr/ucblib/libucb.a or the d_name structs
+ 			   miss the first two characters of the filename */
+ 			while (dir_e = readdir(dev_dir)) {
+ 			    if (strcmp(dir_e->d_name, "..") &&
+ 				strcmp(dir_e->d_name, ".")) {
+ 				strcpy(dev_file, device);
+ 				strcat(dev_file, "/");
+ 				strcat(dev_file, dir_e->d_name);
+ 
+ 				(void) chown(dev_file, uid, gid);
+ 				(void) chmod(dev_file, mode);
+ 			    }
+ 			}
+ 			(void) closedir(dev_dir);
+ 		    } else {
+ 			/* 'device' was not a directory, so we can just do it. */
+ 			(void) chown(device, uid, gid);
+ 			(void) chmod(device, mode);
+ 		    }
+ 		    device = strtok((char *)NULL, COLON); /* Move thru list. */
+ #else /* solaris */
+ 		device = strtok(dev_list, COLON);
+ 		while (device) {
+ 			(void) chown(device, uid, gid);
+ 			(void) chmod(device, mode);
+ 			device = strtok((char *)NULL, COLON);
+ #endif /* solaris */
+ 		}
+ 	}
+ 	(void) fclose(fp);
+ }
+ #endif /* sun */
+ 
+ 
+ #ifdef USE_LOGIN_CONF
+ 
+ static char *get_login_conf(char *value)
+ {
+ 	static char **login_confs = NULL;
+ 	char **string;
+ 
+ 	if (value == NULL) {
+ 		return NULL;
+ 	}
+ 
+ 	if (login_confs == NULL) {
+ 		login_confs = read_login_confs();
+ 
+ 		if (login_confs == NULL)
+ 			return NULL;
+ 	}
+ 
+ 	for (string = login_confs; *string != NULL; string++) {
+ 		char *s;
+ 
+ 		if (strncmp(value, *string, strlen(value)) != 0)
+ 			continue;
+ 
+ 		s = *string + strlen(value);
+ 
+ 		if (*s != '=')
+ 			continue;
+ 
+ 		s++;
+ 
+ 		return s;
+ 	}
+ 
+ 	return NULL;
+ }
+ 
+ #ifndef LOGIN_CONF_BUFFER_SIZE
+ /*
+  * Size of buffer used to read the login configuration file.
+  * If the file has lines longer than this size, you may
+  * run into problems.
+  */
+ #define LOGIN_CONF_BUFFER_SIZE		256
+ #endif
+ 
+ char **read_login_confs()
+ {
+ 	FILE *fconfs = NULL;
+ 	char **confs = NULL;
+ 	int size = 0;
+ 	int num_confs = 0;
+ 
+ 
+ 	fconfs = fopen(LOGIN_CONF_FILE, "r");
+ 
+ 	if (fconfs == NULL) {
+ 		syslog(LOG_ERR, "Could not open login configuration file %s", 
+ 					 LOGIN_CONF_FILE);
+ 		return NULL;
+ 	}
+ 
+ 	while(!feof(fconfs)) {
+ 		char buffer[LOGIN_CONF_BUFFER_SIZE];
+ 		const char *whitespace = " \t\n";
+ 		char *start;
+ 		char *c;
+ 
+ 		if (fgets(buffer, sizeof(buffer), fconfs) == NULL)
+ 		  break;
+ 
+ 		/* Remove comment */
+ 		c = strchr(buffer, '#');
+ 		if (c != NULL)
+ 			*c = '\0';
+ 
+ 		/* Remove preceding whitespace */
+ 		start = buffer + strspn(buffer, whitespace);
+ 
+ 		/* Remove trailing whitespace */
+ 		c = start + strcspn(start, whitespace);
+ 		*c = '\0';
+ 
+ 		/* If there is anything left add it to our array */
+ 		if (strlen(start) > 0) {
+ 			char *copy;
+ 			
+ 			/*
+ 			 * Make sure there is room on the array for this string
+ 			 * and the NULL terminator
+ 			 */
+ 			if ((num_confs + 1) > size) {
+ 
+ 				size += 10;
+ 
+ 				confs = realloc(confs, size * sizeof(char *));
+ 
+ 				if (!confs) {
+ 					syslog(LOG_ERR, "realloc() failed: %m");
+ 					goto error;
+ 				}
+ 			}
+ 
+ 			copy = strdup(start);
+ 
+ 			if (copy == NULL) {
+ 				syslog(LOG_ERR, "strdup() failed: %m");
+ 				goto error;
+ 			}
+ 
+ 			confs[num_confs] = copy;
+ 
+ 			num_confs++;
+ 
+ 			/* Terminate the list */
+ 			confs[num_confs] = NULL;
+ 		}
+ 	}
+ 
+ 	fclose(fconfs);
+ 	return confs;
+ 
+  error:
+ 	/* An unrecoverable error occurred */
+ 
+ 	fclose(fconfs);
+ 
+ 	if (confs != NULL) {
+ 		char **s;
+ 
+ 		for (s = confs; *s != NULL; s++)
+ 			free(*s);
+ 
+ 		free(confs);
+ 	}
+ 
+ 	return NULL;
+ }
+ 
+ #endif /* USE_LOGIN_CONF */
+ 
+ #ifdef __linux
+ 
+ /*
+  * getttynam() fails under Linux (it always returns 0).
+  * I stole this source below from Linux's login program.
+  *                              - vwelch  4/20/98
+  */
+ #ifndef SECURETTY
+ #define SECURETTY	"/etc/securetty"
+ #endif
+ 
+ /* Return 1 if root is allowed to login on this tty, 0 otherwise  */
+ int check_securetty(char *tty)
+ {
+ 	int fd;
+ 	char buf[100],*p;
+ 	int cnt, more;
+     
+ 	fd = open(SECURETTY, O_RDONLY);
+ 	if(fd < 0) return 1;
+     
+ 	/* read each line in /etc/securetty, if a line matches our ttyline
+ 	   then root is allowed to login on this tty, and we should return
+ 	   true. */
+ 	for(;;) {
+ 		p = buf; cnt = 100;
+ 		while(--cnt >= 0 &&
+ 		      (more = read(fd, p, 1)) == 1 &&
+ 		      *p != '\n') p++;
+ 		if(more && *p == '\n') {
+ 			*p = '\0';
+ 			if(!strcmp(buf, tty)) {
+ 				close(fd);
+ 				return 1;
+ 			} else
+ 				continue;
+ 		} else {
+ 			close(fd);
+ 			return 0;
+ 		}
+ 	}
+ }	
+ 
+ #endif /* __linux */
+ 
+ 
+ #ifdef HAVE_PRPASSWD
+ /*
+  * Check a password under HP-UX's protected password scheme.
+  * This function is complicated because of the encrypted scheme
+  * used. Note that this scheme only matter if the password is
+  * greater than 8 characters, otherwise a plain old crypt()
+  * call works great.
+  */
+ int prpasswd_ok(char *pass, char *salt, struct pr_passwd *prpwd)
+ {
+     int segments;		/* number of segments */
+     int segment;		/* current segment number */
+     int encrypted_size;		/* size of encrypted password */
+     char *ppass;		/* pointer to current segment */
+     char *enc_pass;		/* encrypted password */
+     char *penc_pass;		/* pointer to current encrypted segment */
+     int result = 0;		/* Good password? 1 == yes, 0 == no */
+ 
+ 
+     /* Make sure encrypted password is at least of minimum length */
+     if ( strlen(prpwd->ufld.fd_encrypt) <
+ 	 (AUTH_SALT_SIZE+AUTH_CIPHERTEXT_SEG_CHARS) )
+ 	return 0;
+ 
+     /* Determine number of segments in password */
+     segments = AUTH_SEGMENTS(strlen(pass));
+ 
+     /* Size of the encrypted password */
+     encrypted_size = AUTH_CIPHERTEXT_SIZE(segments);
+ 
+     enc_pass = malloc(encrypted_size);
+ 
+     if (enc_pass == NULL)
+ 	return 0;
+ 
+     /* Copy in the salt */
+     penc_pass = enc_pass;
+     strncpy(penc_pass, salt, AUTH_SALT_SIZE);
+     penc_pass += AUTH_SALT_SIZE;
+ 
+     for (segment = 0, ppass = pass;
+ 	 segment < segments;
+ 	 segment++) {
+ 	
+ 	char *enc_segment;
+ 
+ 	/* Encrypt segment */
+ 	enc_segment = crypt(ppass, salt);
+ 	ppass += AUTH_CLEARTEXT_SEG_CHARS;
+ 
+ 	/* Skip over salt */
+ 	enc_segment += AUTH_SALT_SIZE;
+ 
+ 	/* Set salt for next encrypt to result of this encryption */
+ 	salt = enc_segment;
+ 
+ 	/* And append to encrypted password */
+ 	strncpy(penc_pass, enc_segment, AUTH_CIPHERTEXT_SEG_CHARS);
+ 	penc_pass += AUTH_CIPHERTEXT_SEG_CHARS;
+ 	*penc_pass = '\0';
+     }
+ 
+     result = !strcmp(enc_pass, prpwd->ufld.fd_encrypt);
+     
+     free(enc_pass);
+     
+     return result;
+ }
+ 
+ #endif /* HAVE_PRPASSWD */
+     
Index: appl/bsd/loginpaths.h
diff -c krb5/appl/bsd/loginpaths.h:1.1.1.2 krb5/appl/bsd/loginpaths.h:1.3
*** krb5/appl/bsd/loginpaths.h:1.1.1.2	Wed May 12 13:20:57 1999
--- krb5/appl/bsd/loginpaths.h	Wed May 12 14:55:46 1999
***************
*** 45,52 ****
--- 45,59 ----
  #endif
  
  #ifdef sgi
+ #ifdef HAVE_PATHS_H
+ #include <paths.h>
+ #define LPATH _PATH_USERPATH
+ #define RPATH _PATH_USERPATH
+ #define LPATH_root _PATH_ROOTPATH
+ #else
  #define LPATH "/usr/sbin:/usr/bsd:/usr/bin:/bin:/usr/bin/X11"
  #define RPATH "/usr/sbin:/usr/bsd:/usr/bin:/bin:/usr/bin/X11"
+ #endif
  #endif
  
  #ifdef linux
Index: appl/bsd/rcp.M
diff -c krb5/appl/bsd/rcp.M:1.1.1.1 krb5/appl/bsd/rcp.M:1.2
*** krb5/appl/bsd/rcp.M:1.1.1.1	Mon Jun  2 17:54:13 1997
--- krb5/appl/bsd/rcp.M	Mon Jun 16 16:03:04 1997
***************
*** 23,34 ****
  .SH SYNOPSIS
  .B rcp
  [\fB\-p\fP] [\fB\-x\fP] [\fB\-k\fP \fIrealm\fP ] [\fB\-D\fP \fIport\fP]
! [\fB\-N\fP]
  .I file1 file2
  .sp
  .B rcp
  [\fB\-p\fB] [\fB\-x\fP] [\fP\-k\fP \fIrealm\fP] [\fB\-r\fP] [\fB\-D\fP
! \fIport\fP] [\fB\-N\fP]
  .I file ... directory
  .SH DESCRIPTION
  .B Rcp
--- 23,34 ----
  .SH SYNOPSIS
  .B rcp
  [\fB\-p\fP] [\fB\-x\fP] [\fB\-k\fP \fIrealm\fP ] [\fB\-D\fP \fIport\fP]
! [\fB\-n\fP]
  .I file1 file2
  .sp
  .B rcp
  [\fB\-p\fB] [\fB\-x\fP] [\fP\-k\fP \fIrealm\fP] [\fB\-r\fP] [\fB\-D\fP
! \fIport\fP] [\fB\-n\fP]
  .I file ... directory
  .SH DESCRIPTION
  .B Rcp
***************
*** 98,104 ****
  .I port
  on the remote machine.  
  .TP
! .B \-N
  use a network connection, even when copying files on the local machine
  (used for testing purposes).
  .PP
--- 98,104 ----
  .I port
  on the remote machine.  
  .TP
! .B \-n
  use a network connection, even when copying files on the local machine
  (used for testing purposes).
  .PP
Index: appl/gssftp/ftp/Makefile.in
diff -c krb5/appl/gssftp/ftp/Makefile.in:1.1.1.2 krb5/appl/gssftp/ftp/Makefile.in:1.4
*** krb5/appl/gssftp/ftp/Makefile.in:1.1.1.2	Wed May 12 13:21:04 1999
--- krb5/appl/gssftp/ftp/Makefile.in	Wed May 12 14:55:46 1999
***************
*** 1,16 ****
  #
  # appl/gssftp/ftp/Makefile.in
  #
! CFLAGS = -DGSSAPI -DFTP_BUFSIZ=10240 $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
  
  COMERRLIB=$(BUILDTOP)/util/et/libcom_err.a
  
  SRCS	= cmds.c cmdtab.c domacro.c ftp.c getpass.c glob.c main.c pclose.c \
! 	  radix.c ruserpass.c secure.c 
  
  
  OBJS	= cmds.o cmdtab.o domacro.o ftp.o getpass.o glob.o main.o pclose.o \
! 	  radix.o ruserpass.o secure.o
  
  KLIB = -lgssapi_krb5 -lkrb5 -lcrypto -lcom_err
  DEPKLIB = $(TOPLIBD)/gssapi/libgssapi_krb5.a $(TOPLIBD)/libkrb5.a \
--- 1,16 ----
  #
  # appl/gssftp/ftp/Makefile.in
  #
! CFLAGS = -DGSSAPI -DKERBEROS5 -DFTP_BUFSIZ=10240 $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
  
  COMERRLIB=$(BUILDTOP)/util/et/libcom_err.a
  
  SRCS	= cmds.c cmdtab.c domacro.c ftp.c getpass.c glob.c main.c pclose.c \
! 	  radix.c ruserpass.c secure.c atoll.c
  
  
  OBJS	= cmds.o cmdtab.o domacro.o ftp.o getpass.o glob.o main.o pclose.o \
! 	  radix.o ruserpass.o secure.o atoll.o
  
  KLIB = -lgssapi_krb5 -lkrb5 -lcrypto -lcom_err
  DEPKLIB = $(TOPLIBD)/gssapi/libgssapi_krb5.a $(TOPLIBD)/libkrb5.a \
***************
*** 52,56 ****
--- 52,57 ----
  domacro.o: $(srcdir)/domacro.c
  radix.o: $(srcdir)/radix.c
  secure.o: $(srcdir)/secure.c
+ atoll.o: $(srcdir)/atoll.c
  
  # NOPOSTFIX
Index: appl/gssftp/ftp/atoll.c
diff -c /dev/null krb5/appl/gssftp/ftp/atoll.c:1.1
*** /dev/null	Thu Sep 23 15:40:20 1999
--- krb5/appl/gssftp/ftp/atoll.c	Fri Jan 29 15:08:34 1999
***************
*** 0 ****
--- 1,159 ----
+ /*
+  * 1/11/1999
+  *
+  * Modifications of code taken from the GNU libc version 5.3.12 strtol() and
+  * atol() stdlib functions.
+  */
+ 
+ #ifdef USE_FILE64_FUNCS
+ 
+ #include <ctype.h>
+ #include <errno.h>
+ #ifndef errno
+ extern int errno;
+ #endif
+ 
+ #include <limits.h>
+ #include <stddef.h>
+ #include <stdlib.h>
+ 
+ 
+ long long int
+ strtoq(nptr, endptr, base)
+      const char *nptr;
+      char **endptr;
+      int base;
+ {
+   int negative;
+   register unsigned long long int cutoff;
+   register unsigned int cutlim;
+   register unsigned long long int i;
+   register const char *s;
+   register unsigned char c;
+   const char *save, *end;
+   int overflow;
+ 
+   if (base < 0 || base == 1 || base > 36)
+     base = 10;
+ 
+   save = s = nptr;
+ 
+   /* Skip white space.  */
+   while (isspace (*s))
+     ++s;
+   if (*s == '\0')
+     goto noconv;
+ 
+   /* Check for a sign.  */
+   if (*s == '-')
+     {
+       negative = 1;
+       ++s;
+     }
+   else if (*s == '+')
+     {
+       negative = 0;
+       ++s;
+     }
+   else
+     negative = 0;
+ 
+   if (base == 16 && s[0] == '0' && toupper (s[1]) == 'X')
+     s += 2;
+ 
+   /* If BASE is zero, figure it out ourselves.  */
+   if (base == 0)
+     if (*s == '0')
+       {
+ 	if (toupper (s[1]) == 'X')
+ 	  {
+ 	    s += 2;
+ 	    base = 16;
+ 	  }
+ 	else
+ 	  base = 8;
+       }
+     else
+       base = 10;
+ 
+   /* Save the pointer so we can check later if anything happened.  */
+   save = s;
+ 
+     end = NULL;
+ 
+   cutoff = ULONG_LONG_MAX / (unsigned long long int) base;
+   cutlim = ULONG_LONG_MAX % (unsigned long long int) base;
+ 
+   overflow = 0;
+   i = 0;
+   for (c = *s; c != '\0'; c = *++s)
+     {
+       if (s == end)
+ 	break;
+       if (isdigit (c))
+ 	c -= '0';
+       else if (isalpha (c))
+ 	c = toupper (c) - 'A' + 10;
+       else
+ 	break;
+       if (c >= base)
+ 	break;
+       /* Check for overflow.  */
+       if (i > cutoff || (i == cutoff && c > cutlim))
+ 	overflow = 1;
+       else
+ 	{
+ 	  i *= (unsigned long long int) base;
+ 	  i += c;
+ 	}
+     }
+ 
+   /* Check if anything actually happened.  */
+   if (s == save)
+     goto noconv;
+ 
+   /* Store in ENDPTR the address of one character
+      past the last character we converted.  */
+   if (endptr != NULL)
+     *endptr = (char *) s;
+ 
+   /* Check for a value that is within the range of
+      `unsigned long long int', but outside the range of `long long int'.  */
+   if (i > (negative ?
+ 	   -(unsigned long long int) LONG_LONG_MIN :
+ 		(unsigned long long int) LONG_LONG_MAX))
+     overflow = 1;
+ 
+   if (overflow)
+     {
+       errno = ERANGE;
+       return negative ? LONG_LONG_MIN : LONG_LONG_MAX;
+     }
+ 
+   /* Return the result of the appropriate sign.  */
+   return (negative ? -i : i);
+ 
+ noconv:
+   /* We must handle a special case here: the base is 0 or 16 and the
+      first two characters and '0' and 'x', but the rest are no
+      hexadecimal digits.  This is no error case.  We return 0 and
+      ENDPTR points to the `x`.  */
+   if (endptr != NULL)
+     if (save - nptr >= 2 && tolower (save[-1]) == 'x' && save[-2] == '0')
+       *endptr = (char *) &save[-1];
+     else
+       /*  There was no number to convert.  */
+       *endptr = (char *) nptr;
+ 
+   return 0L;
+ }
+ 
+ 
+ long long int
+ atoll(nptr)
+ 	const char *nptr;
+ {
+   return(strtoq(nptr, (char **) NULL, 10));
+ }
+ 
+ #endif /* USE_FILE64_FUNCS */
Index: appl/gssftp/ftp/cmds.c
diff -c krb5/appl/gssftp/ftp/cmds.c:1.1.1.2 krb5/appl/gssftp/ftp/cmds.c:1.7
*** krb5/appl/gssftp/ftp/cmds.c:1.1.1.2	Wed May 12 13:21:05 1999
--- krb5/appl/gssftp/ftp/cmds.c	Fri Aug 27 19:35:02 1999
***************
*** 38,44 ****
--- 38,49 ----
  /*
   * FTP User Program -- Command Routines.
   */
+ 
+ #ifdef HAVE_STDLIB_H
+ #include <stdlib.h>
+ #endif /* HAVE_STDLIB_H */
  #include <sys/param.h>
+ #include <sys/types.h>
  #include <sys/wait.h>
  #include <sys/stat.h>
  #include <sys/socket.h>
***************
*** 54,59 ****
--- 59,68 ----
  #include <time.h>
  #include <netinet/in.h>
  
+ #ifdef USE_FILE64_FUNCS
+ #include "largefile.h"
+ #endif /* USE_FILE64_FUNCS */
+ 
  #ifdef HAVE_GETCWD
  #define getwd(x) getcwd(x,MAXPATHLEN)
  #endif
***************
*** 594,599 ****
--- 603,637 ----
  	if (loc && mapflag) {
  		argv[2] = domap(argv[2]);
  	}
+ 
+ 	/*
+ 	 * Handle reput; find out the remote file size and set the restart
+ 	 * pointer from that point
+ 	 */
+ 	if (argv[0][0] == 'r') {
+ 		int overbose = verbose;
+ 		if (debug == 0)
+ 			verbose = -1;
+ 		if (command("SIZE %s", argv[2]) == COMPLETE) {
+ #if defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS==64
+ 			if (sscanf(reply_string, "%*s %lld", &restart_point)
+ #else
+ 			if (sscanf(reply_string, "%*s %ld", &restart_point)
+ #endif /* defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS==64 */
+ 								!= 1) {
+ 				printf("Couldn't parse size reply: %s\n",
+ 				       reply_string);
+ 				verbose = overbose;
+ 				return;
+ 			}
+ 		} else {
+ 			printf("%s\n", reply_string);
+ 			verbose = overbose;
+ 			return;
+ 		}
+ 		verbose = overbose;
+ 	}
+ 
  	sendrequest(cmd, argv[1], argv[2],
  	    argv[1] != oldargv1 || argv[2] != oldargv2);
  }
***************
*** 735,741 ****
--- 773,783 ----
  	int argc;
  	char *argv[];
  {
+ #ifdef USE_FILE64_FUNCS
+ 	(void) getit(argc, argv, 0, restart_point ? "r+w" : "wl" );
+ #else /* ! USE_FILE64_FUNCS */
  	(void) getit(argc, argv, 0, restart_point ? "r+w" : "w" );
+ #endif /* ! USE_FILE64_FUNCS */
  }
  
  /*
***************
*** 926,932 ****
--- 968,978 ----
  			if (mapflag) {
  				tp = domap(tp);
  			}
+ #ifdef USE_FILE64_FUNCS
+ 			recvrequest("RETR", tp, cp, "wl",
+ #else /* ! USE_FILE64_FUNCS */
  			recvrequest("RETR", tp, cp, "w",
+ #endif /* ! USE_FILE64_FUNCS */
  			    tp != cp || !interactive);
  			if (!mflag && fromatty) {
  				ointer = interactive;
***************
*** 1414,1424 ****
  	int pid;
  	sig_t old1, old2;
  	char shellnam[40], *shell, *namep; 
! #ifdef WAIT_USES_INT
  	int status;
! #else
  	union wait status;
! #endif
  
  	old1 = signal (SIGINT, SIG_IGN);
  	old2 = signal (SIGQUIT, SIG_IGN);
--- 1460,1470 ----
  	int pid;
  	sig_t old1, old2;
  	char shellnam[40], *shell, *namep; 
! #if defined(WAIT_USES_INT) || defined(USE_FILE64_FUNCS)
  	int status;
! #else /* ! WAIT_USES_INT && ! USE_FILE64_FUNCS */
  	union wait status;
! #endif /* ! WAIT_USES_INT && ! USE_FILE64_FUNCS */
  
  	old1 = signal (SIGINT, SIG_IGN);
  	old2 = signal (SIGQUIT, SIG_IGN);
***************
*** 2186,2197 ****
--- 2232,2252 ----
  	int argc;
  	char *argv[];
  {
+ #ifdef USE_FILE64_FUNCS
+ 	extern long long atoll();
+ #else /* ! USE_FILE64_FUNCS */
  	extern long atol();
+ #endif /* ! USE_FILE64_FUNCS */
  	if (argc != 2)
  		printf("restart: offset not specified\n");
  	else {
+ #if defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS==64
+ 		restart_point = atoll(argv[1]);
+ 		printf("restarting at %lld. %s\n", restart_point,
+ #else /* ! USE_FILE64_FUNCS */
  		restart_point = atol(argv[1]);
  		printf("restarting at %ld. %s\n", restart_point,
+ #endif /* ! USE_FILE64_FUNCS */
  		    "execute get, put or append to initiate transfer");
  	}
  }
***************
*** 2275,2280 ****
--- 2330,2344 ----
  		code = -1;
  		return;
  	}
+ 	/*
+ 	 * It turns out that if you did a directory listing right
+ 	 * before this, the FTP server is still in ASCII mode and may
+ 	 * use a really inefficient method for determining file size
+ 	 * (read in the entire file).  Switch back to the "right" mode
+ 	 * if necessary to fix this.
+ 	 */
+ 
+ 	changetype(type, 0);
  	(void) command("SIZE %s", argv[1]);
  }
  
***************
*** 2329,2334 ****
--- 2393,2446 ----
  			argv[1], argv[2]);
  }
  
+ /*
+  * Set local default tcp buffer size
+  */
+ do_lbufsize(argc, argv)
+ 	int argc;
+ 	char *argv[];
+ {
+ 	int val;
+ 
+ 	if (argc > 2) {
+ 		printf("usage: %s [buffer size]\n", argv[0]);
+ 		code = -1;
+ 		return;
+ 	}
+ 
+ 	if (argc > 1) {
+ 		val = atoi(argv[1]);
+ 		if (val < 0) {
+ 			printf("%s: bad buffer size\n");
+ 			code = -1;
+ 			return;
+ 		}
+ 		lbufsize = val;
+ 		if (lbufsize)
+ 			printf("Set local TCP buffer size to %d bytes\n",
+ 				lbufsize);
+ 		else
+ 			printf("Set local TCP buffer size to system default\n");
+ 	} else {
+ 		if (lbufsize)
+ 			printf("Local TCP buffer size is currently set to "
+ 				"%d bytes\n", lbufsize);
+ 		else
+ 			printf("Using system default TCP buffer size\n");
+ 	}
+ }
+ 
+ /*
+  * Set remote default tcp buffer size
+  */
+ 
+ do_rbufsize(argc, argv)
+ 	int argc;
+ 	char *argv[];
+ {
+ 	(void) command(argc > 1 ? "SITE RBUFSZ %s" : "SITE RBUFSZ" , argv[1]);
+ }
+ 
  #ifndef NO_PASSIVE_MODE
  /*
   * Start up passive mode interaction
***************
*** 2341,2345 ****
--- 2453,2465 ----
  	passivemode = !passivemode;
  	printf("Passive mode %s.\n", onoff(passivemode));
  	code = passivemode;
+ }
+ #endif
+ 
+ #if defined(KERBEROS) || defined(GSSAPI)
+ /* wrapper command for AUTH */
+ auth()
+ {
+ 	do_auth();
  }
  #endif
Index: appl/gssftp/ftp/cmdtab.c
diff -c krb5/appl/gssftp/ftp/cmdtab.c:1.1.1.1 krb5/appl/gssftp/ftp/cmdtab.c:1.4
*** krb5/appl/gssftp/ftp/cmdtab.c:1.1.1.1	Mon Jun  2 17:54:19 1997
--- krb5/appl/gssftp/ftp/cmdtab.c	Fri Aug 27 19:35:03 1999
***************
*** 58,71 ****
  int	account(), doproxy(), reset(), setcase(), setntrans(), setnmap();
  int	setsunique(), setrunique(), cdup(), macdef(), domacro();
  int	sizecmd(), modtime(), newer(), rmtstatus();
! int	do_chmod(), do_umask(), siteidle();
  #ifndef NO_PASSIVE_MODE
  int	setpassive();
  #endif
  
  char	accounthelp[] =	"send account command to remote server";
  char	appendhelp[] =	"append to a file";
  char	asciihelp[] =	"set ascii transfer type";
  char	beephelp[] =	"beep when command completed";
  char	binaryhelp[] =	"set binary transfer type";
  char	casehelp[] =	"toggle mget upper/lower case id mapping";
--- 58,77 ----
  int	account(), doproxy(), reset(), setcase(), setntrans(), setnmap();
  int	setsunique(), setrunique(), cdup(), macdef(), domacro();
  int	sizecmd(), modtime(), newer(), rmtstatus();
! int	do_chmod(), do_umask(), siteidle(), do_lbufsize(), do_rbufsize();
  #ifndef NO_PASSIVE_MODE
  int	setpassive();
  #endif
+ #if defined(KERBEROS) || defined(GSSAPI)
+ int auth();
+ #endif
  
  char	accounthelp[] =	"send account command to remote server";
  char	appendhelp[] =	"append to a file";
  char	asciihelp[] =	"set ascii transfer type";
+ #if defined(KERBEROS) || defined(GSSAPI)
+ char	authhelp[] = "authenticate using kerberos or gssapi";
+ #endif
  char	beephelp[] =	"beep when command completed";
  char	binaryhelp[] =	"set binary transfer type";
  char	casehelp[] =	"toggle mget upper/lower case id mapping";
***************
*** 137,142 ****
--- 143,151 ----
  #ifndef NO_PASSIVE_MODE
  char	setpassivehelp[] = "enter passive transfer mode";
  #endif
+ char	lbufsizehelp[]= "set local tcp buffer size";
+ char	rbufsizehelp[]= "set remote tcp buffer size";
+ char	reputhelp[]=	"put file starting at end of remote file";
  
  struct cmd cmdtab[] = {
  	{ "!",		shellhelp,	0,	0,	0,	shell },
***************
*** 144,149 ****
--- 153,161 ----
  	{ "account",	accounthelp,	0,	1,	1,	account},
  	{ "append",	appendhelp,	1,	1,	1,	put },
  	{ "ascii",	asciihelp,	0,	1,	1,	setascii },
+ #if defined(KERBEROS) || defined(GSSAPI)
+ 	{ "auth",	authhelp,	0,	1,	1,	auth }, 
+ #endif
  	{ "bell",	beephelp,	0,	0,	0,	setbell },
  	{ "binary",	binaryhelp,	0,	1,	1,	setbinary },
  	{ "bye",	quithelp,	0,	0,	0,	quit },
***************
*** 165,170 ****
--- 177,183 ----
  	{ "help",	helphelp,	0,	0,	1,	help },
  	{ "idle",	idlehelp,	0,	1,	1,	siteidle },
  	{ "image",	binaryhelp,	0,	1,	1,	setbinary },
+ 	{ "lbufsize",	lbufsizehelp,	0,	0,	0,	do_lbufsize },
  	{ "lcd",	lcdhelp,	0,	0,	0,	lcd },
  	{ "ls",		lshelp,		1,	1,	1,	ls },
  	{ "macdef",	macdefhelp,	0,	0,	0,	macdef },
***************
*** 195,205 ****
--- 208,220 ----
  	{ "pwd",	pwdhelp,	0,	1,	1,	pwd },
  	{ "quit",	quithelp,	0,	0,	0,	quit },
  	{ "quote",	quotehelp,	1,	1,	1,	quote },
+ 	{ "rbufsize",	rbufsizehelp,	0,	1,	1,	do_rbufsize },
  	{ "recv",	receivehelp,	1,	1,	1,	get },
  	{ "reget",	regethelp,	1,	1,	1,	reget },
  	{ "rstatus",	rmtstatushelp,	0,	1,	1,	rmtstatus },
  	{ "rhelp",	remotehelp,	0,	1,	1,	rmthelp },
  	{ "rename",	renamehelp,	0,	1,	1,	renamefile },
+ 	{ "reput",	reputhelp,	1,	1,	1,	put },
  	{ "reset",	resethelp,	0,	1,	1,	reset },
  	{ "restart",	restarthelp,	1,	1,	1,	restart },
  	{ "rmdir",	rmdirhelp,	0,	1,	1,	removedir },
Index: appl/gssftp/ftp/configure.in
diff -c krb5/appl/gssftp/ftp/configure.in:1.1.1.1 krb5/appl/gssftp/ftp/configure.in:1.3
*** krb5/appl/gssftp/ftp/configure.in:1.1.1.1	Mon Jun  2 17:54:20 1997
--- krb5/appl/gssftp/ftp/configure.in	Fri Jan 22 16:13:16 1999
***************
*** 16,21 ****
--- 16,36 ----
  AC_CHECK_HEADERS(sys/select.h)
  AC_HEADER_CHECK(termios.h,AC_FUNC_CHECK(cfsetispeed,AC_DEFINE(POSIX_TERMIOS)))
  AC_CHECK_HEADERS(stdlib.h)
+ dnl
+ dnl Do we want to exclude session encryption?
+ do_encrypt=yes
+ AC_ARG_WITH([session-encrypt],[],do_encrypt=$withval)
+ if test $do_encrypt = no; then
+ 	AC_DEFINE(NOENCRYPTION)
+ fi
+ dnl
+ dnl Check for special "large file" function calls
+ case $krb5_cv_host in
+     *-*-hpux*)
+         AC_CHECK_HEADERS(sys/cnx_types.h, AC_DEFINE(USE_FILE64_FUNCS))
+         ;;
+ esac
+ dnl
  KRB5_LIBRARIES
  V5_USE_SHARED_LIB
  V5_AC_OUTPUT_MAKEFILE
Index: appl/gssftp/ftp/ftp.M
diff -c krb5/appl/gssftp/ftp/ftp.M:1.1.1.1 krb5/appl/gssftp/ftp/ftp.M:1.3
*** krb5/appl/gssftp/ftp/ftp.M:1.1.1.1	Mon Jun  2 17:54:20 1997
--- krb5/appl/gssftp/ftp/ftp.M	Tue Aug 11 17:36:11 1998
***************
*** 152,157 ****
--- 152,163 ----
  .SM ASCII .
  This is the default type.
  .TP
+ .B auth
+ Uses the
+ .B AUTH/ADAT
+ mechanism (see above) to authenticate the user
+ .SM AUTH
+ .TP
  .B bell
  Arrange that a bell be sounded after each file transfer command is
  completed.
***************
*** 326,331 ****
--- 332,349 ----
  .I seconds
  is omitted, the current inactivity timer is printed.
  .TP
+ \fBlbufsize\fP [\fIbytes\fP]
+ Set the TCP buffer sizes on the local machine to
+ .I bytes
+ bytes. If
+ .I bytes
+ is zero, the TCP buffer sizes are not set; the system default is used. If
+ .I bytes
+ is omitted, the current TCP buffer sizes of the local machine are printed.
+ Usually setting the TCP buffer sizes sets the TCP window size. Use with the
+ .B rbufsize
+ command.
+ .TP
  \fBlcd\fP [\fIdirectory\fP]
  Change the working directory on the local machine.  If no
  .I directory
***************
*** 664,669 ****
--- 682,699 ----
  The arguments specified are sent, verbatim, to the remote
  .SM FTP
  server.
+ .TP
+ \fBrbufsize\fP [\fIbytes\fP]
+ Set the TCP buffer sizes on the remote machine to
+ .I bytes
+ bytes. If
+ .I bytes
+ is zero, the TCP buffer sizes are not set; the system default is used. If
+ .I bytes
+ is omitted, the current TCP buffer sizes of the remote machine are printed.
+ Usually setting the TCP buffer sizes sets the TCP window size. Use with the
+ .B lbufsize
+ command.
  .TP
  \fBrecv\fP \fIremote-file\fP [\fIlocal-file\fP]
  A synonym for get.
Index: appl/gssftp/ftp/ftp.c
diff -c krb5/appl/gssftp/ftp/ftp.c:1.1.1.2 krb5/appl/gssftp/ftp/ftp.c:1.8
*** krb5/appl/gssftp/ftp/ftp.c:1.1.1.2	Wed May 12 13:21:09 1999
--- krb5/appl/gssftp/ftp/ftp.c	Fri Aug 27 19:35:03 1999
***************
*** 57,66 ****
--- 57,72 ----
  #include <stdio.h>
  #include <signal.h>
  #include <string.h>
+ #include <unistd.h>
  #include <errno.h>
  #include <netdb.h>
  #include <fcntl.h>
  #include <pwd.h>
+ 
+ #ifdef USE_FILE64_FUNCS
+ #include "largefile.h"
+ #endif /* USE_FILE64_FUNCS */
+ 
  #ifndef STDARG
  #if (defined(__STDC__) && ! defined(VARARGS)) || defined(HAVE_STDARG_H)
  #define STDARG
***************
*** 705,711 ****
--- 711,721 ----
  
  	t.tv_sec = (long) sec;
  	t.tv_usec = 0;
+ #ifdef USE_FILE64_FUNCS
+ 	return(select(32, (int *) mask, (int *) 0, (int *) 0, &t));
+ #else /* ! USE_FILE64_FUNCS */
  	return(select(32, mask, (fd_set *) 0, (fd_set *) 0, &t));
+ #endif /* ! USE_FILE64_FUNCS */
  }
  
  jmp_buf	sendabort;
***************
*** 748,760 ****
  	char *cmd, *local, *remote;
  	int printnames;
  {
- 	struct stat st;
  	struct timeval start, stop;
  	register int c, d;
  	FILE *fin, *dout = 0, *popen();
  	int (*closefunc)(), pclose(), fclose();
  	sig_t oldintr, oldintp;
! 	long bytes = 0, hashbytes = HASHBYTES;
  	char *lmode, buf[FTP_BUFSIZ], *bufp;
  	sigtype abortsend();
  
--- 758,774 ----
  	char *cmd, *local, *remote;
  	int printnames;
  {
  	struct timeval start, stop;
  	register int c, d;
  	FILE *fin, *dout = 0, *popen();
  	int (*closefunc)(), pclose(), fclose();
  	sig_t oldintr, oldintp;
! #if defined(USE_FILE64_FUNCS)
! 	off64_t bytes = 0LL, hashbytes = (off64_t)HASHBYTES;
! #else
! 	off_t bytes = 0, hashbytes = HASHBYTES;
! #endif /* ! USE_FILE64_FUNCS */
! 	struct stat st;
  	char *lmode, buf[FTP_BUFSIZ], *bufp;
  	sigtype abortsend();
  
***************
*** 804,810 ****
--- 818,828 ----
  		}
  		closefunc = pclose;
  	} else {
+ #ifdef USE_FILE64_FUNCS
+ 		fin = fopen(local, "rl");
+ #else /* ! USE_FILE64_FUNCS */
  		fin = fopen(local, "r");
+ #endif /* ! USE_FILE64_FUNCS */
  		if (fin == NULL) {
  			fprintf(stderr, "local: %s: %s\n", local,
  				strerror(errno));
***************
*** 836,842 ****
  
  	if (restart_point &&
  	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
! 		if (fseek(fin, (long) restart_point, 0) < 0) {
  			fprintf(stderr, "local: %s: %s\n", local,
  				strerror(errno));
  			restart_point = 0;
--- 854,866 ----
  
  	if (restart_point &&
  	    (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
! #ifdef USE_FILE64_FUNCS
! 		if (fseek(fin, (off64_t) restart_point, 0) < 0) {
! #elif _FILE_OFFSET_BITS == 64 /* ! USE_FILE64_FUNCS */
! 		if (fseeko(fin, restart_point, 0) < 0) {
! #else /* ! USE_FILE64_FUNCS && ! (_FILE_OFFSET_BITS == 64) */
! 		if (fseek(fin, (off_t) restart_point, 0) < 0) {
! #endif /* ! USE_FILE64_FUNCS */
  			fprintf(stderr, "local: %s: %s\n", local,
  				strerror(errno));
  			restart_point = 0;
***************
*** 844,850 ****
--- 868,880 ----
  				(*closefunc)(fin);
  			return;
  		}
+ #ifdef USE_FILE64_FUNCS
+ 		if (command("REST %lld", (off64_t) restart_point)
+ #elif _FILE_OFFSET_BITS == 64 /* ! USE_FILE64_FUNCS */
+ 		if (command("REST %lld", (off_t) restart_point)
+ #else
  		if (command("REST %ld", (long) restart_point)
+ #endif /* ! USE_FILE64_FUNCS */
  			!= CONTINUE) {
  			restart_point = 0;
  			if (closefunc != NULL)
***************
*** 1007,1020 ****
  	sig_t oldintr, oldintp;
  	int is_retr, tcrflag, bare_lfs = 0;
  	char *gunique();
- 	static int bufsize;
  	static char *buf;
- 	int blksize;
- 	long bytes = 0, hashbytes = HASHBYTES;
  	register int c, d;
  	struct timeval start, stop;
  	struct stat st;
- 	off_t lseek();
  	sigtype abortrecv();
  
  	is_retr = strcmp(cmd, "RETR") == 0;
--- 1037,1053 ----
  	sig_t oldintr, oldintp;
  	int is_retr, tcrflag, bare_lfs = 0;
  	char *gunique();
  	static char *buf;
  	register int c, d;
  	struct timeval start, stop;
+ 	static int bufsize;
+ 	int blksize;
+ #ifdef USE_FILE64_FUNCS
+ 	off64_t bytes = 0LL, hashbytes = (off64_t)HASHBYTES;
+ #else  /* ! USE_FILE64_FUNCS */
+ 	off_t bytes = 0, hashbytes = HASHBYTES;
+ #endif /* ! USE_FILE64_FUNCS */
  	struct stat st;
  	sigtype abortrecv();
  
  	is_retr = strcmp(cmd, "RETR") == 0;
***************
*** 1104,1110 ****
--- 1137,1149 ----
  	if (setjmp(recvabort))
  		goto abort;
  	if (is_retr && restart_point &&
+ #ifdef USE_FILE64_FUNCS
+ 	    command("REST %lld", (off64_t) restart_point) != CONTINUE)
+ #elif _FILE_OFFSET_BITS==64 /* ! USE_FILE64_FUNCS */
+ 	    command("REST %lld", (off_t) restart_point) != CONTINUE)
+ #else
  	    command("REST %ld", (long) restart_point) != CONTINUE)
+ #endif /* ! USE_FILE64_FUNCS */
  		return;
  	if (remote) {
  		if (command("%s %s", cmd, remote) != PRELIM) {
***************
*** 1161,1167 ****
  	case TYPE_I:
  	case TYPE_L:
  		if (restart_point &&
! 		    lseek(fileno(fout), (long) restart_point, L_SET) < 0) {
  			fprintf(stderr, "local: %s: %s\n", local,
  				strerror(errno));
  			if (closefunc != NULL)
--- 1200,1210 ----
  	case TYPE_I:
  	case TYPE_L:
  		if (restart_point &&
! #ifdef USE_FILE64_FUNCS
! 		    lseek(fileno(fout), (off64_t) restart_point, L_SET) < 0) {
! #else /* ! USE_FILE64_FUNCS */
! 		    lseek(fileno(fout), (off_t) restart_point, L_SET) < 0) {
! #endif /* ! USE_FILE64_FUNCS */
  			fprintf(stderr, "local: %s: %s\n", local,
  				strerror(errno));
  			if (closefunc != NULL)
***************
*** 1333,1338 ****
--- 1376,1387 ----
  		if (options & SO_DEBUG &&
  		    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
  			perror("ftp: setsockopt (ignored)");
+ 		if (lbufsize) {
+ 			if (setsockopt(data, SOL_SOCKET, SO_SNDBUF, (char *)&lbufsize, sizeof(lbufsize)) < 0)
+ 				perror("ftp: setsockopt(SO_SNDBUF) (ignored)");
+ 			if (setsockopt(data, SOL_SOCKET, SO_RCVBUF, (char *)&lbufsize, sizeof(lbufsize)) < 0)
+ 				perror("ftp: setsockopt(SO_RCVBUF) (ignored)");
+ 		}
  		if (command("PASV") != COMPLETE) {
  			printf("Passive mode refused.  Turning off passive mode.\n");
  			passivemode = 0;
***************
*** 1394,1399 ****
--- 1443,1454 ----
  		perror("ftp: bind");
  		goto bad;
  	}
+ 	if (lbufsize) {
+ 		if (setsockopt(data, SOL_SOCKET, SO_SNDBUF, (char *)&lbufsize, sizeof(lbufsize)) < 0)
+ 			perror("ftp: setsockopt(SO_SNDBUF) (ignored)");
+ 		if (setsockopt(data, SOL_SOCKET, SO_RCVBUF, (char *)&lbufsize, sizeof(lbufsize)) < 0)
+ 			perror("ftp: setsockopt(SO_RCVBUF) (ignored)");
+ 	}
  	if (options & SO_DEBUG &&
  	    setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0)
  		perror("ftp: setsockopt (ignored)");
***************
*** 1466,1472 ****
  
  ptransfer(direction, bytes, t0, t1)
  	char *direction;
! 	long bytes;
  	struct timeval *t0, *t1;
  {
  	struct timeval td;
--- 1521,1531 ----
  
  ptransfer(direction, bytes, t0, t1)
  	char *direction;
! #ifdef USE_FILE64_FUNCS
! 	off64_t bytes;
! #else /* ! USE_FILE64_FUNCS */
! 	off_t bytes;
! #endif /* ! USE_FILE64_FUNCS */
  	struct timeval *t0, *t1;
  {
  	struct timeval td;
***************
*** 1477,1483 ****
--- 1536,1546 ----
  		s = td.tv_sec + (td.tv_usec / 1000000.);
  #define	nz(x)	((x) == 0 ? 1 : (x))
  		kbs = (bytes / nz(s))/1024.0;
+ #if defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS==64
+ 		printf("%lld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
+ #else /* ! USE_FILE64_FUNCS */
  		printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
+ #endif /* ! USE_FILE64_FUNCS */
  		    bytes, direction, s, kbs);
  	}
  }
***************
*** 1842,1847 ****
--- 1905,1912 ----
  #if defined(KERBEROS) || defined(GSSAPI)
  	u_char out_buf[FTP_BUFSIZ];
  	int i;
+ 	char realhostname[128];
+ 	struct hostent *hp;
  #endif /* KERBEROS */
  
  	if (auth_type) return(1);	/* auth already succeeded */
***************
*** 1914,1919 ****
--- 1979,1985 ----
  	  char stbuf[FTP_BUFSIZ];
  	  char **service_name, **end_service_name;
  	  int comcode;
+ 	  int noisyflag = 0;
  	  struct gss_channel_bindings_struct chan;
  	  chan.initiator_addrtype = GSS_C_AF_INET; /* OM_uint32  */ 
  	  chan.initiator_address.length = 4;
***************
*** 1924,1929 ****
--- 1990,2009 ----
  	  chan.application_data.length = 0;
  	  chan.application_data.value = 0;
  
+  	  /*
+  	  **  Look up actual host name, from connection IP.
+  	  **  Since gss_import_name() -> krb5_sname_to_principal()
+  	  **  will arrive at an actual name anyway, this is not a
+  	  **  question of whether we want the cluster name or the
+  	  **  actual name, but whether we want the actual name to
+  	  **  be the correct one.
+  	  */
+  	  hp = gethostbyaddr(&hisctladdr.sin_addr, 4, AF_INET);
+  	  if (hp)
+  	    strncpy(realhostname, hp->h_name, sizeof(realhostname));
+  	  else
+  	    strncpy(realhostname, hostname, sizeof(realhostname));
+  
  	  for (end_service_name = gss_services; *end_service_name; )
  	    end_service_name++;
  	  end_service_name--;
***************
*** 1935,1944 ****
  	    
  	  
  	  for (service_name = gss_services; *service_name; service_name++) {
  	    
  	    /* ftp@hostname first, the host@hostname */
  	    /* the V5 GSSAPI binding canonicalizes this for us... */
! 	    sprintf(stbuf, "%s@%s", *service_name, hostname);
  	    if (debug)
  	      fprintf(stderr, "Trying to authenticate to <%s>\n", stbuf);
  
--- 2015,2025 ----
  	    
  	  
  	  for (service_name = gss_services; *service_name; service_name++) {
+ 	    noisyflag = debug || (service_name == end_service_name);
  	    
  	    /* ftp@hostname first, the host@hostname */
  	    /* the V5 GSSAPI binding canonicalizes this for us... */
! 	    sprintf(stbuf, "%s@%s", *service_name, realhostname);
  	    if (debug)
  	      fprintf(stderr, "Trying to authenticate to <%s>\n", stbuf);
  
***************
*** 1965,1971 ****
  				     &gcontext,
  				     target_name,
  				     GSS_C_NULL_OID,
! 				     GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
  				     0,
  				     &chan,	/* channel bindings */
  				     token_ptr,
--- 2046,2053 ----
  				     &gcontext,
  				     target_name,
  				     GSS_C_NULL_OID,
! 				     GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
! 				     (forward ? GSS_C_DELEG_FLAG : 0),
  				     0,
  				     &chan,	/* channel bindings */
  				     token_ptr,
***************
*** 1976,1982 ****
  	      
  
  	      if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED){
! 		user_gss_error(maj_stat, min_stat, "initializing context");
  		(void) gss_release_name(&min_stat, &target_name);
  		/* could just be that we missed on the service name */
  		goto outer_loop;
--- 2058,2065 ----
  	      
  
  	      if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED){
! 		if (!(maj_stat == GSS_S_FAILURE) || noisyflag)
! 		  user_gss_error(maj_stat, min_stat, "initializing context");
  		(void) gss_release_name(&min_stat, &target_name);
  		/* could just be that we missed on the service name */
  		goto outer_loop;
Index: appl/gssftp/ftp/ftp_var.h
diff -c krb5/appl/gssftp/ftp/ftp_var.h:1.1.1.1 krb5/appl/gssftp/ftp/ftp_var.h:1.3
*** krb5/appl/gssftp/ftp/ftp_var.h:1.1.1.1	Mon Jun  2 17:54:20 1997
--- krb5/appl/gssftp/ftp/ftp_var.h	Thu Mar 19 11:09:59 1998
***************
*** 102,107 ****
--- 102,112 ----
  extern int	mflag;		/* flag: if != 0, then active multi command */
  
  extern int	options;	/* used during socket creation */
+ extern int	lbufsize;	/* default local buffer size */
+ 
+ #ifdef KERBEROS5
+ extern int	forward;	/* Should we forward credentials? */
+ #endif
  
  /*
   * Format of command table.
Index: appl/gssftp/ftp/glob.c
diff -c krb5/appl/gssftp/ftp/glob.c:1.1.1.2 krb5/appl/gssftp/ftp/glob.c:1.4
*** krb5/appl/gssftp/ftp/glob.c:1.1.1.2	Wed May 12 13:21:09 1999
--- krb5/appl/gssftp/ftp/glob.c	Wed May 12 14:55:48 1999
***************
*** 62,67 ****
--- 62,71 ----
  #define NCARGS 4096
  #endif
  
+ #ifdef USE_FILE64_FUNCS
+ #include "largefile.h"
+ #endif /* USE_FILE64_FUNCS */
+ 
  #define	QUOTE 0200
  #define	TRIM 0177
  #define	eq(a,b)		(strcmp(a, b)==0)
Index: appl/gssftp/ftp/largefile.h
diff -c /dev/null krb5/appl/gssftp/ftp/largefile.h:1.1
*** /dev/null	Thu Sep 23 15:40:22 1999
--- krb5/appl/gssftp/ftp/largefile.h	Fri Feb  5 16:15:48 1999
***************
*** 0 ****
--- 1,22 ----
+ /*
+  * This header file contains functions and definitions for platforms
+  * (i.e. SPP-UX) that require separate facilities for accessing large
+  * files (64 bit)
+  */
+ 
+ #include <sys/cnx_types.h>
+ #include <sys/cnx_stat.h>
+ #include <sys/cnx_unistd.h>
+ 
+ #undef off_t
+ #define off_t off64_t
+ #undef stat()
+ #define stat(f, b) stat64(f, b)
+ #undef fstat()
+ #define fstat(f, b) fstat64(f, b)
+ #undef fseek()
+ #define fseek(s, o, w) fseek64(s, o, w)
+ #undef lseek()
+ #define lseek(f, o, w) lseek64(f, o, w)
+ #undef stat
+ #define stat stat64
Index: appl/gssftp/ftp/main.c
diff -c krb5/appl/gssftp/ftp/main.c:1.1.1.1 krb5/appl/gssftp/ftp/main.c:1.4
*** krb5/appl/gssftp/ftp/main.c:1.1.1.1	Mon Jun  2 17:54:20 1997
--- krb5/appl/gssftp/ftp/main.c	Thu Mar 19 11:10:00 1998
***************
*** 46,54 ****
   */
  #include <stdio.h>
  #include "ftp_var.h"
  #include <sys/socket.h>
  #include <sys/ioctl.h>
- #include <sys/types.h>
  
  #include <arpa/ftp.h>
  
--- 46,54 ----
   */
  #include <stdio.h>
  #include "ftp_var.h"
+ #include <sys/types.h>
  #include <sys/socket.h>
  #include <sys/ioctl.h>
  
  #include <arpa/ftp.h>
  
***************
*** 73,78 ****
--- 73,83 ----
  extern char realm[];
  #endif /* KERBEROS */
  
+ #ifdef KERBEROS5
+ #include <krb5.h>
+ #include <com_err.h>
+ #endif
+ 
  main(argc, argv)
  	char *argv[];
  {
***************
*** 80,85 ****
--- 85,96 ----
  	int top;
  	struct passwd *pw = NULL;
  	char homedir[MAXPATHLEN];
+ #ifdef KERBEROS5
+ 	krb5_context context;
+ 	krb5_ccache ccache;
+ 	krb5_error_code code = 0;
+ 	krb5_principal princ = NULL;
+ #endif
  
  	sp = getservbyname("ftp", "tcp");
  	if (sp == 0) {
***************
*** 92,97 ****
--- 103,135 ----
  	memcpy(&staticsp,sp,sizeof(struct servent));
  	sp = &staticsp;
  #endif /* KERBEROS */
+ 
+ #ifdef KERBEROS5
+ 	krb5_init_context(&context);
+ 	krb5_init_ets(context);
+ 
+ 	/*
+ 	 * Forward credentials if we get a command-line flag or if we
+ 	 * have the right stuff set in the profile, _AND_ if our TGT
+ 	 * is forwardable
+ 	 */
+ 
+ 	if ((code = krb5_cc_default(context, &ccache)) != 0) {
+ 		com_err(argv[0], code, "while reading credential cache");
+ 	}
+ 
+ 	if ((code == 0) && 
+ 	    (code = krb5_cc_get_principal(context, ccache, &princ)) != 0) {
+ 		com_err(argv[0], code, "while getting primary principal");
+ 	}
+ 
+ 	if (code == 0) {
+ 		krb5_appdefault_boolean(context, "ftp",
+ 					krb5_princ_realm(context, princ),
+ 					"forward", 0, &forward);
+ 	}
+ #endif /* KERBEROS5 */
+ 
  	doglob = 1;
  	interactive = 1;
  	autologin = 1;
***************
*** 137,142 ****
--- 175,189 ----
  			case 'g':
  				doglob = 0;
  				break;
+ #ifdef KERBEROS5
+ 			case 'f':
+ 				forward = 1;
+ 				break;
+ 			
+ 			case 'F':
+ 				forward = 0;
+ 				break;
+ #endif /* KERBEROS5 */
  
  			default:
  				fprintf(stdout,
***************
*** 146,151 ****
--- 193,244 ----
  	nextopt:
  		argc--, argv++;
  	}
+ 
+ #ifdef KERBEROS5
+ 
+ 	if (code != 0)
+ 		forward = 0;
+ 
+ 	if (forward) {
+ 		krb5_creds creds, mcreds;
+ 
+ 		creds.client = princ;
+ 		code = krb5_build_principal(context, &creds.server,
+ 					    krb5_princ_realm(context, princ)->length,
+ 					    krb5_princ_realm(context, princ)->data,
+ 					    "krbtgt",
+ 					    krb5_princ_realm(context, princ)->data, 0);
+ 		
+ 		if (code != 0) {
+ 			com_err(argv[0], code, "while building TGT principal");
+ 			forward = 0;
+ 		}
+ 
+ 		if (code == 0)
+ 			code = krb5_cc_retrieve_cred(context, ccache, 0,
+ 						     &creds, &mcreds);
+ 		
+ 		if (code == 0) {
+ 			krb5_free_principal(context, creds.server);
+ 
+ 			if ((mcreds.ticket_flags & TKT_FLG_FORWARDABLE) == 0)
+ 				forward = 0;
+ 			
+ 			krb5_free_cred_contents(context, &mcreds);
+ 		}
+ 
+ 		if (code != 0)
+ 			forward = 0;
+ 	}
+ 
+ 	krb5_cc_close(context, ccache);
+ 
+ 	if (princ)
+ 		krb5_free_principal(context, princ);
+ 	krb5_free_context(context);
+ 
+ #endif /* KERBEROS5 */
+ 
  	fromatty = isatty(fileno(stdin));
  	if (fromatty)
  		verbose++;
***************
*** 156,161 ****
--- 249,255 ----
  #endif
  	crflag = 1;	/* strip c.r. on ascii gets */
  	sendport = -1;	/* not using ports */
+ 	lbufsize = 0;	/* take the default buffer size */
  	/*
  	 * Set up the home directory in case we're globbing.
  	 */
Index: appl/gssftp/ftp/ruserpass.c
diff -c krb5/appl/gssftp/ftp/ruserpass.c:1.1.1.1 krb5/appl/gssftp/ftp/ruserpass.c:1.2
*** krb5/appl/gssftp/ftp/ruserpass.c:1.1.1.1	Mon Jun  2 17:54:21 1997
--- krb5/appl/gssftp/ftp/ruserpass.c	Fri Jan 22 16:13:19 1999
***************
*** 43,48 ****
--- 43,53 ----
  #endif
  #include <ctype.h>
  #include <sys/stat.h>
+ 
+ #ifdef USE_FILE64_FUNCS
+ #include "largefile.h"
+ #endif /* USE_FILE64_FUNCS */
+ 
  #include <errno.h>
  #include "ftp_var.h"
  
Index: appl/gssftp/ftpd/Makefile.in
diff -c krb5/appl/gssftp/ftpd/Makefile.in:1.1.1.2 krb5/appl/gssftp/ftpd/Makefile.in:1.4
*** krb5/appl/gssftp/ftpd/Makefile.in:1.1.1.2	Wed May 12 13:21:12 1999
--- krb5/appl/gssftp/ftpd/Makefile.in	Wed May 12 14:55:48 1999
***************
*** 1,13 ****
  #
  # appl/gssftp/ftpd/Makefile.in
  #
! CFLAGS = -DGSSAPI -DFTP_BUFSIZ=10240 $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
  
  SETENVSRC=@SETENVSRC@
  SETENVOBJ=@SETENVOBJ@
  LIBOBJS=@LIBOBJS@
  COMERRLIB=$(BUILDTOP)/util/et/libcom_err.a
! 
  LOCAL_LIBRARIES=-lpty
  DEPLOCAL_LIBRARIES=$(TOPLIBD)/../util/pty/libpty.a
  
--- 1,13 ----
  #
  # appl/gssftp/ftpd/Makefile.in
  #
! CFLAGS = -DGSSAPI -DFTP_BUFSIZ=10240 $(CCOPTS) $(DEFS) $(LOCALINCLUDE) -DKPROGDIR=\"$(CLIENT_BINDIR)\"
  
  SETENVSRC=@SETENVSRC@
  SETENVOBJ=@SETENVOBJ@
  LIBOBJS=@LIBOBJS@
  COMERRLIB=$(BUILDTOP)/util/et/libcom_err.a
! AFSLIBS=@AFSLIBS@
  LOCAL_LIBRARIES=-lpty
  DEPLOCAL_LIBRARIES=$(TOPLIBD)/../util/pty/libpty.a
  
***************
*** 30,36 ****
  all::	ftpd
  
  ftpd:	$(OBJS) $(DEPKLIB)
! 	$(LD) $(LDFLAGS) $(LDARGS) -o $@ $(OBJS) $(KLIB) $(LIBS)
  
  clean::
  	$(RM) ftpd ftpcmd.c
--- 30,36 ----
  all::	ftpd
  
  ftpd:	$(OBJS) $(DEPKLIB)
! 	$(LD) $(LDFLAGS) $(LDARGS) -o $@ $(OBJS) $(KLIB) $(LIBS) $(AFSLIBS)
  
  clean::
  	$(RM) ftpd ftpcmd.c
Index: appl/gssftp/ftpd/configure.in
diff -c krb5/appl/gssftp/ftpd/configure.in:1.1.1.2 krb5/appl/gssftp/ftpd/configure.in:1.10
*** krb5/appl/gssftp/ftpd/configure.in:1.1.1.2	Wed May 12 13:21:12 1999
--- krb5/appl/gssftp/ftpd/configure.in	Wed May 12 14:55:48 1999
***************
*** 19,24 ****
--- 19,49 ----
  AC_REPLACE_FUNCS(getdtablesize)
  AC_HAVE_FUNCS(getcwd getusershell seteuid setreuid setresuid)
  AC_CHECK_LIB(crypt,crypt) dnl 
+ dnl copied (mostly) from appl/bsd/configure.in
+ AFSLIBS=
+ AC_ARG_WITH([afs],
+ [  --without-afs	don't have afs libraries to build against (default)
+   --with-afs=AFSDIR	use preinstalled AFS library tree],
+ ,with_afs=no)dnl
+ if test $with_afs != no; then
+ 	AC_DEFINE(SETPAG)
+ 	AFSLIBS="$AFSLIBS -L$with_afs/lib -L$with_afs/lib/afs -lauth -lsys -lrx -llwp -lsys"
+ 	case $krb5_cv_host in
+ 	*-*-solaris*)
+ 		AFSLIBS="$AFSLIBS -lc -L/usr/ucblib -lucb -R/usr/ucblib"
+ 		;;
+ 	*-*-hpux*)
+ 		AFSLIBS="$AFSLIBS -lBSD -lm"
+ 		;;
+ 	*-*-netbsd*)
+ 		AFSLIBS="$AFSLIBS -lcompat"
+ 		;;
+ 	esac
+ fi
+ AC_SUBST(AFSLIBS)
+ AC_ARG_WITH([multihomed_fixes],
+ [  --with-multihomed-fixes  Includes fixes to help deal with multihomed hosts],
+ AC_DEFINE(KRB5_MULTIHOMED_FIXES))
  AC_CHECK_LIB(util,logwtmp)
  dnl 
  dnl copied from appl/bsd/configure.in
***************
*** 47,61 ****
  AC_DEFINE(HAVE_SHADOW)
  fi
  dnl
  dnl
  case $krb5_cv_host in
! alpha-dec-osf*)
! 	AC_CHECK_LIB(security,setluid,
! 		AC_DEFINE(HAVE_SETLUID)
! 		LIBS="$LIBS -lsecurity"
! 	)
! 	;;
  esac
  USE_ANAME
  KRB5_LIBRARIES
  V5_USE_SHARED_LIB
--- 72,115 ----
  AC_DEFINE(HAVE_SHADOW)
  fi
  dnl
+ dnl Check for --enable-log-preauth-logins
+ AC_ARG_ENABLE([log-preauth-logins],
+ [  --enable-log-preauth-logins  Log whether logins are password or preauthenticated],[
+ AC_MSG_RESULT(Enable logging of preauthenticated logins)
+ AC_DEFINE(LOG_PREAUTH_LOGINS)
+ ])
+ dnl
+ dnl
+ dnl Check for HPUX Protected password support
+ AC_MSG_CHECKING([libsec])
+ AC_CACHE_VAL(krb5_cv_have_libsec,
+ [AC_CHECK_LIB(sec, getprpwent,
+ krb5_cv_have_libsec=yes, krb5_cv_have_libsec=no)])
+ AC_MSG_RESULT($krb5_cv_have_libsec)
+ dnl
+ AC_MSG_CHECKING([HP-UX protected password support])
+ AC_CACHE_VAL(krb5_cv_protected_pwd,
+ [krb5_cv_protected_pwd=$krb5_cv_have_libsec])
+ AC_MSG_RESULT($krb5_cv_protected_pwd)
  dnl
+ if test $krb5_cv_protected_pwd = yes; then
+ AC_DEFINE(HAVE_PRPASSWD)
+ LIBS="$LIBS -lsec"
+ fi
+ dnl
+ dnl Check for special "large file" function calls and OSF/1 setluid call
  case $krb5_cv_host in
! 	*-*-hpux*)
! 		AC_CHECK_HEADERS(sys/cnx_types.h, AC_DEFINE(USE_FILE64_FUNCS))
! 		;;
! 	alpha-dec-osf*)
! 		AC_CHECK_LIB(security,setluid,
! 			AC_DEFINE(HAVE_SETLUID)
! 			LIBS="$LIBS -lsecurity"
! 		)
! 		;;
  esac
+ dnl
  USE_ANAME
  KRB5_LIBRARIES
  V5_USE_SHARED_LIB
Index: appl/gssftp/ftpd/ftpcmd.y
diff -c krb5/appl/gssftp/ftpd/ftpcmd.y:1.1.1.2 krb5/appl/gssftp/ftpd/ftpcmd.y:1.6
*** krb5/appl/gssftp/ftpd/ftpcmd.y:1.1.1.2	Wed May 12 13:21:13 1999
--- krb5/appl/gssftp/ftpd/ftpcmd.y	Fri Aug 27 19:35:09 1999
***************
*** 66,71 ****
--- 66,78 ----
  #include <ctype.h>
  #include <stdlib.h>
  #include <string.h>
+ #ifdef __hpux
+ #include <alloca.h>
+ #endif
+ 
+ #ifdef USE_FILE64_FUNCS
+ #include "largefile.h"
+ #endif /* USE_FILE64_FUNCS */
  
  extern	char *auth_type;
  
***************
*** 130,135 ****
--- 137,143 ----
  extern	int usedefault;
  extern  int transflag;
  extern  char tmpline[];
+ extern	int rbufsize;
  char	**ftpglob();
  
  off_t	restart_point;
***************
*** 164,170 ****
  struct tab sitetab[];
  %}
  
! %union { int num; char *str; }
  
  %token
  	A	B	C	E	F	I
--- 172,178 ----
  struct tab sitetab[];
  %}
  
! %union { int num; char *str; off_t byte; }
  
  %token
  	A	B	C	E	F	I
***************
*** 182,188 ****
  	AUTH	ADAT	PROT    PBSZ
  	CCC
  
! 	UMASK	IDLE	CHMOD
  
  	LEXERR
  
--- 190,196 ----
  	AUTH	ADAT	PROT    PBSZ
  	CCC
  
! 	UMASK	IDLE	CHMOD	RBUFSZ
  
  	LEXERR
  
***************
*** 352,365 ****
--- 360,381 ----
  	|	STOR check_login SP pathname CRLF
  		= {
  			if ($2 && $4 != NULL)
+ #ifdef USE_FILE64_FUNCS
+ 				store_file((char *) $4, "wl", 0);
+ #else /* ! USE_FILE64_FUNCS */
  				store_file((char *) $4, "w", 0);
+ #endif /* ! USE_FILE64_FUNCS */
  			if ($4 != NULL)
  				free((char *) $4);
  		}
  	|	APPE check_login SP pathname CRLF
  		= {
  			if ($2 && $4 != NULL)
+ #ifdef USE_FILE64_FUNCS
+ 				store_file((char *) $4, "al", 0);
+ #else /* ! USE_FILE64_FUNCS */
  				store_file((char *) $4, "a", 0);
+ #endif /* ! USE_FILE64_FUNCS */
  			if ($4 != NULL)
  				free((char *) $4);
  		}
***************
*** 546,555 ****
--- 562,594 ----
  				    timeout);
  			}
  		}
+ 	|	SITE SP RBUFSZ CRLF
+ 		= {
+ 			if (rbufsize)
+ 				reply(200, "Using a TCP buffer size of %d "
+ 					"bytes", rbufsize);
+ 			else
+ 				reply(200, "Using system default for TCP "
+ 					"buffer size");
+ 		}
+ 	|	SITE SP RBUFSZ SP NUMBER CRLF
+ 		= {
+ 			rbufsize = $5;
+ 			if (rbufsize) 
+ 				reply(200, "TCP buffer size set to %d bytes",
+ 					rbufsize);
+ 			else
+ 				reply(200, "Using system default for TCP "
+ 					"buffer size");
+ 		}
  	|	STOU check_login SP pathname CRLF
  		= {
  			if ($2 && $4 != NULL)
+ #ifdef USE_FILE64_FUNCS
+ 				store_file((char *) $4, "wl", 1);
+ #else /* ! USE_FILE64_FUNCS */
  				store_file((char *) $4, "w", 1);
+ #endif /* ! USE_FILE64_FUNCS */
  			if ($4 != NULL)
  				free((char *) $4);
  		}
***************
*** 599,605 ****
  			if ($2 && $4 != NULL) {
  				struct stat stbuf;
  				if (stat((char *) $4, &stbuf) < 0)
! 					perror_reply(550, "%s", (char *) $4);
  				else if ((stbuf.st_mode&S_IFMT) != S_IFREG) {
  					reply(550, "%s: not a plain file.",
  						(char *) $4);
--- 638,644 ----
  			if ($2 && $4 != NULL) {
  				struct stat stbuf;
  				if (stat((char *) $4, &stbuf) < 0)
! 					perror_reply(550, (char *) $4);
  				else if ((stbuf.st_mode&S_IFMT) != S_IFREG) {
  					reply(550, "%s: not a plain file.",
  						(char *) $4);
***************
*** 651,658 ****
  	|	REST SP byte_size CRLF
  		= {
  			fromname = (char *) 0;
! 			restart_point = $3;
  			reply(350, "Restarting at %ld. %s", restart_point,
  			    "Send STORE or RETRIEVE to initiate transfer.");
  		}
  	;
--- 690,701 ----
  	|	REST SP byte_size CRLF
  		= {
  			fromname = (char *) 0;
! 			restart_point = $<byte>3;
! #if defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS == 64
! 			reply(350, "Restarting at %lld. %s", restart_point,
! #else /* ! USE_FILE64_FUNCS */
  			reply(350, "Restarting at %ld. %s", restart_point,
+ #endif /* ! USE_FILE64_FUNCS */
  			    "Send STORE or RETRIEVE to initiate transfer.");
  		}
  	;
***************
*** 905,910 ****
--- 948,954 ----
  	{ "UMASK", UMASK, ARGS, 1,	"[ <sp> umask ]" },
  	{ "IDLE", IDLE, ARGS, 1,	"[ <sp> maximum-idle-time ]" },
  	{ "CHMOD", CHMOD, NSTR, 1,	"<sp> mode <sp> file-name" },
+ 	{ "RBUFSZ", RBUFSZ, ARGS, 1,	"[ <sp> buffer-size ]" },
  	{ "HELP", HELP, OSTR, 1,	"[ <sp> <string> ]" },
  	{ NULL,   0,    0,    0,	0 }
  };
***************
*** 1282,1287 ****
--- 1326,1336 ----
  				c = cbuf[cpos];
  				cbuf[cpos] = '\0';
  				yylval.num = atoi(cp);
+ #if defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS == 64
+ 				yylval.byte = atoll(cp);
+ #else /* defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS == 64 */
+ 				yylval.byte = atol(cp);
+ #endif /* defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS == 64 */
  				cbuf[cpos] = c;
  				state = STR1;
  				return (NUMBER);
***************
*** 1297,1302 ****
--- 1346,1356 ----
  				c = cbuf[cpos];
  				cbuf[cpos] = '\0';
  				yylval.num = atoi(cp);
+ #if defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS == 64
+ 				yylval.byte = atoll(cp);
+ #else /* defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS == 64 */
+ 				yylval.byte = atol(cp);
+ #endif /* defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS == 64 */
  				cbuf[cpos] = c;
  				return (NUMBER);
  			}
***************
*** 1470,1483 ****
  		    (stbuf.st_mode&S_IFMT) != S_IFREG)
  			reply(550, "%s: not a plain file.", filename);
  		else
  			reply(213, "%lu", stbuf.st_size);
  		break;}
  	case TYPE_A: {
  		FILE *fin;
  		register int c;
- 		register long count;
  		struct stat stbuf;
  		fin = fopen(filename, "r");
  		if (fin == NULL) {
  			perror_reply(550, filename);
  			return;
--- 1524,1546 ----
  		    (stbuf.st_mode&S_IFMT) != S_IFREG)
  			reply(550, "%s: not a plain file.", filename);
  		else
+ #if defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS==64
+ 			reply(213, "%llu", stbuf.st_size);
+ #else /* ! USE_FILE64_FUNCS */
  			reply(213, "%lu", stbuf.st_size);
+ #endif /* ! USE_FILE64_FUNCS */
  		break;}
  	case TYPE_A: {
  		FILE *fin;
  		register int c;
  		struct stat stbuf;
+ #ifdef USE_FILE64_FUNCS
+ 		register long long count;
+ 		fin = fopen(filename, "rl");
+ #else /* ! USE_FILE64_FUNCS */
+ 		register long count;
  		fin = fopen(filename, "r");
+ #endif /* ! USE_FILE64_FUNCS */
  		if (fin == NULL) {
  			perror_reply(550, filename);
  			return;
***************
*** 1497,1503 ****
--- 1560,1570 ----
  		}
  		(void) fclose(fin);
  
+ #if defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS==64
+ 		reply(213, "%lld", count);
+ #else /* ! USE_FILE64_FUNCS */
  		reply(213, "%ld", count);
+ #endif /* ! USE_FILE64_FUNCS */
  		break;}
  	default:
  		reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]);
Index: appl/gssftp/ftpd/ftpd.M
diff -c krb5/appl/gssftp/ftpd/ftpd.M:1.1.1.2 krb5/appl/gssftp/ftpd/ftpd.M:1.3
*** krb5/appl/gssftp/ftpd/ftpd.M:1.1.1.2	Wed May 12 13:21:13 1999
--- krb5/appl/gssftp/ftpd/ftpd.M	Wed May 12 14:55:49 1999
***************
*** 324,329 ****
--- 324,335 ----
  give help information.
  .IR E.g. ,
  SITE HELP
+ .sp -1
+ .TP
+ RBUFSZ
+ set or report the TCP buffer sizes
+ .IR E.g. ,
+ RBUFSZ 32768
  .PP
  The remaining ftp requests specified in Internet
  .I RFC 959
Index: appl/gssftp/ftpd/ftpd.c
diff -c krb5/appl/gssftp/ftpd/ftpd.c:1.1.1.3 krb5/appl/gssftp/ftpd/ftpd.c:1.17
*** krb5/appl/gssftp/ftpd/ftpd.c:1.1.1.3	Wed May 12 13:21:14 1999
--- krb5/appl/gssftp/ftpd/ftpd.c	Fri Aug 27 19:35:09 1999
***************
*** 68,73 ****
--- 68,91 ----
  #ifdef HAVE_SHADOW
  #include <shadow.h>
  #endif
+ 
+ #ifdef USE_FILE64_FUNCS
+ #include "largefile.h"
+ #endif /* USE_FILE64_FUNCS */
+ 
+ #ifdef HAVE_PRPASSWD
+ /* HPUX's protected (e.g. shadow) password database */
+ #include <sys/types.h>
+ #include <hpsecurity.h>
+ /*
+  * Argh - this sucks. We need to include "/usr/include/prot.h" but
+  * specifying <prot.h> gets us kerberosIV/prot.h, so we have to use
+  * the full path name.
+  */
+ #include "/usr/include/prot.h"
+ char *prcrypt(char *, char *);
+ #endif
+ 
  #include <setjmp.h>
  #ifndef POSIX_SETJMP
  #undef sigjmp_buf
***************
*** 122,127 ****
--- 140,150 ----
  extern lreply(int, char *, ...);
  #endif
  
+ #ifdef HAVE_PRPASSWD
+ /* Use prcrypt() instead of crypt()? */
+ static int use_prcrypt = 0;
+ #endif
+ 
  #ifdef KERBEROS
  #include <krb.h>
  
***************
*** 186,191 ****
--- 209,215 ----
  int	usedefault = 1;		/* for data transfers */
  int	pdata = -1;		/* for passive mode */
  int	transflag;
+ int	rbufsize = 0;		/* Buffer size */
  off_t	file_size;
  off_t	byte_count;
  #if !defined(CMASK) || CMASK == 0
***************
*** 220,225 ****
--- 244,317 ----
  char	proctitle[FTP_BUFSIZ];	/* initial part of title */
  #endif /* SETPROCTITLE */
  
+ /*
+  * AFS PAG and ticket destruction code
+  */
+ 
+ #ifdef SETPAG
+ 
+ typedef krb5_sigtype sigtype;
+ 
+ #ifndef POSIX_SETJMP
+ #undef sigjmp_buf
+ #undef sigsetjmp
+ #undef siglongjmp
+ #define sigjmp_buf	jmp_buf
+ #define sigsetjmp(j,s)	setjmp(j)
+ #define siglongjmp	longjmp
+ #endif
+ 
+ #if !defined(SIGSYS) && defined(__linux__)
+ /* Linux doesn't seem to have SIGSYS */
+ #define SIGSYS	SIGUNUSED
+ #endif
+ 
+ #ifdef POSIX_SIGNALS
+ typedef struct sigaction handler;
+ #define handler_init(H,F)		(sigemptyset(&(H).sa_mask), \
+ 					 (H).sa_flags=0, \
+ 					 (H).sa_handler=(F))
+ #define handler_swap(S,NEW,OLD)		sigaction(S, &NEW, &OLD)
+ #define handler_set(S,OLD)		sigaction(S, &OLD, NULL)
+ #else
+ typedef sigtype (*handler)();
+ #define handler_init(H,F)		((H) = (F))
+ #define handler_swap(S,NEW,OLD)		((OLD) = signal ((S), (NEW)))
+ #define handler_set(S,OLD)		(signal ((S), (OLD)))
+ #endif
+ 
+ extern setpag(), ktc_ForgetAllTokens();
+ 
+ static int pagflag = 0;
+ 
+ static sigjmp_buf setpag_buf;
+ 
+ static sigtype sigsys ()
+ {
+     siglongjmp(setpag_buf, 1);
+ }
+ 
+ static int try_afscall(scall)
+ 	int (*scall)();
+ {
+ 	handler sa, osa;
+ 	volatile int retval = 0;
+ 
+ 	(void) &retval;
+ 	handler_init(sa, sigsys);
+ 	handler_swap(SIGSYS, sa, osa);
+ 	if (sigsetjmp(setpag_buf, 1) == 0) {
+ 	    (*scall)();
+ 	    retval = 1;
+ 	}
+ 	handler_set(SIGSYS, osa);
+ 	return retval;
+ }
+ 
+ #define try_setpag()	try_afscall(setpag);
+ #define try_unlog()	try_afscall(ktc_ForgetAllTokens)
+ #endif /* SETPAG */
+ 
  #ifdef __SCO__
  /* sco has getgroups and setgroups but no initgroups */
  int initgroups(char* name, gid_t basegid) {
***************
*** 243,248 ****
--- 335,341 ----
  {
  	int addrlen, on = 1, tos, port = -1;
  	char *cp;
+ 	char ccname[35];
  
  	debug = 0;
  #ifdef SETPROCTITLE
***************
*** 430,435 ****
--- 523,539 ----
  #define LOG_DAEMON 0
  #endif
  	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
+ 
+ #ifdef GSSAPI
+ 	/*
+ 	 * Just in case we're using Kerberos, setup a private
+ 	 * credential cache
+ 	 */
+ 
+ 	sprintf(ccname, "FILE:/tmp/krb5cc_p%d", getpid());
+ 	setenv("KRB5CCNAME", ccname, 0);
+ #endif
+ 
  	addrlen = sizeof (his_addr);
  	if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
  		syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
***************
*** 541,546 ****
--- 645,653 ----
  #ifdef HAVE_SHADOW
  	register struct spwd *sp;
  #endif
+ #ifdef HAVE_PRPASSWD
+ 	struct pr_passwd *prpwd;
+ #endif
  	char *sgetsave();
  
  	if ((p = getpwnam(name)) == NULL)
***************
*** 554,560 ****
  	}
  	save = *p;
  	save.pw_name = sgetsave(p->pw_name);
! #ifdef HAVE_SHADOW
  	if ((sp = getspnam(name)) == NULL)
  	    save.pw_passwd = sgetsave(p->pw_passwd);
  	else
--- 661,675 ----
  	}
  	save = *p;
  	save.pw_name = sgetsave(p->pw_name);
! #ifdef HAVE_PRPASSWD
! 	if ((prpwd = getprpwnam(name)) == NULL) {
! 	    save.pw_passwd = sgetsave(p->pw_passwd);
! 	    use_prcrypt = 0;
! 	} else {
! 	    save.pw_passwd = sgetsave(prpwd->ufld.fd_encrypt);
! 	    use_prcrypt =1;
! 	}
! #elif HAVE_SHADOW
  	if ((sp = getspnam(name)) == NULL)
  	    save.pw_passwd = sgetsave(p->pw_passwd);
  	else
***************
*** 646,655 ****
  		while ((cp = getusershell()) != NULL)
  			if (strcmp(cp, shell) == 0)
  				break;
! 		/* endusershell(); */ /* this breaks on solaris 2.4 */
  #else
  		cp = shell;
! #endif
  		if (cp == NULL || checkuser(name)) {
  			reply(530, "User %s access denied.", name);
  			if (logging)
--- 761,770 ----
  		while ((cp = getusershell()) != NULL)
  			if (strcmp(cp, shell) == 0)
  				break;
! 		endusershell();
  #else
  		cp = shell;
! #endif	
  		if (cp == NULL || checkuser(name)) {
  			reply(530, "User %s access denied.", name);
  			if (logging)
***************
*** 755,760 ****
--- 870,878 ----
   */
  end_login()
  {
+ #ifdef GSSAPI
+ 	afs_logout();
+ #endif
  
  	(void) seteuid((uid_t)0);
  	if (logged_in)
***************
*** 820,838 ****
  	char *passwd;
  {
  	char *xpasswd, *salt;
  
  	if (logged_in || askpasswd == 0) {
  		reply(503, "Login with USER first.");
  		return;
  	}
  	askpasswd = 0;
! 	if (
  #ifdef KERBEROS
! 	    !kerb_ok &&
  #endif /* KERBEROS */
  #ifdef GSSAPI
! 	    !gss_ok &&
  #endif /* GSSAPI */
  	    !guest) {		/* "ftp" is only account allowed no password */
  		if (pw == NULL)
  			salt = "xx";
--- 938,962 ----
  	char *passwd;
  {
  	char *xpasswd, *salt;
+ 	int preauthenticated;
  
  	if (logged_in || askpasswd == 0) {
  		reply(503, "Login with USER first.");
  		return;
  	}
  	askpasswd = 0;
! 
! 	/* Has user been preauthenticated? */
! 	preauthenticated =
  #ifdef KERBEROS
! 	    kerb_ok ||
  #endif /* KERBEROS */
  #ifdef GSSAPI
! 	    gss_ok ||
  #endif /* GSSAPI */
+ 		0;
+ 
+ 	if (!preauthenticated &&
  	    !guest) {		/* "ftp" is only account allowed no password */
  		if (pw == NULL)
  			salt = "xx";
***************
*** 843,848 ****
--- 967,976 ----
  		xpasswd = "";
  #else
  		xpasswd = crypt(passwd, salt);
+ #ifdef HAVE_PRPASSWD
+ 		if (use_prcrypt)
+ 		    xpasswd = prcrypt(passwd, salt);
+ #endif /* HAVE_PRPASSWD */
  #endif
  #ifdef KERBEROS
  		/* null pw_passwd ok if Kerberos password ok */
***************
*** 850,855 ****
--- 978,989 ----
  		    (*pw->pw_passwd && strcmp(xpasswd, pw->pw_passwd) &&
  			!kpass(pw->pw_name, passwd)) ||
  		    (!*pw->pw_passwd && !kpass(pw->pw_name, passwd))) {
+ #elif defined(GSSAPI)
+ 		/* null pw_passwd ok if Kerberos 5 password ok */
+ 		if (pw == NULL ||
+ 		    (*pw->pw_passwd && strcmp(xpasswd, pw->pw_passwd) &&
+ 			!k5pass(pw->pw_name, passwd)) ||
+ 		    (!*pw->pw_passwd && !k5pass(pw->pw_name, passwd))) {
  #else
  		/* The strcmp does not catch null passwords! */
  		if (pw == NULL || *pw->pw_passwd == '\0' ||
***************
*** 885,914 ****
  			reply(550, "Can't set guest privileges.");
  			goto bad;
  		}
! 	} else if (chdir(pw->pw_dir) < 0) {
! 		if (chdir("/") < 0) {
! 			reply(530, "User %s: can't change directory to %s.",
! 			    pw->pw_name, pw->pw_dir);
  			goto bad;
! 		} else
! 			lreply(230, "No directory! Logging in with home=/");
! 	}
  #ifdef HAVE_SETLUID
!   	/*
!   	 * If we're on a system which keeps track of login uids, then
!  	 * set the login uid. If this fails this opens up a problem on DEC OSF
!  	 * with C2 enabled.
! 	 */
! 	if (((uid_t)getluid() != pw->pw_uid)
! 	    && setluid((uid_t)pw->pw_uid) < 0) {
! 	        reply(550, "Can't set luid.");
! 		goto bad;
! 	}
  #endif
! 	if (seteuid((uid_t)pw->pw_uid) < 0) {
! 		reply(550, "Can't set uid.");
! 		goto bad;
  	}
  	if (guest) {
  		reply(230, "Guest login ok, access restrictions apply.");
  #ifdef SETPROCTITLE
--- 1019,1077 ----
  			reply(550, "Can't set guest privileges.");
  			goto bad;
  		}
! 		if (seteuid((uid_t)pw->pw_uid) < 0) {
! 			reply(550, "Can't set uid.");
  			goto bad;
! 		}
! 	} else {
! 		/*
! 		 * Call afs_login to hide the extra magic we need to do
! 		 *
! 		 * Note that much of this stuff needs to happen as the user,
! 		 * so we're setting the effective uid now.  But note that
! 		 * we call setpag _before_ we give up root.
! 		 */
! 
! #ifdef SETPAG
! 		pagflag = try_setpag();
! #endif /* SETPAG */
! 
! #ifdef GSSAPI
! 		save_credentials();
! #endif
! 
  #ifdef HAVE_SETLUID
! 		/*
! 		 * If we're on a system which keeps track of login uids, then
! 		 * set the login uid. If this fails this opens up a problem
! 		 * on DEC OSF with C2 enabled.
! 		 */
! 		if (((uid_t)getluid() != pw->pw_uid)
! 		    && setluid((uid_t)pw->pw_uid) < 0) {
! 			reply(550, "Can't set luid.");
! 			goto bad;
! 		}
  #endif
! 		if (seteuid((uid_t)pw->pw_uid) < 0) {
! 			reply(550, "Can't set uid.");
! 			goto bad;
! 		}
! 
! 
! #ifdef GSSAPI
! 		afs_login(pw->pw_uid);
! #endif
! 
! 		if (chdir(pw->pw_dir) < 0) {
! 			if (chdir("/") < 0) {
! 				reply(530, "User %s: can't change directory to %s.",
! 				    pw->pw_name, pw->pw_dir);
! 				goto bad;
! 			} else
! 				lreply(230, "No directory! Logging in with home=/");
! 		}
  	}
+ 
  	if (guest) {
  		reply(230, "Guest login ok, access restrictions apply.");
  #ifdef SETPROCTITLE
***************
*** 928,934 ****
  		setproctitle(proctitle);
  #endif /* SETPROCTITLE */
  		if (logging)
! 			syslog(LOG_INFO, "FTP LOGIN FROM %s, %s (%s)",
  			    rhost_addra, remotehost, pw->pw_name);
  	}
  	home = pw->pw_dir;		/* home dir for globbing */
--- 1091,1104 ----
  		setproctitle(proctitle);
  #endif /* SETPROCTITLE */
  		if (logging)
! 			syslog(LOG_INFO, "FTP %s LOGIN FROM %s %s, (%s)",
! #ifdef LOG_PREAUTH_LOGINS
! 			       (preauthenticated
! 				? "PREAUTHENTICATED "
! 				: "PASSWORD "),
! #else /* LOG_PREAUTH_LOGINS */
! 			       "",
! #endif /* ! LOG_PREAUTH_LOGINS */
  			    rhost_addra, remotehost, pw->pw_name);
  	}
  	home = pw->pw_dir;		/* home dir for globbing */
***************
*** 947,953 ****
--- 1117,1127 ----
  	int (*closefunc)();
  
  	if (cmd == 0) {
+ #ifdef USE_FILE64_FUNCS
+ 		fin = fopen(name, "rl"), closefunc = fclose;
+ #else /* ! USE_FILE64_FUNCS */
  		fin = fopen(name, "r"), closefunc = fclose;
+ #endif /* ! USE_FILE64_FUNCS */
  		st.st_size = 0;
  	} else {
  		char line[FTP_BUFSIZ];
***************
*** 1017,1023 ****
--- 1191,1201 ----
  		return;
  
  	if (restart_point)
+ #ifdef USE_FILE64_FUNCS
+ 		mode = "r+wl";
+ #else /* ! USE_FILE64_FUNCS */
  		mode = "r+w";
+ #endif /* ! USE_FILE64_FUNCS */
  	fout = fopen(name, mode);
  	closefunc = fclose;
  	if (fout == NULL) {
***************
*** 1084,1089 ****
--- 1262,1273 ----
  	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  	    (char *) &on, sizeof (on)) < 0)
  		goto bad;
+ 	if (rbufsize) {
+ 		if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&rbufsize, sizeof(rbufsize)) < 0)
+ 			goto bad;
+ 		if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&rbufsize, sizeof(rbufsize)) < 0)
+ 			goto bad;
+ 	}
  	/* anchor socket to avoid multi-homing problems */
  	data_source.sin_family = AF_INET;
  	data_source.sin_addr = ctrl_addr.sin_addr;
***************
*** 1123,1129 ****
--- 1307,1317 ----
  	file_size = size;
  	byte_count = 0;
  	if (size != (off_t) -1)
+ #if defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS==64
+ 		(void) sprintf (sizebuf, " (%lld bytes)", size);
+ #else /* ! USE_FILE64_FUNCS */
  		(void) sprintf (sizebuf, " (%ld bytes)", size);
+ #endif /* ! USE_FILE64_FUNCS */
  	else
  		(void) strcpy(sizebuf, "");
  	if (pdata >= 0) {
***************
*** 1765,1770 ****
--- 1953,1967 ----
  dologout(status)
  	int status;
  {
+ 	/*
+ 	 * Prevent reception of SIGURG from resulting in a resumption
+ 	 * back to the main program loop.
+ 	 */
+ 	transflag = 0;
+ 
+ #ifdef GSSAPI
+ 	afs_logout();
+ #endif
  	if (logged_in) {
  		(void) seteuid((uid_t)0);
  		pty_logwtmp(ttyline, "", "");
***************
*** 1798,1807 ****
--- 1995,2011 ----
  	}
  	if (strcmp(cp, "STAT") == 0) {
  		if (file_size != (off_t) -1)
+ #if defined(USE_FILE64_FUNCS) || _FILE_OFFSET_BITS==64
+ 			reply(213, "Status: %llu of %llu bytes transferred",
+ 			    byte_count, file_size);
+ 		else
+ 			reply(213, "Status: %llu bytes transferred", byte_count);
+ #else /* ! USE_FILE64_FUNCS */
  			reply(213, "Status: %lu of %lu bytes transferred",
  			    byte_count, file_size);
  		else
  			reply(213, "Status: %lu bytes transferred", byte_count);
+ #endif /* ! USE_FILE64_FUNCS */
  	}
  }
  
***************
*** 1828,1833 ****
--- 2032,2047 ----
  		(void) seteuid((uid_t)pw->pw_uid);
  		goto pasv_error;
  	}
+ 	if (rbufsize) {
+ 		if (setsockopt(pdata, SOL_SOCKET, SO_SNDBUF, (char *)&rbufsize, sizeof(rbufsize)) < 0) {
+ 			perror_reply(425, "Can't set requested socket buffer send size");
+ 			return;
+ 		}
+ 		if (setsockopt(pdata, SOL_SOCKET, SO_RCVBUF, (char *)&rbufsize, sizeof(rbufsize)) < 0) {
+ 			perror_reply(425, "Can't set requested socket buffer receive size");
+ 			return;
+ 		}
+ 	}
  	(void) seteuid((uid_t)pw->pw_uid);
  	len = sizeof(pasv_addr);
  	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
***************
*** 2006,2011 ****
--- 2220,2229 ----
  		char service_name[MAXHOSTNAMELEN+10];
  		char **service;
  		struct hostent *hp;
+ #ifdef KRB5_MULTIHOMED_FIXES
+ 		struct sockaddr_in s;
+ 		int slen;
+ #endif /* KRB5_MULTIHOMED_FIXES */
  
  		chan.initiator_addrtype = GSS_C_AF_INET;
  		chan.initiator_address.length = 4;
***************
*** 2026,2031 ****
--- 2244,2250 ----
  		tok.value = gout_buf;
  		tok.length = length;
  
+ #ifndef KRB5_MULTIHOMED_FIXES
  		if (gethostname(localname, MAXHOSTNAMELEN)) {
  			reply(501, "couldn't get local hostname (%d)\n", errno);
  			syslog(LOG_ERR, "Couldn't get local hostname (%d)", errno);
***************
*** 2037,2044 ****
  			syslog(LOG_ERR, "Couldn't canonicalize local hostname (%d)", h_errno);
  			return 0;
  		}
  		strcpy(localname, hp->h_name);
! 
  		for (service = gss_services; *service; service++) {
  			sprintf(service_name, "%s@%s", *service, localname);
  			name_buf.value = service_name;
--- 2256,2285 ----
  			syslog(LOG_ERR, "Couldn't canonicalize local hostname (%d)", h_errno);
  			return 0;
  		}
+ #else /* KRB5_MULTIHOMED_FIXES */
+ 		slen = sizeof(s);
+ 		if (getsockname(0, (struct sockaddr *) &s, &slen) < 0) {
+ 			reply(501, "couldn't get socket name (%d)\n", errno);
+ 			syslog(LOG_ERR, "Couldn't get socket name (%d)", errno);
+ 			return 0;
+ 		}
+ 		if (!(hp = gethostbyaddr((char *)&s.sin_addr.s_addr,
+ 														 sizeof(s.sin_addr.s_addr),
+ 														 AF_INET))) {
+ #ifndef h_errno
+ 			/*
+ 			 * Under AIX h_errno is a macro.
+ 			 * This should really be a feature test.
+ 			 */
+ 			extern int h_errno;
+ #endif /* h_errno */
+ 			reply(501, "couldn't canonicalize local hostname (%d)\n", h_errno);
+ 			syslog(LOG_ERR, "Couldn't canonicalize local hostname (%d)", h_errno);
+ 			return 0;
+ 		}
+ #endif /* KRB5_MULTIHOMED_FIXES */
  		strcpy(localname, hp->h_name);
! 		
  		for (service = gss_services; *service; service++) {
  			sprintf(service_name, "%s@%s", *service, localname);
  			name_buf.value = service_name;
***************
*** 2318,2324 ****
  		}
  		(void) closedir(dirp);
  	}
! 	ret = secure_write(fileno(dout), "", 0);
  data_err:
  	if (dout == NULL)
  		reply(550, "No files found.");
--- 2559,2565 ----
  		}
  		(void) closedir(dirp);
  	}
! 	ret = secure_flush(fileno(dout));
  data_err:
  	if (dout == NULL)
  		reply(550, "No files found.");
***************
*** 2444,2447 ****
--- 2685,3107 ----
  	krb5_free_context(kc);
  	return retval;
  }
+ 
+ /*
+  * Save our credentials and destroy a credential cache before we call setuid
+  */
+ 
+ static krb5_creds *saved_creds;
+ 
+ save_credentials()
+ {
+ 	krb5_context context;
+ 	krb5_ccache cc;
+ 	krb5_principal me, server;
+ 	krb5_creds mcred;
+ 
+ 	krb5_init_context(&context);
+ 
+ 	saved_creds = NULL;
+ 
+ 	if (krb5_cc_default(context, &cc))
+ 		goto leave;
+ 	
+ 	if (krb5_cc_get_principal(context, cc, &me)) {
+ 		krb5_cc_destroy(context, cc);
+ 		goto leave;
+ 	}
+ 	
+ 	if (krb5_build_principal_ext(context, &server,
+ 				     krb5_princ_realm(context, me)->length,
+ 				     krb5_princ_realm(context, me)->data,
+ 				     KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
+ 				     krb5_princ_realm(context, me)->length,
+ 				     krb5_princ_realm(context, me)->data,
+ 				     0)) {
+ 		krb5_cc_destroy(context, cc);
+ 		krb5_free_principal(context, me);
+ 		goto leave;
+ 	}
+ 
+ 	saved_creds = (krb5_creds *) malloc(sizeof(krb5_creds));
+ 	mcred.server = server;
+ 	mcred.client = me;
+ 
+ 	if (krb5_cc_retrieve_cred(context, cc, KRB5_TC_MATCH_SRV_NAMEONLY,
+ 				  &mcred, saved_creds)) {
+ 		free(saved_creds);
+ 		saved_creds = NULL;
+ 		krb5_cc_destroy(context, cc);
+ 		krb5_free_principal(context, me);
+ 		krb5_free_principal(context, server);
+ 		goto leave;
+ 	}
+ 
+ 	krb5_cc_destroy(context, cc);
+ 	krb5_free_principal(context, me);
+ 	krb5_free_principal(context, server);
+ 
+ leave:
+ 	krb5_free_context(context);
+ 
+ 	return;
+ }
+ 
+ /*
+  * Handle the magic we need for AFS.  Get a PAG and try to run aklog.
+  *
+  * Most of this was taken from login.
+  */
+ 
+ afs_login(uid)
+ 	int uid;
+ {
+ 	krb5_context context;
+ 	krb5_ccache cc;
+ 	int try_aklog = 0;
+ 	char *aklog_path;
+ 	struct stat st;
+ 
+ 	if (saved_creds == NULL)
+ 		return;
+ 
+ 	krb5_init_context(&context);
+ 
+ 	krb5_appdefault_boolean(context, "ftpd",
+ 				krb5_princ_realm(context, saved_creds->client),
+ 				"krb5_run_aklog", try_aklog, &try_aklog);
+ 	
+ 	if (try_aklog) {
+ 
+ 		if (krb5_cc_default(context, &cc))
+ 			goto leave;
+ 
+ 		if (krb5_cc_initialize(context, cc, saved_creds->client))
+ 			goto leave;
+ 
+ 		if (krb5_cc_store_cred(context, cc, saved_creds))
+ 			goto leave;
+ 
+ 		krb5_appdefault_string(context, "ftpd",
+ 				       krb5_princ_realm(context, saved_creds->client),
+ 				       "krb5_aklog_path", KPROGDIR "/aklog",
+ 				       &aklog_path);
+ 		
+ 		if (stat(aklog_path, &st) == 0) {
+ 			int pid, testpid;
+ 
+ 			/*
+ 			 * Aklog _really_ wants to run as "real user",
+ 			 * and in some cases, aklog breaks when using it
+ 			 * with an NFS translator.  Make sure that we run
+ 			 * aklog as the real user.
+ 			 */
+ 
+ 			if ((pid = fork()) == 0) {
+ 				seteuid(0);
+ 				setuid((uid_t) uid);
+ 				system(aklog_path);
+ 				exit(0);
+ 			} else {
+ 				while ((testpid = wait(NULL)) != pid &&
+ 					testpid != -1);
+ 			}
+ 		}
+ 
+ 		free(aklog_path);
+ 	}
+ 
+ leave:
+ 
+ 	if (saved_creds)
+ 		krb5_free_creds(context, saved_creds);
+ 
+ 	krb5_free_context(context);
+ 
+ }
+ 
+ afs_logout()
+ {
+ 	krb5_context context;
+ 	krb5_ccache cc;
+ 	int afs_retain_token = 0;
+ 	char *realm = NULL;
+ 	krb5_data realmdata;
+ 
+ 	krb5_init_context(&context);
+ 
+ 	krb5_cc_default(context, &cc);
+ 
+ 	krb5_cc_destroy(context, cc);
+ 
+ 	krb5_get_default_realm(context, &realm);
+ 
+ 	realmdata.data = realm;
+ 
+ 	krb5_appdefault_boolean(context, "ftpd", &realmdata, "afs_retain_token",
+ 				afs_retain_token, &afs_retain_token);
+ 	
+ 	krb5_xfree(realm);
+ 
+ 	if (!afs_retain_token) {
+ #ifdef SETPAG
+ 		if (pagflag)
+ 			try_unlog();
+ #endif /* SETPAG */
+ 	}
+ 
+ 	krb5_free_context(context);
+ }
+ 
+ static char *k5services[] = { "ftp", "host", NULL };
+ 
+ #define KRB5_DEFAULT_LIFETIME "5h 0m 0s"
+ 
+ /*
+  * Check our Kerberos 5 password
+  */
+ 
+ k5pass(name, passwd)
+ 	char *name, *passwd;
+ {
+ 	krb5_context context;
+ 	krb5_principal me = NULL, server = NULL, ver_princ = NULL;
+ 	krb5_keyblock *kb = NULL;
+ 	krb5_creds my_creds;
+ 	krb5_ccache cc;
+ 	krb5_timestamp now;
+ 	krb5_data packet;
+ 	krb5_auth_context auth_context = NULL;
+ 	char *lifetimestring, **service;
+ 	krb5_deltat lifetime;
+ 	int valid = 0;
+ 
+ 	packet.data = NULL;
+ 
+ 	/*
+ 	 * Setup Kerberos for getting the initial TGT
+ 	 */
+ 
+ 	krb5_init_context(&context);
+ 
+ 	if (krb5_cc_default(context, &cc))
+ 		goto leave;
+ 
+ 	memset((char *) &my_creds, 0, sizeof(my_creds));
+ 
+ 	if (krb5_parse_name(context, name, &me)) {
+ 		krb5_cc_destroy(context, cc);
+ 		goto leave;
+ 	}
+ 
+ 	my_creds.client = me;
+ 
+ 	if (krb5_cc_initialize(context, cc, me)) {
+ 		krb5_cc_destroy(context, cc);
+ 		goto leave;
+ 	}
+ 
+ 	if (krb5_build_principal_ext(context, &server,
+ 				     krb5_princ_realm(context, me)->length,
+ 				     krb5_princ_realm(context, me)->data,
+ 				     KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
+ 				     krb5_princ_realm(context, me)->length,
+ 				     krb5_princ_realm(context, me)->data,
+ 				     0)) {
+ 		krb5_cc_destroy(context, cc);
+ 		goto leave;
+ 	}
+ 
+ 	my_creds.server = server;
+ 
+ 	if (krb5_timeofday(context, &now)) {
+ 		krb5_cc_destroy(context, cc);
+ 		goto leave;
+ 	}
+ 
+ 	my_creds.times.starttime = 0;
+ 
+ 	krb5_appdefault_string(context, "ftpd", krb5_princ_realm(context, me),
+ 				   "default_lifetime", KRB5_DEFAULT_LIFETIME,
+ 				   &lifetimestring);
+ 
+ 	if (krb5_string_to_deltat(lifetimestring, &lifetime)) {
+ 		krb5_cc_destroy(context, cc);
+ 		free(lifetimestring);
+ 		goto leave;
+ 	}
+ 
+ 	free(lifetimestring);
+ 
+ 	my_creds.times.endtime = now + lifetime;
+ 	my_creds.times.renew_till = 0;
+ 
+ 	if (krb5_get_in_tkt_with_password(context, 0, 0, NULL, 0,
+ 						 passwd, cc, &my_creds, 0)) {
+ 		krb5_cc_destroy(context, cc);
+ 		goto leave;
+ 	}
+ 
+ 	/*
+ 	 * Ok, if we've reached this part successfully, then that means that
+ 	 * we've gotten a valid ticket from the KDC.  Now we try to get a
+ 	 * service ticket from the KDC using a known key.  In this case,
+ 	 * we try "ftp" and "host".  If neither of these principals are in
+ 	 * the keytab, then let this user in anyway.
+ 	 */
+ 
+ 	for (service = k5services; *service; service++) {
+ 		if (krb5_sname_to_principal(context, NULL, *service,
+ 					    KRB5_NT_SRV_HST, &ver_princ)) {
+ 			krb5_cc_destroy(context, cc);
+ 			goto leave;
+ 		}
+ 
+ 		if (krb5_kt_read_service_key(context, NULL, ver_princ, 0,
+ 					     ENCTYPE_DES_CBC_CRC, &kb) == 0)
+ 			break;
+ 		else {
+ 			krb5_free_principal(context, ver_princ);
+ 			ver_princ = NULL;
+ 		}
+ 	}
+ 
+ 	
+ 	if (ver_princ == NULL) {
+ 		valid = 1;
+ 		goto leave;
+ 	}
+ 
+ 	/*
+ 	 * The reason we're doing all of this is probably not very
+ 	 * obvious.  Here's the theory:
+ 	 *
+ 	 * Just getting a valid ticket from the KDC for that user isn't
+ 	 * 100% secure, because if someone else is faking replies from the
+ 	 * KDC, then they could forge a reponse that appeared to be valid,
+ 	 * but actually wasn't.  So what we do here is use a service
+ 	 * ticket for the principal {ftp|host}/<host>} and generate an
+ 	 * AP_REQ message (using krb5_mk_req()), and then use krb5_rd_req()
+ 	 * to validate that message.  Since the request generated by mk_req()
+ 	 * was encrypted with the host or ftp principal's secret key, and
+ 	 * that service ticket was generated by using the user's TGT,
+ 	 * then if we can decode the mk_req() message, that means that
+ 	 * the user's credentials are legitmate.
+ 	 */
+ 
+ 	if (krb5_mk_req(context, &auth_context, 0, *service,
+ 			krb5_princ_component(context, ver_princ, 1)->data,
+ 			NULL, cc, &packet)) {
+ 		krb5_cc_destroy(context, cc);
+ 		goto leave;
+ 	}
+ 
+ 	if (auth_context) {
+ 		krb5_auth_con_free(context, auth_context);
+ 		auth_context = NULL;
+ 	}
+ 
+ 	if (krb5_rd_req(context, &auth_context, &packet, ver_princ, NULL,
+ 			NULL, NULL)) {
+ 		krb5_cc_destroy(context, cc);
+ 		goto leave;
+ 	}
+ 
+ 	/*
+ 	 * _Whew_!  Everything is cool!
+ 	 */
+ 
+ 	valid = 1;
+ 
+ leave:
+ 
+ 	if (packet.data)
+ 		krb5_xfree(packet.data);
+ 	if (auth_context)
+ 		krb5_auth_con_free(context, auth_context);
+ 	if (kb)
+ 		krb5_free_keyblock(context, kb);
+ 	if (my_creds.keyblock.contents) {
+ 		krb5_free_cred_contents(context, &my_creds);
+ 		me = NULL;
+ 		server = NULL;
+ 	}
+ 	if (me)
+ 		krb5_free_principal(context, me);
+ 	if (server)
+ 		krb5_free_principal(context, server);
+ 	if (ver_princ)
+ 		krb5_free_principal(context, ver_princ);
+ 
+ 	krb5_free_context(context);
+ 
+ 	return(valid);
+ }
+ 
  #endif /* GSSAPI */
+ 
+ 
+ #ifdef HAVE_PRPASSWD
+ /*
+  * Return the encrypted string of a password under HP-UX's protected
+  * password scheme. Note that if a password is 8 or less characters
+  * this is the same as a crypt() call.
+  */
+ char *prcrypt(char *pass, char *salt)
+ {
+     int segments;		/* number of segments */
+     int segment;		/* current segment number */
+     int encrypted_size;		/* size of encrypted password */
+     char *ppass;		/* pointer to current segment */
+     /*
+      * Buffer for encrypted password string large enough for the
+      * longest allowed password (AUTH_MAX_PASSWD_LENGTH)
+      */
+     static char enc_pass[AUTH_CIPHERTEXT_SIZE(AUTH_SEGMENTS(AUTH_MAX_PASSWD_LENGTH))];
+     char *penc_pass;		/* pointer to current encrypted segment */
+     int passwd_len;		/* Length of password */
+ 
+ 
+     /* Make sure password isn't too long */
+     passwd_len = strlen(pass);
+ 
+     if (passwd_len > AUTH_MAX_PASSWD_LENGTH)
+ 	passwd_len = AUTH_MAX_PASSWD_LENGTH;
+        
+     /* Determine number of segments in password */
+     segments = AUTH_SEGMENTS(passwd_len);
+ 
+     /* Size of the encrypted password */
+     encrypted_size = AUTH_CIPHERTEXT_SIZE(segments);
+ 
+     /* Copy in the salt */
+     penc_pass = enc_pass;
+     strncpy(penc_pass, salt, AUTH_SALT_SIZE);
+     penc_pass += AUTH_SALT_SIZE;
+ 
+     for (segment = 0, ppass = pass;
+ 	 segment < segments;
+ 	 segment++) {
+ 	
+ 	char *enc_segment;
+ 
+ 	/* Encrypt segment */
+ 	enc_segment = crypt(ppass, salt);
+ 	ppass += AUTH_CLEARTEXT_SEG_CHARS;
+ 
+ 	/* Skip over salt */
+ 	enc_segment += AUTH_SALT_SIZE;
+ 
+ 	/* Set salt for next encrypt to result of this encryption */
+ 	salt = enc_segment;
+ 
+ 	/* And append to encrypted password */
+ 	strncpy(penc_pass, enc_segment, AUTH_CIPHERTEXT_SEG_CHARS);
+ 	penc_pass += AUTH_CIPHERTEXT_SEG_CHARS;
+ 	*penc_pass = '\0';
+     }
+ 
+     return enc_pass;
+ }
+ 
+ #endif /* HAVE_PRPASSWD */
Index: appl/gssftp/ftpd/largefile.h
diff -c /dev/null krb5/appl/gssftp/ftpd/largefile.h:1.1
*** /dev/null	Thu Sep 23 15:40:24 1999
--- krb5/appl/gssftp/ftpd/largefile.h	Fri Feb  5 16:19:16 1999
***************
*** 0 ****
--- 1,22 ----
+ /*
+  * This header file contains functions and definitions for platforms
+  * (i.e. SPP-UX) that require separate facilities for accessing large
+  * files (64 bit)
+  */
+ 
+ #include <sys/cnx_types.h>
+ #include <sys/cnx_stat.h>
+ #include <sys/cnx_unistd.h>
+ 
+ #undef off_t
+ #define off_t off64_t
+ #undef stat()
+ #define stat(f, b) stat64(f, b)
+ #undef fstat()
+ #define fstat(f, b) fstat64(f, b)
+ #undef fseek()
+ #define fseek(s, o, w) fseek64(s, o, w)
+ #undef lseek()
+ #define lseek(f, o, w) lseek64(f, o, w)
+ #undef stat
+ #define stat stat64
Index: appl/gssftp/ftpd/logwtmp.c
diff -c krb5/appl/gssftp/ftpd/logwtmp.c:1.1.1.2 krb5/appl/gssftp/ftpd/logwtmp.c:1.6
*** krb5/appl/gssftp/ftpd/logwtmp.c:1.1.1.2	Wed Feb 25 17:23:02 1998
--- krb5/appl/gssftp/ftpd/logwtmp.c	Mon Jan 11 15:00:45 1999
***************
*** 1,3 ****
--- 1,4 ----
+ #ifndef USE_PTY_LOGWTMP_FTPD
  /*
   * Copyright (c) 1988 The Regents of the University of California.
   * All rights reserved.
***************
*** 71,76 ****
--- 72,125 ----
  	if (fstat(fd, &buf) == 0) {
  		(void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
  		(void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+ 
+ 		/*
+ 		 * Fill in as many fields as we can. Accounting on
+ 		 * some systems depends on this. The following code
+ 		 * was taken from util/pty/update_utmp.c and
+ 		 * update_wtmp.c
+ 		 */
+ #ifndef NO_UT_PID
+ 		if (!strcmp (line, "/dev/console")) {
+ #if defined(__sun) && defined(__SVR4)
+ 		    strncpy (ut.ut_id, "co", 2);
+ #else
+ 		    strncpy (ut.ut_id, "cons", 4);
+ #endif
+ 		} else {
+ 		    char *tmpx;
+ 		    char utmp_id[5];
+ 
+ 
+ 		    tmpx = line + strlen(line)-1;
+ 		    if (*(tmpx-1) != '/')
+ 			tmpx--; /* last two characters, unless it's a / */
+ #if defined(__hpux) || defined(__linux__)
+ 		    strcpy(utmp_id, tmpx);
+ #elif defined(sgi)
+ 		    /* Everything after '/dev/tty/' */
+ 		    strcpy(utmp_id, line + 8);   /* 8 == strlen("/dev/tty"); */
+ #else
+ 		    sprintf(utmp_id, "kl%s", tmpx);
+ #endif
+ 		    strncpy(ut.ut_id, utmp_id, sizeof(ut.ut_id));
+ 		}
+ #endif /* !NO_UT_PID */
+ 
+ 		(void)time(&ut.ut_time);
+ #ifndef NO_UT_PID
+ 		if (*name) {
+ 		    ut.ut_pid = getpid();
+ 		    ut.ut_type = USER_PROCESS;
+ 		} else {
+ #ifdef EMPTY
+ 		    ut.ut_type = EMPTY;
+ #else
+ 		    ut.ut_type = DEAD_PROCESS; /* For Linux brokenness*/
+ #endif	    
+ 		}
+ #endif /* ! NO_UT_PID */
+ 
  #ifndef NO_UT_HOST
  		(void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
  #endif
***************
*** 80,82 ****
--- 129,132 ----
  			(void)ftruncate(fd, buf.st_size);
  	}
  }
+ #endif /* USE_PTY_LOGWTMP_FTPD */
Index: appl/telnet/libtelnet/auth.h
diff -c krb5/appl/telnet/libtelnet/auth.h:1.1.1.1 krb5/appl/telnet/libtelnet/auth.h:1.2
*** krb5/appl/telnet/libtelnet/auth.h:1.1.1.1	Mon Jun  2 17:54:37 1997
--- krb5/appl/telnet/libtelnet/auth.h	Mon Jun  2 18:34:09 1997
***************
*** 87,90 ****
--- 87,98 ----
  #define OPTS_FORWARDABLE_CREDS       0x00000001
  
  extern auth_debug_mode;
+ 
+ struct config_opts {
+ 	char	*optname;
+ 	int	*optvar;
+ };
+ 
+ void kerberos5_defaults P((struct config_opts *));
+ 
  #endif
Index: appl/telnet/libtelnet/kerberos.c
diff -c krb5/appl/telnet/libtelnet/kerberos.c:1.1.1.1 krb5/appl/telnet/libtelnet/kerberos.c:1.3
*** krb5/appl/telnet/libtelnet/kerberos.c:1.1.1.1	Mon Jun  2 17:54:38 1997
--- krb5/appl/telnet/libtelnet/kerberos.c	Mon Aug 25 19:12:44 1997
***************
*** 136,148 ****
  	Authenticator *ap;
  	int server;
  {
- 	FILE *fp;
- 
  	if (server) {
  		str_data[3] = TELQUAL_REPLY;
- 		if ((fp = fopen(KEYFILE, "r")) == NULL)
- 			return(0);
- 		fclose(fp);
  	} else {
  		str_data[3] = TELQUAL_IS;
  	}
--- 136,143 ----
***************
*** 435,442 ****
  	if (UserNameRequested && !kuserok(&adat, UserNameRequested)) {
  		strcpy(name, UserNameRequested);
  		return(AUTH_VALID);
! 	} else
  		return(AUTH_USER);
  }
  
  #define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
--- 430,444 ----
  	if (UserNameRequested && !kuserok(&adat, UserNameRequested)) {
  		strcpy(name, UserNameRequested);
  		return(AUTH_VALID);
! 	} else {
! 		/*
! 		 * Always copy in UserNameRequested if the authentication
! 		 * is valid, because the higher level routines need it.
! 		 */
! 		if (UserNameRequested)
! 			strcpy(name, UserNameRequested);
  		return(AUTH_USER);
+ 	}
  }
  
  #define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
Index: appl/telnet/libtelnet/kerberos5.c
diff -c krb5/appl/telnet/libtelnet/kerberos5.c:1.1.1.3 krb5/appl/telnet/libtelnet/kerberos5.c:1.7
*** krb5/appl/telnet/libtelnet/kerberos5.c:1.1.1.3	Wed May 12 13:21:25 1999
--- krb5/appl/telnet/libtelnet/kerberos5.c	Wed May 12 14:55:50 1999
***************
*** 123,128 ****
--- 123,129 ----
  krb5_keyblock	*session_key = 0;
  char *		telnet_srvtab = NULL;
  char *		telnet_krb5_realm = NULL;
+ int		require_hwpreauth = 0;
  
  	static int
  Data(ap, type, d, c)
***************
*** 184,196 ****
  {
      krb5_error_code retval;
      krb5_ccache ccache;
      char *ccname;
      
      if (telnet_context == 0)
  	return;
  
      ccname = getenv(KRB5_ENV_CCNAME);
!     if (ccname) {
  	retval = krb5_cc_resolve(telnet_context, ccname, &ccache);
  	if (!retval)
  	    retval = krb5_cc_destroy(telnet_context, ccache);
--- 185,205 ----
  {
      krb5_error_code retval;
      krb5_ccache ccache;
+     krb5_data realm;
      char *ccname;
+     int retain_ccache = 0;
      
      if (telnet_context == 0)
  	return;
  
+     krb5_get_default_realm(telnet_context, &realm.data);
+ 
+     krb5_appdefault_boolean(telnet_context, "telnetd", &realm,
+ 			    "retain_ccache", retain_ccache, &retain_ccache);
+     krb5_xfree(realm.data);
+ 
      ccname = getenv(KRB5_ENV_CCNAME);
!     if (ccname && ! retain_ccache) {
  	retval = krb5_cc_resolve(telnet_context, ccname, &ccache);
  	if (!retval)
  	    retval = krb5_cc_destroy(telnet_context, ccache);
***************
*** 490,495 ****
--- 499,517 ----
  				      ticket->enc_part2 ->client,
  				      &name))
  			name = 0;
+ 		
+ 		/*
+ 		 * Sigh, if we have the require_hwpreauth flag, then
+ 		 * reject this ticket if we don't have the hwpreauth
+ 		 * ticket flag set
+ 		 */
+ 		
+ 		if (require_hwpreauth && !(ticket->enc_part2->flags &
+ 					   TKT_FLG_HW_AUTH)) {
+ 			(void) strcpy(errbuf, "No hardware preauth flag set");
+ 			goto errout;
+ 		}
+ 
  		Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
  		if (auth_debug_mode) {
  			printf(
***************
*** 682,689 ****
  	{
  		strcpy(name, UserNameRequested);
  		return(AUTH_VALID);
! 	} else
  		return(AUTH_USER);
  }
  
  #define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
--- 704,719 ----
  	{
  		strcpy(name, UserNameRequested);
  		return(AUTH_VALID);
! 	} else {
! 		/*
! 		 * Always copy in UserNameRequested if the authentication
! 		 * is valid, because the higher level routines need it.
! 		 */
! 		if (UserNameRequested)
! 			strcpy(name, UserNameRequested);
! 
  		return(AUTH_USER);
+ 	}
  }
  
  #define	BUMP(buf, len)		while (*(buf)) {++(buf), --(len);}
***************
*** 804,812 ****
  				server, ccache,
  				forward_flags & OPTS_FORWARDABLE_CREDS,
  				&forw_creds))) {
! 	if (auth_debug_mode) 
! 	    printf("Kerberos V5: error getting forwarded creds - %s\r\n",
! 	  	   error_message(r));
  	goto cleanup;
      }
      
--- 834,841 ----
  				server, ccache,
  				forward_flags & OPTS_FORWARDABLE_CREDS,
  				&forw_creds))) {
! 	printf("Kerberos V5: error getting forwarded creds - %s\r\n",
! 	       error_message(r));
  	goto cleanup;
      }
      
***************
*** 830,833 ****
--- 859,887 ----
  }
  #endif	/* FORWARD */
  
+ void
+ kerberos5_defaults(opts)
+ 	struct config_opts *opts;
+ {
+ 	struct config_opts *opt;
+ 	krb5_data realm;
+ 
+ 	if (!telnet_context) {
+ 		krb5_init_context(&telnet_context);
+ 		krb5_init_ets(telnet_context);
+ 	}
+ 
+ 	if (! telnet_krb5_realm) {
+ 		krb5_get_default_realm(telnet_context, &realm.data);
+ 	} else {
+ 		realm.data = strdup(telnet_krb5_realm);
+ 	}
+ 
+ 	for (opt = opts; opt->optname != 0; opt++)
+ 		krb5_appdefault_boolean(telnet_context, "telnet", &realm,
+ 					opt->optname, *(opt->optvar),
+ 					opt->optvar);
+ 
+ 	free(realm.data);
+ }
  #endif /* KRB5 */
Index: appl/telnet/telnet/Makefile.in
diff -c krb5/appl/telnet/telnet/Makefile.in:1.1.1.1 krb5/appl/telnet/telnet/Makefile.in:1.2
*** krb5/appl/telnet/telnet/Makefile.in:1.1.1.1	Mon Jun  2 17:54:41 1997
--- krb5/appl/telnet/telnet/Makefile.in	Tue Jul 29 15:26:32 1997
***************
*** 20,26 ****
  #	@(#)Makefile.generic	5.5 (Berkeley) 3/1/91
  #
  
! AUTH_DEF=-DAUTHENTICATION -DENCRYPTION -DKRB5 -DFORWARD -UNO_LOGIN_F -DLOGIN_CAP_F -DLOGIN_PROGRAM=KRB5_PATH_LOGIN
  OTHERDEFS=-DLINEMODE -DKLUDGELINEMODE -DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON
  LOCALINCLUDES=-I.. -I$(srcdir)/..
  CFLAGS = $(CCOPTS) $(AUTH_DEF) $(OTHERDEFS) $(DEFS) $(LOCALINCLUDES)
--- 20,26 ----
  #	@(#)Makefile.generic	5.5 (Berkeley) 3/1/91
  #
  
! AUTH_DEF=-DAUTHENTICATION -DKRB5 -DFORWARD -UNO_LOGIN_F -DLOGIN_CAP_F -DLOGIN_PROGRAM=KRB5_PATH_LOGIN
  OTHERDEFS=-DLINEMODE -DKLUDGELINEMODE -DDIAGNOSTICS -DENV_HACK -DOLD_ENVIRON
  LOCALINCLUDES=-I.. -I$(srcdir)/..
  CFLAGS = $(CCOPTS) $(AUTH_DEF) $(OTHERDEFS) $(DEFS) $(LOCALINCLUDES)
Index: appl/telnet/telnet/commands.c
diff -c krb5/appl/telnet/telnet/commands.c:1.1.1.1 krb5/appl/telnet/telnet/commands.c:1.3
*** krb5/appl/telnet/telnet/commands.c:1.1.1.1	Mon Jun  2 17:54:41 1997
--- krb5/appl/telnet/telnet/commands.c	Fri Sep  5 11:24:49 1997
***************
*** 1719,1736 ****
  	/*
  	 * Special case for DISPLAY variable.  If it is ":0.0" or
  	 * "unix:0.0", we have to get rid of "unix" and insert our
! 	 * hostname.
  	 */
  	if ((ep = env_find("DISPLAY"))
  	    && ((*ep->value == ':')
  	        || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
  		char hbuf[256+1];
  		char *cp2 = strchr((char *)ep->value, ':');
  
  		gethostname(hbuf, 256);
  		hbuf[256] = '\0';
! 		cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
! 		sprintf((char *)cp, "%s%s", hbuf, cp2);
  		free(ep->value);
  		ep->value = (unsigned char *)cp;
  	}
--- 1719,1739 ----
  	/*
  	 * Special case for DISPLAY variable.  If it is ":0.0" or
  	 * "unix:0.0", we have to get rid of "unix" and insert our
! 	 * hostname.  Make it a FQDN if possible.
  	 */
  	if ((ep = env_find("DISPLAY"))
  	    && ((*ep->value == ':')
  	        || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
  		char hbuf[256+1];
+ 		struct hostent *hp;
  		char *cp2 = strchr((char *)ep->value, ':');
  
  		gethostname(hbuf, 256);
  		hbuf[256] = '\0';
! 		hp = gethostbyname(hbuf);
! 		cp = (char *)malloc(strlen(hp ? hp->h_name : hbuf) +
! 				    strlen(cp2) + 1);
! 		sprintf((char *)cp, "%s%s", hp ? hp->h_name : hbuf, cp2);
  		free(ep->value);
  		ep->value = (unsigned char *)cp;
  	}
***************
*** 2507,2514 ****
  	}
  	telnetport = 1;
      }
-     printf("Trying %s...\r\n", inet_ntoa(sin.sin_addr));
      do {
  	net = socket(AF_INET, SOCK_STREAM, 0);
  	setuid(getuid());
  	if (net < 0) {
--- 2510,2517 ----
  	}
  	telnetport = 1;
      }
      do {
+ 	printf("Trying %s...\r\n", inet_ntoa(sin.sin_addr));
  	net = socket(AF_INET, SOCK_STREAM, 0);
  	setuid(getuid());
  	if (net < 0) {
Index: appl/telnet/telnet/configure.in
diff -c krb5/appl/telnet/telnet/configure.in:1.1.1.2 krb5/appl/telnet/telnet/configure.in:1.3
*** krb5/appl/telnet/telnet/configure.in:1.1.1.2	Wed May 12 13:21:30 1999
--- krb5/appl/telnet/telnet/configure.in	Wed May 12 14:55:51 1999
***************
*** 45,50 ****
--- 45,57 ----
  	DEPKRB4_CRYPTO_LIB='$(TOPLIBD)/libdes425.a'
  fi
  dnl
+ dnl Do we want to exclude session encryption?
+ do_encrypt=yes
+ AC_ARG_WITH([session-encrypt],[],do_encrypt=$withval)
+ if test $do_encrypt = yes; then
+ 	AC_DEFINE(ENCRYPTION)
+ fi
+ dnl
  USE_KRB4_LIBRARY
  USE_ANAME
  KRB5_LIBRARIES
Index: appl/telnet/telnet/externs.h
diff -c krb5/appl/telnet/telnet/externs.h:1.1.1.1 krb5/appl/telnet/telnet/externs.h:1.2
*** krb5/appl/telnet/telnet/externs.h:1.1.1.1	Mon Jun  2 17:54:42 1997
--- krb5/appl/telnet/telnet/externs.h	Mon Jun  2 18:34:15 1997
***************
*** 77,83 ****
  #if defined(USE_TERMIO) && !defined(SYSV_TERMIO)
  # define termio termios
  #endif
! #if defined(NO_CC_T) || !defined(USE_TERMIO)
  # if !defined(USE_TERMIO)
  typedef char cc_t;
  # else
--- 77,83 ----
  #if defined(USE_TERMIO) && !defined(SYSV_TERMIO)
  # define termio termios
  #endif
! #if defined(NO_CC_T)
  # if !defined(USE_TERMIO)
  typedef char cc_t;
  # else
Index: appl/telnet/telnet/main.c
diff -c krb5/appl/telnet/telnet/main.c:1.1.1.1 krb5/appl/telnet/telnet/main.c:1.5
*** krb5/appl/telnet/telnet/main.c:1.1.1.1	Mon Jun  2 17:54:42 1997
--- krb5/appl/telnet/telnet/main.c	Wed Sep 10 17:07:01 1997
***************
*** 48,53 ****
--- 48,54 ----
  #include "ring.h"
  #include "externs.h"
  #include "defines.h"
+ #include <libtelnet/auth.h>
  
  
  #if 0
***************
*** 103,108 ****
--- 104,123 ----
  	exit(1);
  }
  
+ #ifdef KRB5
+ static int forward = 0, forwardable = 0;
+ static int encrypt = 0, forceencrypt = 0;
+ 
+ static struct config_opts c_opts[] = {
+ 	"forward", &forward,
+ 	"forwardable", &forwardable,
+ 	"encrypt", &encrypt,
+ 	"autologin", &autologin,
+ 	"forceencrypt", &forceencrypt,
+ 	NULL, NULL,
+ };
+ #endif
+ 
  /*
   * main.  Parse arguments, invoke the protocol or command parser.
   */
***************
*** 110,115 ****
--- 125,131 ----
  /* see forward.c -- indicate that we're in telnet, not telnetd. */
  char *line = 0;
  
+ 
  main(argc, argv)
  	int argc;
  	char *argv[];
***************
*** 120,125 ****
--- 136,142 ----
  	char *user;
  #ifdef	FORWARD
  	extern int forward_flags;
+ 	int opt_forward = 0, opt_forwardable = 0;
  #endif	/* FORWARD */
  #ifdef ENCRYPTION
  	extern int auth_enable_encrypt;
***************
*** 142,148 ****
  	rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
  	autologin = -1;
  
! 	while ((ch = getopt(argc, argv, "8EKLS:X:acde:fFk:l:n:rt:x")) != EOF) {
  		switch(ch) {
  		case '8':
  			eight = 3;	/* binary output and input */
--- 159,173 ----
  	rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
  	autologin = -1;
  
! #ifdef KRB5
! 	/*
! 	 * Get the defaults from the Kerberos 5 profile, if we have one
! 	 */
! 	
! 	kerberos5_defaults(c_opts);
! #endif /* KRB5 */
! 
! 	while ((ch = getopt(argc, argv, "8EKLNS:X:acde:fFk:l:n:rt:x")) != EOF) {
  		switch(ch) {
  		case '8':
  			eight = 3;	/* binary output and input */
***************
*** 158,163 ****
--- 183,198 ----
  		case 'L':
  			eight |= 2;	/* binary output only */
  			break;
+ 		case 'N':
+ #if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD)
+ 			opt_forward = forward = 0;
+ 			opt_forwardable = forwardable = 0;
+ #else
+ 			fprintf(stderr,
+ 			 "%s: Warning: -N ignored, no Kerberos V5 support.\n", 
+ 				prompt);
+ #endif
+ 		break;
  		case 'S':
  		    {
  #if defined(HAS_GETTOS) || (defined(IPPROTO_IP) && defined(IP_TOS))
***************
*** 196,208 ****
  			break;
  		case 'f':
  #if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD)
! 			if (forward_flags & OPTS_FORWARD_CREDS) {
  			    fprintf(stderr, 
  				    "%s: Only one of -f and -F allowed.\n",
  				    prompt);
  			    usage();
  			}
! 			forward_flags |= OPTS_FORWARD_CREDS;
  #else
  			fprintf(stderr,
  			 "%s: Warning: -f ignored, no Kerberos V5 support.\n", 
--- 231,243 ----
  			break;
  		case 'f':
  #if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD)
! 			if (opt_forwardable) {
  			    fprintf(stderr, 
  				    "%s: Only one of -f and -F allowed.\n",
  				    prompt);
  			    usage();
  			}
! 			opt_forward = 1;
  #else
  			fprintf(stderr,
  			 "%s: Warning: -f ignored, no Kerberos V5 support.\n", 
***************
*** 211,224 ****
  			break;
  		case 'F':
  #if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD)
! 			if (forward_flags & OPTS_FORWARD_CREDS) {
  			    fprintf(stderr, 
  				    "%s: Only one of -f and -F allowed.\n",
  				    prompt);
  			    usage();
  			}
! 			forward_flags |= OPTS_FORWARD_CREDS;
! 			forward_flags |= OPTS_FORWARDABLE_CREDS;
  #else
  			fprintf(stderr,
  			 "%s: Warning: -F ignored, no Kerberos V5 support.\n", 
--- 246,258 ----
  			break;
  		case 'F':
  #if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD)
! 			if (opt_forward) {
  			    fprintf(stderr, 
  				    "%s: Only one of -f and -F allowed.\n",
  				    prompt);
  			    usage();
  			}
! 			opt_forwardable = 1;
  #else
  			fprintf(stderr,
  			 "%s: Warning: -F ignored, no Kerberos V5 support.\n", 
***************
*** 282,296 ****
  			break;
  		case 'x':
  #ifdef	ENCRYPTION
! 			encrypt_auto(1);
! 			decrypt_auto(1);
! 			wantencryption = 1;
! 			autologin = 1;
! 			auth_enable_encrypt = 1;
  #else
  			fprintf(stderr,
! 			    "%s: Warning: -x ignored, no ENCRYPT support.\n",
  								prompt);
  #endif
  			break;
  		case '?':
--- 316,328 ----
  			break;
  		case 'x':
  #ifdef	ENCRYPTION
! 			encrypt = 1;
! 			forceencrypt = 1;
  #else
  			fprintf(stderr,
! 			    "%s: encryption not supported.\n",
  								prompt);
+ 			exit(1);
  #endif
  			break;
  		case '?':
***************
*** 299,304 ****
--- 331,358 ----
  			/* NOTREACHED */
  		}
  	}
+ 
+ #if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD)
+ 	if (opt_forward || forward) {
+ 		forward_flags |= OPTS_FORWARD_CREDS;
+ 	}
+ 	if (opt_forwardable || forwardable) {
+ 		forward_flags |= OPTS_FORWARD_CREDS;
+ 		forward_flags |= OPTS_FORWARDABLE_CREDS;
+ 	}
+ #endif /* AUTH and KRB5 and FORWARD */
+ 
+ #ifdef  ENCRYPTION
+ 	if (encrypt) {
+ 		encrypt_auto(1);
+ 		decrypt_auto(1);
+ 		if (forceencrypt)
+ 			wantencryption = 1;
+ 		autologin = 1;
+ 		auth_enable_encrypt = 1;
+ 	}
+ #endif
+ 
  	if (autologin == -1)
  		autologin = (rlogin == _POSIX_VDISABLE) ? 0 : 1;
  
Index: appl/telnet/telnet/telnet.c
diff -c krb5/appl/telnet/telnet/telnet.c:1.1.1.1 krb5/appl/telnet/telnet/telnet.c:1.2
*** krb5/appl/telnet/telnet/telnet.c:1.1.1.1	Mon Jun  2 17:54:43 1997
--- krb5/appl/telnet/telnet/telnet.c	Wed Sep 10 17:07:04 1997
***************
*** 2271,2287 ****
      }
  #endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION)  */
  #   if !defined(TN3270)
  #if	defined(AUTHENTICATION)
!     if (autologin)
! 	send_will(TELOPT_AUTHENTICATION, 1);
  #endif
  #ifdef	ENCRYPTION
-     if (telnetport || wantencryption) {
  	send_do(TELOPT_ENCRYPT, 1);
  	send_will(TELOPT_ENCRYPT, 1);
-     }
  #endif	/* ENCRYPTION */
-     if (telnetport) {
  	send_do(TELOPT_SGA, 1);
  	send_will(TELOPT_TTYPE, 1);
  	send_will(TELOPT_NAWS, 1);
--- 2271,2285 ----
      }
  #endif	/* defined(AUTHENTICATION) || defined(ENCRYPTION)  */
  #   if !defined(TN3270)
+     if (telnetport) {
  #if	defined(AUTHENTICATION)
! 	if (autologin)
! 	    send_will(TELOPT_AUTHENTICATION, 1);
  #endif
  #ifdef	ENCRYPTION
  	send_do(TELOPT_ENCRYPT, 1);
  	send_will(TELOPT_ENCRYPT, 1);
  #endif	/* ENCRYPTION */
  	send_do(TELOPT_SGA, 1);
  	send_will(TELOPT_TTYPE, 1);
  	send_will(TELOPT_NAWS, 1);
***************
*** 2308,2313 ****
--- 2306,2313 ----
  	extern int auth_has_failed;
  	time_t timeout = time(0) + 60;
  
+ 	if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
+ 		send_will(TELOPT_AUTHENTICATION, 1);
  	send_do(TELOPT_ENCRYPT, 1);
  	send_will(TELOPT_ENCRYPT, 1);
  	while (1) {
***************
*** 2335,2340 ****
--- 2335,2341 ----
  	    if (printed_encrypt == 0) {
  		    printed_encrypt = 1;
  		    printf("Waiting for encryption to be negotiated...");
+ 		    fflush(stdout);
  		    /*
  		     * Turn on MODE_TRAPSIG and then turn off localchars 
  		     * so that ^C will cause telnet to exit.
Index: appl/telnet/telnetd/configure.in
diff -c krb5/appl/telnet/telnetd/configure.in:1.1.1.2 krb5/appl/telnet/telnetd/configure.in:1.4
*** krb5/appl/telnet/telnetd/configure.in:1.1.1.2	Wed May 12 13:21:35 1999
--- krb5/appl/telnet/telnetd/configure.in	Wed May 12 14:55:52 1999
***************
*** 25,30 ****
--- 25,32 ----
  AC_HEADER_TIME
  AC_CHECK_HEADERS(string.h arpa/nameser.h)
  AC_CHECK_HEADERS(sys/time.h sys/tty.h)
+ AC_CHECK_HEADERS(sys/utsname.h)
+ AC_CHECK_HEADERS(sys/termio.h)
  AC_HAVE_FUNCS(vhangup)
  dnl Make our operating system-specific security checks and definitions for
  dnl login.
***************
*** 44,49 ****
--- 46,55 ----
       # Irix doesn't have a working granpt, and more over
       # you can't push anything onto a pty, so telnetd really
       # Really wants to treat it as if it doesn't have streams
+      broken_streams=yes
+      ;;
+ *-*-aix*)
+      # ioctl(pty, I_PUSH, "pckt") fails under AIX 4.1, 4.2 and 4.3 (at least)
       broken_streams=yes
       ;;
  esac
Index: appl/telnet/telnetd/ext.h
diff -c krb5/appl/telnet/telnetd/ext.h:1.1.1.2 krb5/appl/telnet/telnetd/ext.h:1.3
*** krb5/appl/telnet/telnetd/ext.h:1.1.1.2	Wed Feb 25 17:23:34 1998
--- krb5/appl/telnet/telnetd/ext.h	Thu Feb 26 11:38:34 1998
***************
*** 234,240 ****
  #   ifdef ultrix
  #    define DEFAULT_IM	"\r\n\r\nULTRIX (%h) (%t)\r\n\r\r\n\r"
  #   else
! #    define DEFAULT_IM	"\r\n\r\n4.4 BSD UNIX (%h) (%t)\r\n\r\r\n\r"
  #   endif
  #  endif
  # endif
--- 234,248 ----
  #   ifdef ultrix
  #    define DEFAULT_IM	"\r\n\r\nULTRIX (%h) (%t)\r\n\r\r\n\r"
  #   else
! #    ifdef sgi
! #     define DEFAULT_IM "\r\n\r\nIRIX (%h) (%t)\r\n\r\r\n\r"
! #    else
! #     if defined(hpux) || defined(__hpux)
! #      define DEFAULT_IM "\r\n\r\nHP/UX (%h) (%t)\r\n\r\r\n\r"
! #     else
! #      define DEFAULT_IM	"\r\n\r\n4.4 BSD UNIX (%h) (%t)\r\n\r\r\n\r"
! #     endif
! #    endif
  #   endif
  #  endif
  # endif
Index: appl/telnet/telnetd/sys_term.c
diff -c krb5/appl/telnet/telnetd/sys_term.c:1.1.1.3 krb5/appl/telnet/telnetd/sys_term.c:1.3
*** krb5/appl/telnet/telnetd/sys_term.c:1.1.1.3	Wed May 12 13:21:36 1999
--- krb5/appl/telnet/telnetd/sys_term.c	Wed May 12 14:55:52 1999
***************
*** 1068,1073 ****
--- 1068,1075 ----
  		autologin = 0;
  
  	if (autologin < auth_level) {
+ 		syslog(LOG_ERR,
+ 		       "Rejected connection that lacked needed preauthentication");
  		fatal(net, "Authorization failed");
  		exit(1);
  	}
Index: appl/telnet/telnetd/telnetd.8
diff -c krb5/appl/telnet/telnetd/telnetd.8:1.1.1.2 krb5/appl/telnet/telnetd/telnetd.8:1.4
*** krb5/appl/telnet/telnetd/telnetd.8:1.1.1.2	Wed May 12 13:21:37 1999
--- krb5/appl/telnet/telnetd/telnetd.8	Wed May 12 14:55:53 1999
***************
*** 40,45 ****
--- 40,46 ----
  .B /usr/libexec/telnetd
  [\fB\-a\fP \fIauthmode\fP] [\fB\-B\fP] [\fB\-D\fP] [\fIdebugmode\fP]
  [\fB\-edebug\fP] [\fB\-h\fP] [\fB\-I\fP\fIinitid\fP] [\fB\-l\fP]
+ [\fB\-L\fP \fIlogin_program\fP]
  [\fB\-k\fP] [\fB\-n\fP] [\fB\-r\fP\fIlowpty-highpty\fP] [\fB\-s\fP]
  [\fB\-S\fP \fItos\fP] [\fB\-U\fP] [\fB\-X\fP \fIauthtype\fP]
  [\fB\-w\fP [\fBip\fP|\fImaxhostlen\fP[\fB,\fP[\fBno\fP]\fBstriplocal\fP]]]
***************
*** 92,103 ****
  .B debug
  Turns on authentication debugging code.
  .TP
! .B user
  Only allow connections when the remote user can provide valid
  authentication information to identify the remote user, and is allowed
  access to the specified account without providing a password.
  .TP
! .B valid
  Only allow connections when the remote user can provide valid
  authentication information to identify the remote user.  The
  .IR login (1)
--- 93,104 ----
  .B debug
  Turns on authentication debugging code.
  .TP
! .B valid
  Only allow connections when the remote user can provide valid
  authentication information to identify the remote user, and is allowed
  access to the specified account without providing a password.
  .TP
! .B user
  Only allow connections when the remote user can provide valid
  authentication information to identify the remote user.  The
  .IR login (1)
***************
*** 227,232 ****
--- 228,236 ----
  mode.  If the
  .SM LINEMODE
  option is not supported, it will go into kludge linemode.
+ .TP
+ \fB\-L\fP \fIlogin_program\fP
+ This options allows specification of the login program to run.
  .TP
  .B \-n
  Disable
Index: appl/telnet/telnetd/telnetd.c
diff -c krb5/appl/telnet/telnetd/telnetd.c:1.1.1.4 krb5/appl/telnet/telnetd/telnetd.c:1.3
*** krb5/appl/telnet/telnetd/telnetd.c:1.1.1.4	Wed May 12 13:21:38 1999
--- krb5/appl/telnet/telnetd/telnetd.c	Wed May 12 14:55:53 1999
***************
*** 179,185 ****
  	's',
  #endif
  #ifdef KRB5
! 	'R', ':', 't', ':',
  #endif
  	'\0'
  };
--- 179,185 ----
  	's',
  #endif
  #ifdef KRB5
! 	'R', ':', 't', ':', 'H',
  #endif
  	'\0'
  };
***************
*** 297,302 ****
--- 297,312 ----
  		case 'h':
  			hostinfo = 0;
  			break;
+ 
+ #ifdef KRB5
+ 		case 'H':
+ 		    {
+ 			extern int require_hwpreauth;
+ 
+ 			require_hwpreauth = 1;
+ 			break;
+ 		    }
+ #endif /* KRB5 */
  
  #if	defined(CRAY) && defined(NEWINIT)
  		case 'I':
Index: appl/telnet/telnetd/termios-tn.c
diff -c krb5/appl/telnet/telnetd/termios-tn.c:1.1.1.2 krb5/appl/telnet/telnetd/termios-tn.c:1.3
*** krb5/appl/telnet/telnetd/termios-tn.c:1.1.1.2	Wed May 12 13:21:39 1999
--- krb5/appl/telnet/telnetd/termios-tn.c	Wed May 12 14:55:53 1999
***************
*** 5,11 ****
  #include <sys/stream.h>
  #include <sys/ioctl.h>
  #include <termios.h>
! #if !defined(TCSETS) && defined(_AIX) /* kludge for AIX */
  #include <termio.h>
  #endif
  
--- 5,11 ----
  #include <sys/stream.h>
  #include <sys/ioctl.h>
  #include <termios.h>
! #if defined(HAVE_SYS_TERMIO_H) || (!defined(TCSETS) && defined(_AIX))
  #include <termio.h>
  #endif
  
Index: appl/telnet/telnetd/utility.c
diff -c krb5/appl/telnet/telnetd/utility.c:1.1.1.1 krb5/appl/telnet/telnetd/utility.c:1.3
*** krb5/appl/telnet/telnetd/utility.c:1.1.1.1	Mon Jun  2 17:54:47 1997
--- krb5/appl/telnet/telnetd/utility.c	Wed Feb  4 15:26:23 1998
***************
*** 35,40 ****
--- 35,43 ----
  
  #define PRINTOPTIONS
  #include "telnetd.h"
+ #ifdef HAVE_SYS_UTSNAME_H
+ #include <sys/utsname.h>
+ #endif /* HAVE_SYS_UTSNAME_H */
  
  /*
   * utility functions performing io related tasks
***************
*** 367,373 ****
  	int f;
  	const char *msg;
  {
! 	char buf[BUFSIZ], *strerror();
  
  	(void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno));
  	fatal(f, buf);
--- 370,380 ----
  	int f;
  	const char *msg;
  {
! 	char buf[BUFSIZ];
! #ifndef __convex__
! 	/* strerror() is a macro under ConvexOS */
! 	char *strerror();
! #endif /* __convex__*/
  
  	(void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno));
  	fatal(f, buf);
***************
*** 448,453 ****
--- 455,465 ----
  	char *slash;
  	time_t t;
  	char db[100];
+ #ifdef HAVE_SYS_UTSNAME_H
+ 	struct utsname utsinfo;
+ 
+ 	uname(&utsinfo);
+ #endif /* HAVE_SYS_UTSNAME_H */
  
  	putlocation = where;
  
***************
*** 480,485 ****
--- 492,515 ----
  			(void)strftime(db, sizeof(db), fmtstr, localtime(&t));
  			putstr(db);
  			break;
+ 
+ #ifdef HAVE_SYS_UTSNAME_H
+ 		case 's':
+ 			putstr(utsinfo.sysname);
+ 			break;
+ 
+ 		case 'm':
+ 			putstr(utsinfo.machine);
+ 			break;
+ 
+ 		case 'r':
+ 			putstr(utsinfo.release);
+ 			break;
+ 
+ 		case 'v':
+ 			putstr(utsinfo.version);
+ 			break;
+ #endif /* HAVE_SYS_UTSNAME_H */
  
  		case '%':
  			putchr('%');
Index: appl/user_user/client.c
diff -c krb5/appl/user_user/client.c:1.1.1.1 krb5/appl/user_user/client.c:1.2
*** krb5/appl/user_user/client.c:1.1.1.1	Mon Jun  2 17:54:48 1997
--- krb5/appl/user_user/client.c	Wed Sep 30 17:31:27 1998
***************
*** 83,89 ****
--- 83,94 ----
  
    if ((host = gethostbyname (argv[1])) == NULL)
      {
+ #ifndef h_errno
+       /*
+        * Under AIX h_errno is a macro. This should really be a feature test.
+        */
        extern int h_errno;
+ #endif /* h_errno */
  
        if (h_errno == HOST_NOT_FOUND)
  	fprintf (stderr, "uu-client: unknown host \"%s\".\n", argv[1]);
Index: clients/kinit/Makefile.in
diff -c krb5/clients/kinit/Makefile.in:1.1.1.1 krb5/clients/kinit/Makefile.in:1.2
*** krb5/clients/kinit/Makefile.in:1.1.1.1	Mon Jun  2 17:54:53 1997
--- krb5/clients/kinit/Makefile.in	Mon Jun  2 18:34:21 1997
***************
*** 1,4 ****
! CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
  
  all::
  
--- 1,4 ----
! CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE) -DKPROGDIR=\"$(CLIENT_BINDIR)\"
  
  all::
  
Index: clients/kinit/kinit.c
diff -c krb5/clients/kinit/kinit.c:1.1.1.1 krb5/clients/kinit/kinit.c:1.8
*** krb5/clients/kinit/kinit.c:1.1.1.1	Mon Jun  2 17:54:53 1997
--- krb5/clients/kinit/kinit.c	Thu Sep 23 13:38:37 1999
***************
*** 61,67 ****
      char *cache_name = NULL;		/* -f option */
      char *keytab_name = NULL;		/* -t option */
      char *service_name = NULL;		/* -s option */
!     krb5_deltat lifetime = KRB5_DEFAULT_LIFE;	/* -l option */
      krb5_timestamp starttime = 0;
      krb5_deltat rlife = 0;
      int options = KRB5_DEFAULT_OPTIONS;
--- 61,67 ----
      char *cache_name = NULL;		/* -f option */
      char *keytab_name = NULL;		/* -t option */
      char *service_name = NULL;		/* -s option */
!     krb5_deltat lifetime = 0;	/* -l option */
      krb5_timestamp starttime = 0;
      krb5_deltat rlife = 0;
      int options = KRB5_DEFAULT_OPTIONS;
***************
*** 78,84 ****
--- 78,89 ----
      krb5_keytab keytab = NULL;
      struct passwd *pw = 0;
      int pwsize;
+     int not_forward = 0;
+     int run_aklog = 0;
+     int not_run_aklog = 0;
      char password[255], *client_name, prompt[255];
+     krb5_kdc_rep *kdc_rep = 0;
+     krb5_last_req_entry **last_req;
  
      code = krb5_init_context(&kcontext);
      if (code) {
***************
*** 94,101 ****
      if (strrchr(argv[0], '/'))
  	argv[0] = strrchr(argv[0], '/')+1;
  
!     while ((option = getopt(argc, argv, "r:Rfpl:s:c:kt:vS:")) != EOF) {
  	switch (option) {
  	case 'r':
  	    options |= KDC_OPT_RENEWABLE;
  	    code = krb5_string_to_deltat(optarg, &rlife);
--- 99,112 ----
      if (strrchr(argv[0], '/'))
  	argv[0] = strrchr(argv[0], '/')+1;
  
!     while ((option = getopt(argc, argv, "aAr:RfFphl:s:c:kt:vS:")) != EOF) {
  	switch (option) {
+ 	case 'a':
+ 	    run_aklog = 1;
+ 	    break;
+ 	case 'A':
+ 	    not_run_aklog = 1;
+ 	    break;
  	case 'r':
  	    options |= KDC_OPT_RENEWABLE;
  	    code = krb5_string_to_deltat(optarg, &rlife);
***************
*** 119,125 ****
  	    options |= KDC_OPT_PROXIABLE;
  	    break;
  	case 'f':
! 	    options |= KDC_OPT_FORWARDABLE;
  	    break;
  #ifndef NO_KEYTAB
         case 'k':
--- 130,152 ----
  	    options |= KDC_OPT_PROXIABLE;
  	    break;
  	case 'f':
! 	    if (not_forward) {
! 		fprintf(stderr, "Cannot use both -f and -F.\n");
! 		errflg++;
! 	    } else {
! 		options |= KDC_OPT_FORWARDABLE;
! 	    }
! 	    break;
! 	case 'F':
! 	    if (options & KDC_OPT_FORWARDABLE) {
! 		fprintf(stderr, "Cannot use both -f and -F.\n");
! 		errflg++;
! 	    } else {
! 		not_forward = 1;
! 	    }
! 	    break;
! 	case 'h':
! 	    options |= KDC_OPT_HW_AUTH;
  	    break;
  #ifndef NO_KEYTAB
         case 'k':
***************
*** 186,191 ****
--- 213,228 ----
  	}
      }
  
+     if (run_aklog && not_run_aklog) {
+ 	fprintf(stderr, "Cannot use both -a and -A.\n");
+ 	errflg++;
+     }
+ 
+     if (run_aklog && starttime) {
+ 	fprintf(stderr, "Cannout use both -a and -s.\n");
+ 	errflg++;
+     }
+ 
      if (argc - optind > 1) {
  	fprintf(stderr, "Extra arguments (starting with \"%s\").\n",
  		argv[optind+1]);
***************
*** 193,199 ****
      }
  
      if (errflg) {
! 	fprintf(stderr, "Usage: %s [-r time] [-R] [-s time] [-v] [-puf] [-l lifetime] [-c cachename] [-k] [-t keytab] [-S target_service] [principal]\n", argv[0]);
  	exit(2);
      }
  
--- 230,236 ----
      }
  
      if (errflg) {
! 	fprintf(stderr, "Usage: %s [-a|-A] [-r time] [-R] [-s time] [-v] [-puf] [-l lifetime] [-c cachename] [-k] [-t keytab] [-S target_service] [principal]\n", argv[0]);
  	exit(2);
      }
  
***************
*** 278,286 ****
--- 315,353 ----
  	
      my_creds.server = server;
  
+     {
+       int forward;
+       krb5_appdefault_boolean(kcontext, "kinit", krb5_princ_realm(kcontext,me),
+ 					"forwardable", 0, &forward);
+ 	if (forward && ! not_forward)
+ 		options |= KDC_OPT_FORWARDABLE;
+     }
+ 
+     if (!lifetime) {
+       char *lifetimestring;
+       krb5_appdefault_string(kcontext, "kinit", krb5_princ_realm(kcontext,me),
+ 			     "default_lifetime", "", &lifetimestring);
+       if (lifetimestring[0]) {
+ 	code = krb5_string_to_deltat(lifetimestring, &lifetime);
+ 	if (code != 0 || lifetime == 0) {
+ 	  fprintf(stderr, "Bad lifetime value: %s\n", lifetimestring);
+ 	  exit(1);
+ 	}
+       }
+       else lifetime = KRB5_DEFAULT_LIFE;
+       free(lifetimestring);
+     }
+ 
+     if (!run_aklog && !not_run_aklog) {
+ 	krb5_appdefault_boolean(kcontext, "kinit",
+ 				krb5_princ_realm(kcontext,me),
+ 				"krb5_run_aklog", 0, &run_aklog);
+     }
+ 
      if (options & KDC_OPT_POSTDATED) {
        my_creds.times.starttime = starttime;
        my_creds.times.endtime = starttime + lifetime;
+       not_run_aklog = 1;
      } else {
        my_creds.times.starttime = 0;	/* start timer when request
  					   gets to KDC */
***************
*** 300,307 ****
  	  com_err (argv[0], code, "validating tgt");
  	  exit(1);
  	}
! 	/* should be done... */
! 	exit(0);
      }
  
      if (options & KDC_OPT_RENEW) {
--- 367,373 ----
  	  com_err (argv[0], code, "validating tgt");
  	  exit(1);
  	}
! 	goto maybe_aklog;
      }
  
      if (options & KDC_OPT_RENEW) {
***************
*** 313,320 ****
  	  com_err (argv[0], code, "renewing tgt");
  	  exit(1);
  	}
! 	/* should be done... */
! 	exit(0);
      }
  #ifndef NO_KEYTAB
      if (!use_keytab)
--- 379,385 ----
  	  com_err (argv[0], code, "renewing tgt");
  	  exit(1);
  	}
! 	goto maybe_aklog;
      }
  #ifndef NO_KEYTAB
      if (!use_keytab)
***************
*** 334,340 ****
  
  	 code = krb5_get_in_tkt_with_password(kcontext, options, addrs,
  					      NULL, preauth, password, 0,
! 					      &my_creds, 0);
  	 memset(password, 0, sizeof(password));
  #ifndef NO_KEYTAB
      } else {
--- 399,405 ----
  
  	 code = krb5_get_in_tkt_with_password(kcontext, options, addrs,
  					      NULL, preauth, password, 0,
! 					      &my_creds, &kdc_rep);
  	 memset(password, 0, sizeof(password));
  #ifndef NO_KEYTAB
      } else {
***************
*** 351,356 ****
--- 416,459 ----
  	    com_err (argv[0], code, "while getting initial credentials");
  	exit(1);
      }
+     /*
+      * Check for upcoming password expiration
+      */
+ 
+     if (kdc_rep) {
+ 	if (kdc_rep->enc_part2 && kdc_rep->enc_part2->last_req) {
+ 	    for (last_req = kdc_rep->enc_part2->last_req; *last_req;
+ 		 last_req++) {
+ 		if ((*last_req)->lr_type == KRB5_LRQ_PW_EXPTIME) {
+ 		    krb5_deltat delta;
+ 		    char tempbuf[256];
+ 		    float fdelta;
+ 
+ 		    delta = (*last_req)->value - now;
+ 
+ 		    /*
+ 		     * Different messages for hours and days
+ 		     */
+ 
+ 		    if (delta >= 60*60*24) {
+ 			fdelta = ((float) delta) / ((float) 60*60*24);
+ 		    } else {
+ 			fdelta = ((float) delta) / ((float) 60*60);
+ 		    }
+ 
+ 		    if (krb5_timestamp_to_string((*last_req)->value,
+ 						 tempbuf, 256))
+ 			goto fail_warn;
+ 
+ 		    printf("WARNING: Your password will expire in %.1f %s "
+ 			   "on %s.\n", fdelta,
+ 			   delta >= 60*60*24 ? "days" : "hours", tempbuf);
+ 		}
+ 	    }
+ 	}
+ fail_warn:
+ 	krb5_free_kdc_rep(kcontext, kdc_rep);
+     }
  
      code = krb5_cc_initialize (kcontext, ccache, me);
      if (code != 0) {
***************
*** 365,375 ****
  	exit(1);
      }
  
      /* my_creds is pointing at server */
      krb5_free_principal(kcontext, server);
  
      krb5_free_context(kcontext);
!     
      exit(0);
  }
  
--- 468,501 ----
  	exit(1);
      }
  
+  maybe_aklog:
      /* my_creds is pointing at server */
      krb5_free_principal(kcontext, server);
  
+     /* Run aklog if requested */
+     if (run_aklog && !not_run_aklog) {
+ 	char *aklog_path;
+ 	struct stat st;
+ 
+ 
+ 	krb5_appdefault_string(kcontext, "kinit",
+ 			       krb5_princ_realm(kcontext,me),
+ 			       "krb5_aklog_path", KPROGDIR "/aklog",
+ 			       &aklog_path);
+ 
+ 	/*
+ 	 * Make sure it exists before we try to run it
+ 	 */
+ 	if (stat(aklog_path, &st) == 0) {
+ 	    system(aklog_path);
+ 	}
+ 
+ 	free(aklog_path);
+ 	
+     }
+ 
      krb5_free_context(kcontext);
! 
      exit(0);
  }
  
Index: clients/klist/klist.c
diff -c krb5/clients/klist/klist.c:1.1.1.1 krb5/clients/klist/klist.c:1.2
*** krb5/clients/klist/klist.c:1.1.1.1	Mon Jun  2 17:54:54 1997
--- krb5/clients/klist/klist.c	Wed Jun  3 12:15:05 1998
***************
*** 274,280 ****
   
      flags = 0;				/* turns off OPENCLOSE mode */
      if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
! 	if (code == ENOENT) {
  	    if (!status_only)
  		com_err(progname, code, "(ticket cache %s)",
  			krb5_cc_get_name(kcontext, cache));
--- 274,280 ----
   
      flags = 0;				/* turns off OPENCLOSE mode */
      if ((code = krb5_cc_set_flags(kcontext, cache, flags))) {
! 	if (code == KRB5_FCC_NOFILE) {
  	    if (!status_only)
  		com_err(progname, code, "(ticket cache %s)",
  			krb5_cc_get_name(kcontext, cache));
Index: clients/ksu/configure.in
diff -c krb5/clients/ksu/configure.in:1.1.1.2 krb5/clients/ksu/configure.in:1.4
*** krb5/clients/ksu/configure.in:1.1.1.2	Wed May 12 13:21:51 1999
--- krb5/clients/ksu/configure.in	Wed May 12 14:55:54 1999
***************
*** 3,10 ****
  AC_PROG_INSTALL
  USE_ANAME
  AC_HEADER_STDARG
! AC_CHECK_FUNCS(getusershell lstat )
  AC_CHECK_HEADERS(unistd.h)
  case $krb5_cv_host in
  alpha-dec-osf*)
  	AC_CHECK_LIB(security,setluid,
--- 3,16 ----
  AC_PROG_INSTALL
  USE_ANAME
  AC_HEADER_STDARG
! AC_CHECK_FUNCS(getusershell lstat putenv)
  AC_CHECK_HEADERS(unistd.h)
+ AC_ARG_ENABLE([irix-project-init],
+ [  --enable-irix-project-init   Initialize the IRIX project id at login
+   --disable-irix-project-init  Don't do IRIX project setup (default)],[
+ AC_MSG_RESULT(Enabling IRIX project initialization support)
+ AC_DEFINE(IRIX_PROJECT_INIT)
+ ])
  case $krb5_cv_host in
  alpha-dec-osf*)
  	AC_CHECK_LIB(security,setluid,
Index: clients/ksu/krb_auth_su.c
diff -c krb5/clients/ksu/krb_auth_su.c:1.1.1.2 krb5/clients/ksu/krb_auth_su.c:1.2
*** krb5/clients/ksu/krb_auth_su.c:1.1.1.2	Wed Feb 25 17:23:53 1998
--- krb5/clients/ksu/krb_auth_su.c	Thu Feb  5 16:10:22 1998
***************
*** 343,356 ****
  
  	/* Check to make sure ticket hasn't expired */
  	if (retval = krb5_check_exp(context, tkt->enc_part2->times)) {
! 		if (auth_debug && (retval == KRB5KRB_AP_ERR_TKT_EXPIRED)) {
! 			fprintf(stderr,
! 				"krb5_verify_tkt_def: ticket has expired");
! 		}
! 		krb5_free_ticket(context, tkt);	
! 		krb5_kt_free_entry(context, &ktentry);
! 		krb5_free_keyblock(context, tkt_key);
! 		return KRB5KRB_AP_ERR_TKT_EXPIRED;
  	}
  
  	if (!krb5_principal_compare(context, client, tkt->enc_part2->client)) {
--- 343,356 ----
  
  	/* Check to make sure ticket hasn't expired */
  	if (retval = krb5_check_exp(context, tkt->enc_part2->times)) {
! 	    if (auth_debug && (retval == KRB5KRB_AP_ERR_TKT_EXPIRED)) {
! 		fprintf(stderr,
! 			"krb5_verify_tkt_def: ticket has expired");
! 	    }
! 	    krb5_free_ticket(context, tkt);	
! 	    krb5_kt_free_entry(context, &ktentry);
! 	    krb5_free_keyblock(context, tkt_key);
! 	    return KRB5KRB_AP_ERR_TKT_EXPIRED;
  	}
  
  	if (!krb5_principal_compare(context, client, tkt->enc_part2->client)) {
Index: clients/ksu/main.c
diff -c krb5/clients/ksu/main.c:1.1.1.2 krb5/clients/ksu/main.c:1.4
*** krb5/clients/ksu/main.c:1.1.1.2	Wed May 12 13:21:53 1999
--- krb5/clients/ksu/main.c	Wed May 12 14:55:54 1999
***************
*** 793,798 ****
--- 793,808 ----
  	        exit(1);
  	}
  
+ #ifdef IRIX_PROJECT_INIT
+        /*
+ 	* Initialize the magical IRIX array session, and the
+ 	* default project id.
+ 	*/
+ 	
+        newarraysess();
+        setprid(getdfltprojuser(target_user));
+ #endif /* IRIX_PROJECT_INIT */
+ 
         if ( ! strcmp(target_user, source_user)){ 			
         		print_status("Leaving uid as %s (%d)\n",
  				 target_user, target_pwd->pw_uid); 
***************
*** 928,933 ****
--- 938,944 ----
      char *name;
      char *value;
  {
+ #ifdef HAVE_PUTENV
  char * env_var_buf;
  
  	/* allocate extra two spaces, one for the = and one for the \0 */  
***************
*** 935,941 ****
--- 946,957 ----
  					sizeof(char)); 
  
          sprintf(env_var_buf,"%s=%s",name, value);  
+ 
          return putenv(env_var_buf);
+ #else
+ 	/* Assume we have setenv() */
+ 	return setenv(name, value, 1);
+ #endif
  
  }
  
Index: config/config.guess
diff -c krb5/config/config.guess:1.1.1.1 krb5/config/config.guess:1.2
*** krb5/config/config.guess:1.1.1.1	Mon Jun  2 17:54:55 1997
--- krb5/config/config.guess	Wed Oct  8 14:30:36 1997
***************
*** 67,87 ****
      amiga:NetBSD:*:*)
        echo m68k-cbm-netbsd${UNAME_RELEASE}
        exit 0 ;;
      arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
  	echo arm-acorn-riscix${UNAME_RELEASE}
  	exit 0;;
!     Pyramid*:OSx*:*:*)
  	if test "`(/bin/universe) 2>/dev/null`" = att ; then
  		echo pyramid-pyramid-sysv3
  	else
  		echo pyramid-pyramid-bsd
  	fi
  	exit 0 ;;
!     sun4*:SunOS:5.*:*)
  	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
  	exit 0 ;;
      i86pc:SunOS:5.*:*)
! 	echo i386-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
  	exit 0 ;;
      sun4*:SunOS:6*:*)
  	# According to config.sub, this is the proper way to canonicalize
--- 67,94 ----
      amiga:NetBSD:*:*)
        echo m68k-cbm-netbsd${UNAME_RELEASE}
        exit 0 ;;
+     amiga:OpenBSD:*:*)
+       echo m68k-cbm-openbsd${UNAME_RELEASE}
+       exit 0 ;;
      arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
  	echo arm-acorn-riscix${UNAME_RELEASE}
  	exit 0;;
!     Pyramid*:OSx*:*:*|MIS*:OSx*:*:*)
! 	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
  	if test "`(/bin/universe) 2>/dev/null`" = att ; then
  		echo pyramid-pyramid-sysv3
  	else
  		echo pyramid-pyramid-bsd
  	fi
  	exit 0 ;;
!     NILE:*:*:dcosx)
! 	echo pyramid-pyramid-svr4
! 	exit 0 ;;
!     sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
  	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
  	exit 0 ;;
      i86pc:SunOS:5.*:*)
! 	echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
  	exit 0 ;;
      sun4*:SunOS:6*:*)
  	# According to config.sub, this is the proper way to canonicalize
***************
*** 101,125 ****
      sun3*:SunOS:*:*)
  	echo m68k-sun-sunos${UNAME_RELEASE}
  	exit 0 ;;
      atari*:NetBSD:*:*)
  	echo m68k-atari-netbsd${UNAME_RELEASE}
  	exit 0 ;;
      sun3*:NetBSD:*:*)
  	echo m68k-sun-netbsd${UNAME_RELEASE}
  	exit 0 ;;
      mac68k:NetBSD:*:*)
  	echo m68k-apple-netbsd${UNAME_RELEASE}
  	exit 0 ;;
      RISC*:ULTRIX:*:*)
  	echo mips-dec-ultrix${UNAME_RELEASE}
  	exit 0 ;;
      VAX*:ULTRIX*:*:*)
  	echo vax-dec-ultrix${UNAME_RELEASE}
  	exit 0 ;;
!     mips:*:4*:UMIPS)
! 	echo mips-mips-riscos4sysv
! 	exit 0 ;;
!     mips:*:5*:RISCos)
  	echo mips-mips-riscos${UNAME_RELEASE}
  	exit 0 ;;
      Night_Hawk:Power_UNIX:*:*)
--- 108,167 ----
      sun3*:SunOS:*:*)
  	echo m68k-sun-sunos${UNAME_RELEASE}
  	exit 0 ;;
+     aushp:SunOS:*:*)
+ 	echo sparc-auspex-sunos${UNAME_RELEASE}
+ 	exit 0 ;;
      atari*:NetBSD:*:*)
  	echo m68k-atari-netbsd${UNAME_RELEASE}
  	exit 0 ;;
+     atari*:OpenBSD:*:*)
+ 	echo m68k-atari-openbsd${UNAME_RELEASE}
+ 	exit 0 ;;
      sun3*:NetBSD:*:*)
  	echo m68k-sun-netbsd${UNAME_RELEASE}
  	exit 0 ;;
+     sun3*:OpenBSD:*:*)
+ 	echo m68k-sun-openbsd${UNAME_RELEASE}
+ 	exit 0 ;;
      mac68k:NetBSD:*:*)
  	echo m68k-apple-netbsd${UNAME_RELEASE}
  	exit 0 ;;
+     mac68k:OpenBSD:*:*)
+ 	echo m68k-apple-openbsd${UNAME_RELEASE}
+ 	exit 0 ;;
+     powerpc:machten:*:*)
+ 	echo powerpc-apple-machten${UNAME_RELEASE}
+ 	exit 0 ;;
+     RISC*:Mach:*:*)
+ 	echo mips-dec-mach_bsd4.3
+ 	exit 0 ;;
      RISC*:ULTRIX:*:*)
  	echo mips-dec-ultrix${UNAME_RELEASE}
  	exit 0 ;;
      VAX*:ULTRIX*:*:*)
  	echo vax-dec-ultrix${UNAME_RELEASE}
  	exit 0 ;;
!     mips:*:*:UMIPS | mips:*:*:RISCos)
! 	sed 's/^	//' << EOF >dummy.c
! 	int main (argc, argv) int argc; char **argv; {
! 	#if defined (host_mips) && defined (MIPSEB)
! 	#if defined (SYSTYPE_SYSV)
! 	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
! 	#endif
! 	#if defined (SYSTYPE_SVR4)
! 	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
! 	#endif
! 	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
! 	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
! 	#endif
! 	#endif
! 	  exit (-1);
! 	}
! EOF
! 	${CC-cc} dummy.c -o dummy \
! 	  && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
! 	  && rm dummy.c dummy && exit 0
! 	rm -f dummy.c dummy
  	echo mips-mips-riscos${UNAME_RELEASE}
  	exit 0 ;;
      Night_Hawk:Power_UNIX:*:*)
***************
*** 137,143 ****
      AViiON:dgux:*:*)
          # DG/UX returns AViiON for all architectures
          UNAME_PROCESSOR=`/usr/bin/uname -p`
!         if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88100 ] ; then
  	if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
  	     -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
  		echo m88k-dg-dgux${UNAME_RELEASE}
--- 179,185 ----
      AViiON:dgux:*:*)
          # DG/UX returns AViiON for all architectures
          UNAME_PROCESSOR=`/usr/bin/uname -p`
!         if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
  	if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
  	     -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
  		echo m88k-dg-dgux${UNAME_RELEASE}
***************
*** 163,172 ****
      *:IRIX*:*:*)
  	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
  	exit 0 ;;
!    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
  	echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
  	exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
!     i[34]86:AIX:*:*)
  	echo i386-ibm-aix
  	exit 0 ;;
      *:AIX:2:3)
--- 205,214 ----
      *:IRIX*:*:*)
  	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
  	exit 0 ;;
!     ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
  	echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
  	exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
!     i?86:AIX:*:*)
  	echo i386-ibm-aix
  	exit 0 ;;
      *:AIX:2:3)
***************
*** 211,217 ****
  	echo romp-ibm-bsd4.4
  	exit 0 ;;
      ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC NetBSD and
! 	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to 
  	exit 0 ;;                           # report: romp-ibm BSD 4.3
      *:BOSX:*:*)
  	echo rs6000-bull-bosx
--- 253,259 ----
  	echo romp-ibm-bsd4.4
  	exit 0 ;;
      ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC NetBSD and
! 	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
  	exit 0 ;;                           # report: romp-ibm BSD 4.3
      *:BOSX:*:*)
  	echo rs6000-bull-bosx
***************
*** 229,235 ****
  	case "${UNAME_MACHINE}" in
  	    9000/31? )            HP_ARCH=m68000 ;;
  	    9000/[34]?? )         HP_ARCH=m68k ;;
! 	    9000/7?? | 9000/8?[679] ) HP_ARCH=hppa1.1 ;;
  	    9000/8?? )            HP_ARCH=hppa1.0 ;;
  	esac
  	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
--- 271,277 ----
  	case "${UNAME_MACHINE}" in
  	    9000/31? )            HP_ARCH=m68000 ;;
  	    9000/[34]?? )         HP_ARCH=m68k ;;
! 	    9000/7?? | 9000/8?[1679] ) HP_ARCH=hppa1.1 ;;
  	    9000/8?? )            HP_ARCH=hppa1.0 ;;
  	esac
  	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
***************
*** 277,282 ****
--- 319,331 ----
      hp8??:OSF1:*:*)
  	echo hppa1.0-hp-osf
  	exit 0 ;;
+     i?86:OSF1:*:*)
+ 	if [ -x /usr/sbin/sysversion ] ; then
+ 	    echo ${UNAME_MACHINE}-unknown-osf1mk
+ 	else
+ 	    echo ${UNAME_MACHINE}-unknown-osf1
+ 	fi
+ 	exit 0 ;;
      parisc*:Lites*:*:*)
  	echo hppa1.1-hp-lites
  	exit 0 ;;
***************
*** 304,320 ****
      CRAY*Y-MP:*:*:*)
  	echo ymp-cray-unicos${UNAME_RELEASE}
  	exit 0 ;;
!     CRAY*C90:*:*:*)
! 	echo c90-cray-unicos${UNAME_RELEASE}
  	exit 0 ;;
      CRAY-2:*:*:*)
  	echo cray2-cray-unicos
          exit 0 ;;
      hp3[0-9][05]:NetBSD:*:*)
  	echo m68k-hp-netbsd${UNAME_RELEASE}
  	exit 0 ;;
!     i[34]86:BSD/386:*:* | *:BSD/OS:*:*)
! 	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
  	exit 0 ;;
      *:FreeBSD:*:*)
  	echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
--- 353,385 ----
      CRAY*Y-MP:*:*:*)
  	echo ymp-cray-unicos${UNAME_RELEASE}
  	exit 0 ;;
!     CRAY*[A-Z]90:*:*:*)
! 	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
! 	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
! 	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
! 	exit 0 ;;
!     CRAY*TS:*:*:*)
! 	echo t90-cray-unicos${UNAME_RELEASE}
  	exit 0 ;;
      CRAY-2:*:*:*)
  	echo cray2-cray-unicos
          exit 0 ;;
+     F300:UNIX_System_V:*:*)
+         FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'`
+         FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+         echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+         exit 0 ;;
+     F301:UNIX_System_V:*:*)
+        echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'`
+        exit 0 ;;
      hp3[0-9][05]:NetBSD:*:*)
  	echo m68k-hp-netbsd${UNAME_RELEASE}
  	exit 0 ;;
!     hp3[0-9][05]:OpenBSD:*:*)
! 	echo m68k-hp-openbsd${UNAME_RELEASE}
! 	exit 0 ;;
!     i?86:BSD/386:*:* | *:BSD/OS:*:*)
! 	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
  	exit 0 ;;
      *:FreeBSD:*:*)
  	echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
***************
*** 322,329 ****
      *:NetBSD:*:*)
  	echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
  	exit 0 ;;
      i*:CYGWIN*:*)
! 	echo i386-unknown-cygwin32
  	exit 0 ;;
      p*:CYGWIN*:*)
  	echo powerpcle-unknown-cygwin32
--- 387,397 ----
      *:NetBSD:*:*)
  	echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
  	exit 0 ;;
+     *:OpenBSD:*:*)
+ 	echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ 	exit 0 ;;
      i*:CYGWIN*:*)
! 	echo i386-pc-cygwin32
  	exit 0 ;;
      p*:CYGWIN*:*)
  	echo powerpcle-unknown-cygwin32
***************
*** 338,360 ****
  	# The BFD linker knows what the default object file format is, so
  	# first see if it will tell us.
  	ld_help_string=`ld --help 2>&1`
! 	if echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: elf_i[345]86"; then
! 	  echo "${UNAME_MACHINE}-unknown-linux" ; exit 0
! 	elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i[345]86linux"; then
! 	  echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0
! 	elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i[345]86coff"; then
! 	  echo "${UNAME_MACHINE}-unknown-linuxcoff" ; exit 0
  	elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68kelf"; then
! 	  echo "${UNAME_MACHINE}-unknown-linux" ; exit 0
  	elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68klinux"; then
! 	  echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0
  	elif test "${UNAME_MACHINE}" = "alpha" ; then
! 	  echo alpha-unknown-linux ; exit 0
  	else
! 	  # Either a pre-BFD a.out linker (linuxoldld) or one that does not give us
! 	  # useful --help.  Gcc wants to distinguish between linuxoldld and linuxaout.
  	  test ! -d /usr/lib/ldscripts/. \
! 	    && echo "${UNAME_MACHINE}-unknown-linuxoldld" && exit 0
  	  # Determine whether the default compiler is a.out or elf
  	  cat >dummy.c <<EOF
  main(argc, argv)
--- 406,432 ----
  	# The BFD linker knows what the default object file format is, so
  	# first see if it will tell us.
  	ld_help_string=`ld --help 2>&1`
! 	if echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: elf_i.86"; then
! 	  echo "${UNAME_MACHINE}-pc-linux-gnu" ; exit 0
! 	elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i.86linux"; then
! 	  echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0
! 	elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i.86coff"; then
! 	  echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0
  	elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68kelf"; then
! 	  echo "${UNAME_MACHINE}-unknown-linux-gnu" ; exit 0
  	elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68klinux"; then
! 	  echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0
! 	elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: elf32ppc"; then
! 	  echo "powerpc-unknown-linux-gnu" ; exit 0
  	elif test "${UNAME_MACHINE}" = "alpha" ; then
! 	  echo alpha-unknown-linux-gnu ; exit 0
! 	elif test "${UNAME_MACHINE}" = "sparc" ; then
! 	  echo sparc-unknown-linux-gnu ; exit 0
  	else
! 	  # Either a pre-BFD a.out linker (linux-gnuoldld) or one that does not give us
! 	  # useful --help.  Gcc wants to distinguish between linux-gnuoldld and linux-gnuaout.
  	  test ! -d /usr/lib/ldscripts/. \
! 	    && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
  	  # Determine whether the default compiler is a.out or elf
  	  cat >dummy.c <<EOF
  main(argc, argv)
***************
*** 362,370 ****
  char *argv[];
  {
  #ifdef __ELF__
!   printf ("%s-unknown-linux\n", argv[1]);
  #else
!   printf ("%s-unknown-linuxaout\n", argv[1]);
  #endif
    return 0;
  }
--- 434,442 ----
  char *argv[];
  {
  #ifdef __ELF__
!   printf ("%s-pc-linux-gnu\n", argv[1]);
  #else
!   printf ("%s-pc-linux-gnuaout\n", argv[1]);
  #endif
    return 0;
  }
***************
*** 374,405 ****
  	fi ;;
  # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
  # are messed up and put the nodename in both sysname and nodename.
!     i[34]86:DYNIX/ptx:4*:*)
  	echo i386-sequent-sysv4
  	exit 0 ;;
!     i[34]86:*:4.*:* | i[34]86:SYSTEM_V:4.*:*)
  	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
  		echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
  	else
! 		echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}
  	fi
  	exit 0 ;;
!     i[34]86:*:3.2:*)
  	if test -f /usr/options/cb.name; then
  		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
! 		echo ${UNAME_MACHINE}-unknown-isc$UNAME_REL
  	elif /bin/uname -X 2>/dev/null >/dev/null ; then
  		UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
  		(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
  		(/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
  			&& UNAME_MACHINE=i586
! 		echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL
  	else
! 		echo ${UNAME_MACHINE}-unknown-sysv32
  	fi
  	exit 0 ;;
      Intel:Mach:3*:*)
! 	echo i386-unknown-mach3
  	exit 0 ;;
      paragon:*:*:*)
  	echo i860-intel-osf1
--- 446,477 ----
  	fi ;;
  # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
  # are messed up and put the nodename in both sysname and nodename.
!     i?86:DYNIX/ptx:4*:*)
  	echo i386-sequent-sysv4
  	exit 0 ;;
!     i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
  	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
  		echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
  	else
! 		echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
  	fi
  	exit 0 ;;
!     i?86:*:3.2:*)
  	if test -f /usr/options/cb.name; then
  		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
! 		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
  	elif /bin/uname -X 2>/dev/null >/dev/null ; then
  		UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
  		(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
  		(/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
  			&& UNAME_MACHINE=i586
! 		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
  	else
! 		echo ${UNAME_MACHINE}-pc-sysv32
  	fi
  	exit 0 ;;
      Intel:Mach:3*:*)
! 	echo i386-pc-mach3
  	exit 0 ;;
      paragon:*:*:*)
  	echo i860-intel-osf1
***************
*** 415,442 ****
  	# "miniframe"
  	echo m68010-convergent-sysv
  	exit 0 ;;
!     M680[234]0:*:R3V[567]*:*)
  	test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
!     3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0)
!         uname -p 2>/dev/null | grep 86 >/dev/null \
!           && echo i486-ncr-sysv4.3 && exit 0 ;;
      3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
!         uname -p 2>/dev/null | grep 86 >/dev/null \
            && echo i486-ncr-sysv4 && exit 0 ;;
!     m680[234]0:LynxOS:2.[23]*:*)
! 	echo m68k-lynx-lynxos${UNAME_RELEASE}
  	exit 0 ;;
      mc68030:UNIX_System_V:4.*:*)
  	echo m68k-atari-sysv4
  	exit 0 ;;
!     i[34]86:LynxOS:2.[23]*:*)
! 	echo i386-lynx-lynxos${UNAME_RELEASE}
  	exit 0 ;;
!     TSUNAMI:LynxOS:2.[23]*:*)
! 	echo sparc-lynx-lynxos${UNAME_RELEASE}
  	exit 0 ;;
!     rs6000:LynxOS:2.[23]*:*)
! 	echo rs6000-lynx-lynxos${UNAME_RELEASE}
  	exit 0 ;;
      RM*:SINIX-*:*:*)
  	echo mips-sni-sysv4
--- 487,522 ----
  	# "miniframe"
  	echo m68010-convergent-sysv
  	exit 0 ;;
!     M68*:*:R3V[567]*:*)
  	test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
!     3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
! 	OS_REL=''
! 	test -r /etc/.relid \
! 	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
! 	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
! 	  && echo i486-ncr-sysv4.3${OS_REL} && exit 0
! 	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
! 	  && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
      3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
!         /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
            && echo i486-ncr-sysv4 && exit 0 ;;
!     m68*:LynxOS:2.*:*)
! 	echo m68k-unknown-lynxos${UNAME_RELEASE}
  	exit 0 ;;
      mc68030:UNIX_System_V:4.*:*)
  	echo m68k-atari-sysv4
  	exit 0 ;;
!     i?86:LynxOS:2.*:*)
! 	echo i386-unknown-lynxos${UNAME_RELEASE}
! 	exit 0 ;;
!     TSUNAMI:LynxOS:2.*:*)
! 	echo sparc-unknown-lynxos${UNAME_RELEASE}
  	exit 0 ;;
!     rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*)
! 	echo rs6000-unknown-lynxos${UNAME_RELEASE}
  	exit 0 ;;
!     SM[BE]S:UNIX_SV:*:*)
! 	echo mips-dde-sysv${UNAME_RELEASE}
  	exit 0 ;;
      RM*:SINIX-*:*:*)
  	echo mips-sni-sysv4
***************
*** 449,464 ****
  		echo ns32k-sni-sysv
  	fi
  	exit 0 ;;
      mc68*:A/UX:*:*)
  	echo m68k-apple-aux${UNAME_RELEASE}
  	exit 0 ;;
!     R3000:*System_V*:*:*)
  	if [ -d /usr/nec ]; then
  	        echo mips-nec-sysv${UNAME_RELEASE}
  	else
  	        echo mips-unknown-sysv${UNAME_RELEASE}
  	fi
          exit 0 ;;
  esac
  
  #echo '(No uname command or uname output not recognized.)' 1>&2
--- 529,557 ----
  		echo ns32k-sni-sysv
  	fi
  	exit 0 ;;
+     *:UNIX_System_V:4*:FTX*)
+ 	# From Gerald Hewes <hewes@openmarket.com>.
+ 	# How about differentiating between stratus architectures? -djm
+ 	echo hppa1.1-stratus-sysv4
+ 	exit 0 ;;
+     *:*:*:FTX*)
+ 	# From seanf@swdc.stratus.com.
+ 	echo i860-stratus-sysv4
+ 	exit 0 ;;
      mc68*:A/UX:*:*)
  	echo m68k-apple-aux${UNAME_RELEASE}
  	exit 0 ;;
!     R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:*)
  	if [ -d /usr/nec ]; then
  	        echo mips-nec-sysv${UNAME_RELEASE}
  	else
  	        echo mips-unknown-sysv${UNAME_RELEASE}
  	fi
          exit 0 ;;
+     PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                            # says <Richard.M.Bartel@ccMail.Census.GOV>
+         echo i586-unisys-sysv4
+         exit 0 ;;
  esac
  
  #echo '(No uname command or uname output not recognized.)' 1>&2
***************
*** 502,508 ****
  #endif
    int version;
    version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
!   printf ("%s-next-nextstep%s\n", __ARCHITECTURE__,  version==2 ? "2" : "3");
    exit (0);
  #endif
  
--- 595,601 ----
  #endif
    int version;
    version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
!   printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
    exit (0);
  #endif
  
***************
*** 519,525 ****
  #endif
  
  #if defined (__386BSD__)
!   printf ("i386-unknown-bsd\n"); exit (0);
  #endif
  
  #if defined (sequent)
--- 612,618 ----
  #endif
  
  #if defined (__386BSD__)
!   printf ("i386-pc-bsd\n"); exit (0);
  #endif
  
  #if defined (sequent)
Index: config/config.sub
diff -c krb5/config/config.sub:1.1.1.1 krb5/config/config.sub:1.2
*** krb5/config/config.sub:1.1.1.1	Mon Jun  2 17:54:54 1997
--- krb5/config/config.sub	Fri Sep  5 14:59:43 1997
***************
*** 1,9 ****
! #!/bin/sh
  # Configuration validation subroutine script, version 1.1.
! #   Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
  # This file is (in principle) common to ALL GNU software.
  # The presence of a machine in this file suggests that SOME GNU software
! # can handle that machine.  It does not imply ALL GNU software can. 
  #
  # This file is free software; you can redistribute it and/or modify
  # it under the terms of the GNU General Public License as published by
--- 1,9 ----
! #! /bin/sh
  # Configuration validation subroutine script, version 1.1.
! #   Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
  # This file is (in principle) common to ALL GNU software.
  # The presence of a machine in this file suggests that SOME GNU software
! # can handle that machine.  It does not imply ALL GNU software can.
  #
  # This file is free software; you can redistribute it and/or modify
  # it under the terms of the GNU General Public License as published by
***************
*** 17,23 ****
  #
  # You should have received a copy of the GNU General Public License
  # along with this program; if not, write to the Free Software
! # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  
  # As a special exception to the GNU General Public License, if you
  # distribute this file as part of a program that contains a
--- 17,24 ----
  #
  # You should have received a copy of the GNU General Public License
  # along with this program; if not, write to the Free Software
! # Foundation, Inc., 59 Temple Place - Suite 330,
! # Boston, MA 02111-1307, USA.
  
  # As a special exception to the GNU General Public License, if you
  # distribute this file as part of a program that contains a
***************
*** 40,47 ****
--- 41,59 ----
  # The goal of this file is to map all the various variations of a given
  # machine specification into a single specification in the form:
  #	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+ # or in some cases, the newer four-part form:
+ #	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
  # It is wrong to echo any other type of specification.
  
+ if [ x$1 = x ]
+ then
+ 	echo Configuration name missing. 1>&2
+ 	echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
+ 	echo "or     $0 ALIAS" 1>&2
+ 	echo where ALIAS is a recognized configuration type. 1>&2
+ 	exit 1
+ fi
+ 
  # First pass through any local machine types.
  case $1 in
  	*local*)
***************
*** 52,62 ****
  	;;
  esac
  
! # Separate what the user gave into CPU-COMPANY and OS (if any).
! basic_machine=`echo $1 | sed 's/-[^-]*$//'`
! if [ $basic_machine != $1 ]
! then os=`echo $1 | sed 's/.*-/-/'`
! else os=; fi
  
  ### Let's recognize common machines as not being operating systems so
  ### that things like config.sub decstation-3100 work.  We also
--- 64,84 ----
  	;;
  esac
  
! # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
! # Here we must recognize all the valid KERNEL-OS combinations.
! maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
! case $maybe_os in
!   linux-gnu*)
!     os=-$maybe_os
!     basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
!     ;;
!   *)
!     basic_machine=`echo $1 | sed 's/-[^-]*$//'`
!     if [ $basic_machine != $1 ]
!     then os=`echo $1 | sed 's/.*-/-/'`
!     else os=; fi
!     ;;
! esac
  
  ### Let's recognize common machines as not being operating systems so
  ### that things like config.sub decstation-3100 work.  We also
***************
*** 71,110 ****
  	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
  	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
  	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
! 	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp )
  		os=
  		basic_machine=$1
  		;;
  	-hiux*)
  		os=-hiuxwe2
  		;;
  	-sco4)
  		os=-sco3.2v4
! 		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
  		;;
  	-sco3.2.[4-9]*)
  		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
! 		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
  		;;
  	-sco3.2v[4-9]*)
  		# Don't forget version if it is 3.2v4 or newer.
! 		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
  		;;
  	-sco*)
  		os=-sco3.2v2
! 		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
  		;;
  	-isc)
  		os=-isc2.2
! 		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
  		;;
  	-clix*)
  		basic_machine=clipper-intergraph
  		;;
  	-isc*)
! 		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
  		;;
! 	-lynx)
  		os=-lynxos
  		;;
  	-ptx*)
--- 93,137 ----
  	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
  	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
  	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
! 	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
! 	-apple)
  		os=
  		basic_machine=$1
  		;;
  	-hiux*)
  		os=-hiuxwe2
  		;;
+ 	-sco5)
+ 		os=sco3.2v5
+ 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ 		;;
  	-sco4)
  		os=-sco3.2v4
! 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
  		;;
  	-sco3.2.[4-9]*)
  		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
! 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
  		;;
  	-sco3.2v[4-9]*)
  		# Don't forget version if it is 3.2v4 or newer.
! 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
  		;;
  	-sco*)
  		os=-sco3.2v2
! 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
  		;;
  	-isc)
  		os=-isc2.2
! 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
  		;;
  	-clix*)
  		basic_machine=clipper-intergraph
  		;;
  	-isc*)
! 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
  		;;
! 	-lynx*)
  		os=-lynxos
  		;;
  	-ptx*)
***************
*** 113,145 ****
  	-windowsnt*)
  		os=`echo $os | sed -e 's/windowsnt/winnt/'`
  		;;
  esac
  
  # Decode aliases for certain CPU-COMPANY combinations.
  case $basic_machine in
  	# Recognize the basic CPU types without company name.
  	# Some are omitted here because they have special meanings below.
! 	tahoe | i[345]86 | i860 | m68k | m68000 | m88k | ns32k | arm | pyramid \
! 		| tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \
! 		| alpha | we32k | ns16k | clipper | sparclite | i370 | sh \
! 		| powerpc | sparc64 | 1750a | dsp16xx | mips64 | mipsel \
! 		| pdp11 | mips64el | mips64orion | mips64orionel )
  		basic_machine=$basic_machine-unknown
  		;;
  	# Object if more than one company name word.
  	*-*-*)
  		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
  		exit 1
  		;;
  	# Recognize the basic CPU types with company name.
! 	vax-* | tahoe-* | i[345]86-* | i860-* | m68k-* | m68000-* | m88k-* \
  	      | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \
! 	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
  	      | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
! 	      | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
  	      | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
! 	      | pdp11-* | sh-* | powerpc-* | sparc64-* | mips64-* | mipsel-* \
! 	      | mips64el-* | mips64orion-* | mips64orionel-* )
  		;;
  	# Recognize the various machine names and aliases which stand
  	# for a CPU type and a company and sometimes even an OS.
--- 140,183 ----
  	-windowsnt*)
  		os=`echo $os | sed -e 's/windowsnt/winnt/'`
  		;;
+ 	-psos*)
+ 		os=-psos
+ 		;;
  esac
  
  # Decode aliases for certain CPU-COMPANY combinations.
  case $basic_machine in
  	# Recognize the basic CPU types without company name.
  	# Some are omitted here because they have special meanings below.
! 	tahoe | i860 | m68k | m68000 | m88k | ns32k | arm \
! 		| arme[lb] | pyramid \
! 		| tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \
! 		| alpha | we32k | ns16k | clipper | i370 | sh \
! 		| powerpc | powerpcle | 1750a | dsp16xx | mips64 | mipsel \
! 		| pdp11 | mips64el | mips64orion | mips64orionel \
! 		| sparc | sparclet | sparclite | sparc64)
  		basic_machine=$basic_machine-unknown
  		;;
+ 	# We use `pc' rather than `unknown'
+ 	# because (1) that's what they normally are, and
+ 	# (2) the word "unknown" tends to confuse beginning users.
+ 	i[3456]86)
+ 	  basic_machine=$basic_machine-pc
+ 	  ;;
  	# Object if more than one company name word.
  	*-*-*)
  		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
  		exit 1
  		;;
  	# Recognize the basic CPU types with company name.
! 	vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \
  	      | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \
! 	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \
  	      | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
! 	      | hppa-* | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
  	      | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
! 	      | pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \
! 	      | mips64el-* | mips64orion-* | mips64orionel-* | f301-*)
  		;;
  	# Recognize the various machine names and aliases which stand
  	# for a CPU type and a company and sometimes even an OS.
***************
*** 178,183 ****
--- 216,225 ----
  		basic_machine=m68k-apollo
  		os=-sysv
  		;;
+ 	aux)
+ 		basic_machine=m68k-apple
+ 		os=-aux
+ 		;;
  	balance)
  		basic_machine=ns32k-sequent
  		os=-dynix
***************
*** 210,215 ****
--- 252,261 ----
  		basic_machine=cray2-cray
  		os=-unicos
  		;;
+ 	[ctj]90-cray)
+ 		basic_machine=c90-cray
+ 		os=-unicos
+ 		;;
  	crds | unos)
  		basic_machine=m68k-crds
  		;;
***************
*** 291,315 ****
  	hp9k8[0-9][0-9] | hp8[0-9][0-9])
  		basic_machine=hppa1.0-hp
  		;;
  	i370-ibm* | ibm*)
  		basic_machine=i370-ibm
  		os=-mvs
  		;;
  # I'm not sure what "Sysv32" means.  Should this be sysv3.2?
! 	i[345]86v32)
! 		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
  		os=-sysv32
  		;;
! 	i[345]86v4*)
! 		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
  		os=-sysv4
  		;;
! 	i[345]86v)
! 		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
  		os=-sysv
  		;;
! 	i[345]86sol2)
! 		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
  		os=-solaris2
  		;;
  	iris | iris4d)
--- 337,364 ----
  	hp9k8[0-9][0-9] | hp8[0-9][0-9])
  		basic_machine=hppa1.0-hp
  		;;
+ 	hppa-next)
+ 		os=-nextstep3
+ 		;;
  	i370-ibm* | ibm*)
  		basic_machine=i370-ibm
  		os=-mvs
  		;;
  # I'm not sure what "Sysv32" means.  Should this be sysv3.2?
! 	i[3456]86v32)
! 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
  		os=-sysv32
  		;;
! 	i[3456]86v4*)
! 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
  		os=-sysv4
  		;;
! 	i[3456]86v)
! 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
  		os=-sysv
  		;;
! 	i[3456]86sol2)
! 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
  		os=-solaris2
  		;;
  	iris | iris4d)
***************
*** 407,423 ****
          pc532 | pc532-*)
  		basic_machine=ns32k-pc532
  		;;
! 	pentium-*)
! 		# We will change tis to say i586 once there has been
! 		# time for various packages to start to recognize that.
! 		basic_machine=i486-`echo $basic_machine | sed 's/^[^-]*-//'`
  		;;
  	pn)
  		basic_machine=pn-gould
  		;;
  	ps2)
  		basic_machine=i386-ibm
  		;;
  	rtpc | rtpc-*)
  		basic_machine=romp-ibm
  		;;
--- 456,502 ----
          pc532 | pc532-*)
  		basic_machine=ns32k-pc532
  		;;
! 	pentium | p5)
! 		basic_machine=i586-intel
! 		;;
! 	pentiumpro | p6)
! 		basic_machine=i686-intel
! 		;;
! 	pentium-* | p5-*)
! 		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
! 		;;
! 	pentiumpro-* | p6-*)
! 		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
! 		;;
! 	k5)
! 		# We don't have specific support for AMD's K5 yet, so just call it a Pentium
! 		basic_machine=i586-amd
! 		;;
! 	nexen)
! 		# We don't have specific support for Nexgen yet, so just call it a Pentium
! 		basic_machine=i586-nexgen
  		;;
  	pn)
  		basic_machine=pn-gould
  		;;
+ 	power)	basic_machine=rs6000-ibm
+ 		;;
+ 	ppc)	basic_machine=powerpc-unknown
+ 	        ;;
+ 	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ 		;;
+ 	ppcle | powerpclittle | ppc-le | powerpc-little)
+ 		basic_machine=powerpcle-unknown
+ 	        ;;
+ 	ppcle-* | powerpclittle-*)
+ 		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ 		;;
  	ps2)
  		basic_machine=i386-ibm
  		;;
+ 	rm[46]00)
+ 		basic_machine=mips-siemens
+ 		;;
  	rtpc | rtpc-*)
  		basic_machine=romp-ibm
  		;;
***************
*** 462,467 ****
--- 541,550 ----
  		basic_machine=sparc-sun
  		os=-sunos4
  		;;
+ 	sun4sol2)
+ 		basic_machine=sparc-sun
+ 		os=-solaris2
+ 		;;
  	sun3 | sun3-*)
  		basic_machine=m68k-sun
  		;;
***************
*** 478,483 ****
--- 561,570 ----
  	tower | tower-32)
  		basic_machine=m68k-ncr
  		;;
+ 	udi29k)
+ 		basic_machine=a29k-amd
+ 		os=-udi
+ 		;;
  	ultra3)
  		basic_machine=a29k-nyu
  		os=-sym1
***************
*** 490,495 ****
--- 577,585 ----
  		basic_machine=vax-dec
  		os=-vms
  		;;
+        vpp*|vx|vx-*)
+                basic_machine=f301-fujitsu
+                ;;
  	vxworks960)
  		basic_machine=i960-wrs
  		os=-vxworks
***************
*** 498,503 ****
--- 588,597 ----
  		basic_machine=m68k-wrs
  		os=-vxworks
  		;;
+ 	vxworks29k)
+ 		basic_machine=a29k-wrs
+ 		os=-vxworks
+ 		;;
  	xmp)
  		basic_machine=xmp-cray
  		os=-unicos
***************
*** 565,570 ****
--- 659,666 ----
  if [ x"$os" != x"" ]
  then
  case $os in
+         # First match some system type aliases
+         # that might get confused with valid system types.
  	# -solaris* is a basic system type, with this one exception.
  	-solaris1 | -solaris1.*)
  		os=`echo $os | sed -e 's|solaris1|sunos4|'`
***************
*** 572,593 ****
  	-solaris)
  		os=-solaris2
  		;;
  	-gnu/linux*)
! 		os=`echo $os | sed -e 's|gnu/linux|linux|'`
  		;;
  	# First accept the basic system types.
  	# The portable systems comes first.
! 	# Each alternative must end in a *, to match a version number.
  	# -sysv* is not here because it comes later, after sysvr4.
  	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
! 	      | -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[345]* \
  	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
! 	      | -amigados* | -msdos* | -newsos* | -unicos* | -aos* \
! 	      | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
! 	      | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \
! 	      | -hiux* | -386bsd* | -netbsd* | -freebsd* | -riscix* \
  	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
! 	      | -ptx* | -coff* | -winnt*)
  		;;
  	-sunos5*)
  		os=`echo $os | sed -e 's|sunos5|solaris2|'`
--- 668,699 ----
  	-solaris)
  		os=-solaris2
  		;;
+ 	-unixware* | svr4*)
+ 		os=-sysv4
+ 		;;
  	-gnu/linux*)
! 		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
  		;;
  	# First accept the basic system types.
  	# The portable systems comes first.
! 	# Each alternative MUST END IN A *, to match a version number.
  	# -sysv* is not here because it comes later, after sysvr4.
  	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
! 	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
  	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
! 	      | -amigados* | -msdos* | -newsos* | -unicos* | -aof* | -aos* \
! 	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
! 	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
! 	      | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
  	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
! 	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
! 	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
! 	      | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
! 	      | -linux-gnu* | -uxpv*)
! 	# Remember, each alternative MUST END IN *, to match a version number.
! 		;;
! 	-linux*)
! 		os=`echo $os | sed -e 's|linux|linux-gnu|'`
  		;;
  	-sunos5*)
  		os=`echo $os | sed -e 's|sunos5|solaris2|'`
***************
*** 613,618 ****
--- 719,734 ----
  	-ctix* | -uts*)
  		os=-sysv
  		;;
+ 	-ns2 )
+ 	        os=-nextstep2
+ 		;;
+ 	# Preserve the version number of sinix5.
+ 	-sinix5.*)
+ 		os=`echo $os | sed -e 's|sinix|sysv|'`
+ 		;;
+ 	-sinix*)
+ 		os=-sysv4
+ 		;;
  	-triton*)
  		os=-sysv3
  		;;
***************
*** 659,670 ****
--- 775,792 ----
  	*-acorn)
  		os=-riscix1.2
  		;;
+ 	arm*-semi)
+ 		os=-aout
+ 		;;
          pdp11-*)
  		os=-none
  		;;
  	*-dec | vax-*)
  		os=-ultrix4.2
  		;;
+ 	m68*-apollo)
+ 		os=-domain
+ 		;;
  	i386-sun)
  		os=-sunos4.0.2
  		;;
***************
*** 707,712 ****
--- 829,837 ----
  	m88k-omron*)
  		os=-luna
  		;;
+ 	*-next )
+ 		os=-nextstep
+ 		;;
  	*-sequent)
  		os=-ptx
  		;;
***************
*** 734,742 ****
--- 859,873 ----
          *-sgi)
  		os=-irix
  		;;
+         *-siemens)
+ 		os=-sysv4
+ 		;;
  	*-masscomp)
  		os=-rtu
  		;;
+ 	f301-fujitsu)
+ 		os=-uxpv
+ 		;;
  	*)
  		os=-none
  		;;
***************
*** 755,763 ****
  			-sunos*)
  				vendor=sun
  				;;
- 			-lynxos*)
- 				vendor=lynx
- 				;;
  			-aix*)
  				vendor=ibm
  				;;
--- 886,891 ----
***************
*** 784,789 ****
--- 912,923 ----
  				;;
  			-ptx*)
  				vendor=sequent
+ 				;;
+ 			-vxsim* | -vxworks*)
+ 				vendor=wrs
+ 				;;
+ 			-aux*)
+ 				vendor=apple
  				;;
  		esac
  		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
Index: include/k5-int.h
diff -c krb5/include/k5-int.h:1.1.1.1 krb5/include/k5-int.h:1.4
*** krb5/include/k5-int.h:1.1.1.1	Mon Jun  2 17:54:59 1997
--- krb5/include/k5-int.h	Thu Apr 15 14:48:28 1999
***************
*** 502,507 ****
--- 502,508 ----
  #define PA_SAM_TYPE_SKEY_K0    3   /*  S/key where  KDC has key 0 */
  #define PA_SAM_TYPE_SKEY       4   /*  Traditional S/Key */
  #define PA_SAM_TYPE_SECURID    5   /*  Security Dynamics */
+ #define PA_SAM_TYPE_CRYPTOCARD 6   /*  CryptoCard RB-1 */
  #define PA_SAM_TYPE_GRAIL    128 /* experimental */
  
  typedef struct _krb5_predicted_sam_response {
***************
*** 718,723 ****
--- 719,727 ----
  krb5_error_code krb5_find_config_files
          KRB5_PROTOTYPE(());
  
+ krb5_error_code krb5_locate_server
+ 	KRB5_PROTOTYPE((krb5_context, const krb5_data *, const char *,
+ 			const char *, void **, int *));
  
  /* in here to deal with stuff from lib/crypto/os */
  
***************
*** 1122,1127 ****
--- 1126,1134 ----
  krb5_error_code encode_krb5_predicted_sam_response
  	KRB5_PROTOTYPE((const krb5_predicted_sam_response * , krb5_data **));
  
+ krb5_error_code encode_krb5_principal
+ 	KRB5_PROTOTYPE((const krb5_principal, krb5_data **));
+ 
  /*************************************************************************
   * End of prototypes for krb5_encode.c
   *************************************************************************/
***************
*** 1237,1242 ****
--- 1244,1252 ----
  
  krb5_error_code decode_krb5_predicted_sam_response
  	KRB5_PROTOTYPE((const krb5_data *, krb5_predicted_sam_response **));
+ 
+ krb5_error_code decode_krb5_principal
+ 	KRB5_PROTOTYPE((const krb5_data *, krb5_principal *));
  
  /*************************************************************************
   * End of prototypes for krb5_decode.c
Index: include/krb5.hin
diff -c krb5/include/krb5.hin:1.1.1.1 krb5/include/krb5.hin:1.6
*** krb5/include/krb5.hin:1.1.1.1	Mon Jun  2 17:54:59 1997
--- krb5/include/krb5.hin	Thu Jul 23 12:52:59 1998
***************
*** 518,525 ****
   * Here's the stuff for the checksum switch:
   */
  #define krb5_checksum_size(context, ctype)  (krb5_cksumarray[ctype]->checksum_length)
! #define krb5_calculate_checksum(context, ctype, in, in_length, seed, seed_length, outcksum) krb5_x(((*krb5_cksumarray[ctype]->sum_func)),(in, in_length, seed, seed_length, outcksum))
! #define krb5_verify_checksum(context, ctype, cksum, in, in_length, seed, seed_length) krb5_x((*krb5_cksumarray[ctype]->sum_verf_func),(cksum, in, in_length, seed, seed_length))
  
  /*
   * encryption routine prototypes
--- 518,525 ----
   * Here's the stuff for the checksum switch:
   */
  #define krb5_checksum_size(context, ctype)  (krb5_cksumarray[ctype]->checksum_length)
! #define krb5_calculate_checksum(context, ctype, in, in_length, seed, seed_length, outcksum) krb5_x(((krb5_cksumarray[ctype]->sum_func)),(in, in_length, seed, seed_length, outcksum))
! #define krb5_verify_checksum(context, ctype, cksum, in, in_length, seed, seed_length) krb5_x((krb5_cksumarray[ctype]->sum_verf_func),(cksum, in, in_length, seed, seed_length))
  
  /*
   * encryption routine prototypes
***************
*** 556,562 ****
  #define	KDC_OPT_RENEWABLE		0x00800000
  /* #define	KDC_OPT_UNUSED		0x00400000 */
  /* #define	KDC_OPT_RESERVED	0x00200000 */
! /* #define	KDC_OPT_RESERVED	0x00100000 */
  /* #define	KDC_OPT_RESERVED	0x00080000 */
  /* #define	KDC_OPT_RESERVED	0x00040000 */
  /* #define	KDC_OPT_RESERVED	0x00020000 */
--- 556,562 ----
  #define	KDC_OPT_RENEWABLE		0x00800000
  /* #define	KDC_OPT_UNUSED		0x00400000 */
  /* #define	KDC_OPT_RESERVED	0x00200000 */
! #define	KDC_OPT_HW_AUTH			0x00100000
  /* #define	KDC_OPT_RESERVED	0x00080000 */
  /* #define	KDC_OPT_RESERVED	0x00040000 */
  /* #define	KDC_OPT_RESERVED	0x00020000 */
***************
*** 720,725 ****
--- 720,726 ----
  #define KRB5_LRQ_ONE_LAST_RENEWAL	(-4)
  #define KRB5_LRQ_ALL_LAST_REQ		5
  #define KRB5_LRQ_ONE_LAST_REQ		(-5)
+ #define KRB5_LRQ_PW_EXPTIME		6
  
  /* PADATA types */
  #define KRB5_PADATA_NONE                0
***************
*** 747,752 ****
--- 748,756 ----
  /* Reserved for SPX pre-authentication. */
  #define KRB5_PADATA_DASS		16
  
+ /* Special experimental pre-auth types */
+ #define KRB5_PADATA_AS_REP		20 /* AS-REP encrypted w/ server key */
+ 
  /* Transited encoding types */
  #define	KRB5_DOMAIN_X500_COMPRESS	1
  
***************
*** 757,762 ****
--- 761,774 ----
  #define	KRB5_AUTHDATA_OSF_DCE	64
  #define KRB5_AUTHDATA_SESAME	65
  
+ /* password change constants */
+ 
+ #define KRB5_KPASSWD_SUCCESS		0
+ #define KRB5_KPASSWD_MALFORMED		1
+ #define KRB5_KPASSWD_HARDERROR		2
+ #define KRB5_KPASSWD_AUTHERROR		3
+ #define KRB5_KPASSWD_SOFTERROR		4
+ 
  /*
   * end "proto.h"
   */
***************
*** 2035,2041 ****
  /*
   * begin stuff from libos.h
   */
! 
  krb5_error_code krb5_read_password
  	KRB5_PROTOTYPE((krb5_context,
  			const char *,
--- 2047,2066 ----
  /*
   * begin stuff from libos.h
   */
! void krb5_appdefault_boolean
! 	KRB5_PROTOTYPE((krb5_context,
! 			const char *,
! 			const krb5_data *,
! 			const char *,
! 			int,
! 			int * ));
! void krb5_appdefault_string
! 	KRB5_PROTOTYPE((krb5_context,
! 			const char *,
! 			const krb5_data *,
! 			const char *,
! 			const char *,
! 			char ** ));
  krb5_error_code krb5_read_password
  	KRB5_PROTOTYPE((krb5_context,
  			const char *,
Index: include/krb5/Makefile.in
diff -c krb5/include/krb5/Makefile.in:1.1.1.1 krb5/include/krb5/Makefile.in:1.2
*** krb5/include/krb5/Makefile.in:1.1.1.1	Mon Jun  2 17:55:03 1997
--- krb5/include/krb5/Makefile.in	Mon Jun 16 16:03:46 1997
***************
*** 27,35 ****
--- 27,39 ----
  install::
  SYSCONFDIR = @sysconfdir@
  LOCALSTATEDIR = @localstatedir@
+ BINDIR = @bindir@
+ SBINDIR = @sbindir@
  PROCESS_REPLACE = -e "s+@KRB5RCTMPDIR+$(KRB5RCTMPDIR)+" \
  		  -e "s+@PREFIX+$(INSTALL_PREFIX)+" \
  		  -e "s+@EXEC_PREFIX+$(INSTALL_EXEC_PREFIX)+" \
+ 		  -e "s+@BINDIR+$(BINDIR)+" \
+ 		  -e "s+@SBINDIR+$(SBINDIR)+" \
  	-e 's+@LOCALSTATEDIR+$(LOCALSTATEDIR)+' \
  	-e 's+@SYSCONFDIR+$(SYSCONFDIR)+' 
  
Index: include/krb5/configure.in
diff -c krb5/include/krb5/configure.in:1.1.1.1 krb5/include/krb5/configure.in:1.2
*** krb5/include/krb5/configure.in:1.1.1.1	Mon Jun  2 17:55:03 1997
--- krb5/include/krb5/configure.in	Mon Jun  2 18:34:29 1997
***************
*** 99,105 ****
  AC_MSG_CHECKING([for replay cache directory])
  AC_CACHE_VAL(krb5_cv_sys_rcdir,
  [
! for t_dir in /usr/tmp /var/usr/tmp /var/tmp /tmp ; do
  	test -d $t_dir || continue
  	krb5_cv_sys_rcdir=$t_dir
  	break
--- 99,105 ----
  AC_MSG_CHECKING([for replay cache directory])
  AC_CACHE_VAL(krb5_cv_sys_rcdir,
  [
! for t_dir in /var/tmp /usr/tmp /var/usr/tmp /tmp ; do
  	test -d $t_dir || continue
  	krb5_cv_sys_rcdir=$t_dir
  	break
Index: include/krb5/kdb.h
diff -c krb5/include/krb5/kdb.h:1.1.1.1 krb5/include/krb5/kdb.h:1.2
*** krb5/include/krb5/kdb.h:1.1.1.1	Mon Jun  2 17:55:03 1997
--- krb5/include/krb5/kdb.h	Fri Jun 19 12:01:35 1998
***************
*** 115,120 ****
--- 115,121 ----
  #define KRB5_TL_MOD_PRINC		0x0002
  #define KRB5_TL_KADM_DATA		0x0003
  #define KRB5_TL_KADM5_E_DATA		0x0004
+ #define KRB5_TL_RB1_CHALLENGE		0x0005
      
  /*
   * Determines the number of failed KDC requests before DISALLOW_ALL_TIX is set
Index: include/krb5/stock/osconf.h
diff -c krb5/include/krb5/stock/osconf.h:1.1.1.1 krb5/include/krb5/stock/osconf.h:1.4
*** krb5/include/krb5/stock/osconf.h:1.1.1.1	Mon Jun  2 17:55:04 1997
--- krb5/include/krb5/stock/osconf.h	Mon Aug  4 15:48:22 1997
***************
*** 58,65 ****
  #define	DEFAULT_KDC_ENCTYPE	ENCTYPE_DES_CBC_CRC
  #define KDCRCACHE		"dfl:krb5kdc_rcache"
  
! #define KDC_PORTNAME		"kerberos" /* for /etc/services or equiv. */
! #define KDC_SECONDARY_PORTNAME	"kerberos-sec" /* For backwards */
  					    /* compatibility with */
  					    /* port 750 clients */
  
--- 58,65 ----
  #define	DEFAULT_KDC_ENCTYPE	ENCTYPE_DES_CBC_CRC
  #define KDCRCACHE		"dfl:krb5kdc_rcache"
  
! #define KDC_PORTNAME		"kerberos5" /* for /etc/services or equiv. */
! #define KDC_SECONDARY_PORTNAME	"kerberos" /* For backwards */
  					    /* compatibility with */
  					    /* port 750 clients */
  
***************
*** 68,73 ****
--- 68,75 ----
  
  #define DEFAULT_KDC_PORTLIST	"88,750"
  
+ #define DEFAULT_KPASSWD_PORT	464
+ 
  /*
   * Defaults for the KADM5 admin system.
   */
***************
*** 83,90 ****
  #define RCTMPDIR	"@KRB5RCTMPDIR"	/* directory to store replay caches */
  
  #define KRB5_PATH_TTY	"/dev/tty"
! #define KRB5_PATH_LOGIN	"@EXEC_PREFIX/sbin/login.krb5"
! #define KRB5_PATH_RLOGIN "@EXEC_PREFIX/bin/rlogin"
  
  #define KRB5_ENV_CCNAME	"KRB5CCNAME"
  
--- 85,92 ----
  #define RCTMPDIR	"@KRB5RCTMPDIR"	/* directory to store replay caches */
  
  #define KRB5_PATH_TTY	"/dev/tty"
! #define KRB5_PATH_LOGIN	"@SBINDIR/login.krb5"
! #define KRB5_PATH_RLOGIN "@BINDIR/rlogin"
  
  #define KRB5_ENV_CCNAME	"KRB5CCNAME"
  
***************
*** 106,113 ****
  
  #define KPROP_DEFAULT_FILE "@LOCALSTATEDIR/krb5kdc/slave_datatrans"
  #define KPROPD_DEFAULT_FILE "@LOCALSTATEDIR/krb5kdc/from_master"
! #define KPROPD_DEFAULT_KDB5_UTIL "@PREFIX/sbin/kdb5_util"
! #define KPROPD_DEFAULT_KDB5_EDIT "@PREFIX/sbin/kdb5_edit"
  #define KPROPD_DEFAULT_KRB_DB DEFAULT_KDB_FILE
  #define KPROPD_ACL_FILE "@LOCALSTATEDIR/krb5kdc/kpropd.acl"
  
--- 108,115 ----
  
  #define KPROP_DEFAULT_FILE "@LOCALSTATEDIR/krb5kdc/slave_datatrans"
  #define KPROPD_DEFAULT_FILE "@LOCALSTATEDIR/krb5kdc/from_master"
! #define KPROPD_DEFAULT_KDB5_UTIL "@SBINDIR/kdb5_util"
! #define KPROPD_DEFAULT_KDB5_EDIT "@SBINDIR/kdb5_edit"
  #define KPROPD_DEFAULT_KRB_DB DEFAULT_KDB_FILE
  #define KPROPD_ACL_FILE "@LOCALSTATEDIR/krb5kdc/kpropd.acl"
  
Index: kadmin/cli/Makefile.in
diff -c krb5/kadmin/cli/Makefile.in:1.1.1.1 krb5/kadmin/cli/Makefile.in:1.2
*** krb5/kadmin/cli/Makefile.in:1.1.1.1	Mon Jun  2 17:55:05 1997
--- krb5/kadmin/cli/Makefile.in	Fri Jun 19 12:01:52 1998
***************
*** 1,7 ****
  CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
  
  PROG = kadmin
! OBJS = kadmin.o kadmin_ct.o ss_wrapper.o getdate.o keytab.o
  
  all:: $(PROG).local $(PROG)
  
--- 1,7 ----
  CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
  
  PROG = kadmin
! OBJS = kadmin.o kadmin_ct.o ss_wrapper.o getdate.o keytab.o cryptocard.o
  
  all:: $(PROG).local $(PROG)
  
Index: kadmin/cli/configure.in
diff -c krb5/kadmin/cli/configure.in:1.1.1.1 krb5/kadmin/cli/configure.in:1.3
*** krb5/kadmin/cli/configure.in:1.1.1.1	Mon Jun  2 17:55:05 1997
--- krb5/kadmin/cli/configure.in	Mon Aug 10 15:59:42 1998
***************
*** 3,11 ****
--- 3,24 ----
  AC_PROG_INSTALL
  AC_PROG_YACC
  AC_HAVE_HEADERS(unistd.h sys/timeb.h alloca.h)
+ AC_HAVE_HEADERS(pty.h)
  AC_HAVE_FUNCS(ftime timezone)
  AC_REPLACE_FUNCS([memmove strftime])
  USE_KADMCLNT_LIBRARY
+ dnl
+ dnl --with-kadmin-cryptocard adds the special cryptocard interface to kadmin
+ dnl
+ AC_ARG_WITH([kadmin-cryptocard],
+ [  --with-kadmin-cryptocard	Add support for programming CRYPTOCard RB-1 tokens
+   --without-kadmin-cryptocard	Do not add CRYPTOCard programming support (default)],
+ ,
+ withval=no)dnl
+ if test "$withval" = yes; then
+ 	AC_MSG_RESULT(Adding CRYPTOCard RB-1 programming support)
+ 	AC_DEFINE(KADMIN_CRYPTOCARD)
+ fi
  USE_GSSAPI_LIBRARY
  USE_KADMSRV_LIBRARY
  USE_GSSRPC_LIBRARY
Index: kadmin/cli/cryptocard.c
diff -c /dev/null krb5/kadmin/cli/cryptocard.c:1.5
*** /dev/null	Thu Sep 23 15:40:56 1999
--- krb5/kadmin/cli/cryptocard.c	Mon Jan 25 14:04:39 1999
***************
*** 0 ****
--- 1,1021 ----
+ /*
+  * cryptocard.c - A set of routines designed to provide an interface for
+  * CRYPTOCard RB-1 challenge-response hardware.
+  *
+  * This code uses kadm5_randkey_principal() to generate a random DES key for
+  * a RB-1 token, and then prints out the necessary info in the format
+  * required by the RB-1.  This also can talk to the RB-1 token initializer
+  * for more convenient token programming.
+  */
+ 
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+ #endif
+ #ifdef HAVE_PTY_H
+ #include <pty.h>
+ #endif
+ #include <fcntl.h>
+ #include <termios.h>
+ #include <errno.h>
+ 
+ #ifdef KADMIN_CRYPTOCARD
+ 
+ #include <krb5.h>
+ #include <k5-int.h>
+ #include <kadm5/admin.h>
+ 
+ /*
+  * Defines needed for the RB-1 initializer
+  *
+  * First we have codes used by the LED's on the front panel.
+  */
+ 
+ #define LED_NONE	0x00	/* No LEDs on at all */
+ #define LED_RESET	0x01	/* Reset LED (really card power toggle) */
+ #define LED_INSERT	0x02	/* Insert LED on */
+ #define LED_INIT	0x04	/* Init LED on */
+ #define LED_DONE	0x08	/* Done LED on */
+ #define LED_ERROR	0x10	/* Error LED on */
+ #define SOL		0x60	/* Solenoid and flash lights on */
+ 
+ /*
+  * Extra codes used by the RB-1 card
+  */
+ 
+ #define	SCROLL_KEY	0x0b	/* Code for the SCROLL (->) key */
+ #define ENT_KEY		0x0c	/* Code for the ENT key */
+ 
+ /*
+  * Offsets used by the language tables for different RB-1 responses
+  */
+ 
+ #define KEY1		0x00
+ #define KEY2		0x01
+ #define KEY3		0x02
+ #define USER_ID		0x03
+ #define NEW_PIN		0x04
+ #define VERIFY		0x05
+ #define CARD_OK		0x06
+ #define PIN		0x07
+ #define LOCKED		0x08
+ #define OPTIONS		0x09
+ 
+ #define DEFAULT_PORT	"/dev/ttya"
+ 
+ /*
+  * We need to know the responses in each possible language we use.
+  */
+ 
+ struct _language_table {
+ 	char *language_name;
+ 	int lang_code;
+ 	char *response[10];
+ } *lang_ptr, language_table[] = {
+ /*
+  * English (aka "English-1")
+  */
+ 	"english", 0, "Key1?   ", "Key2?   ", "Key3?   ", "User ID?",
+ 	"New PIN?", "Verify  ", "Card OK ", "PIN?    ", "Locked  ",
+ 	"Options?",
+ /*
+  * Alternate English ("English-2")
+  */
+ 	"english2", 1, "Key1?   ", "Key2?   ", "Key3?   ", "User ID?",
+ 	"New PSC?", "Verify  ", "Card OK ", "PSC?    ", "Locked  ",
+ 	"Options?",
+ /*
+  * French
+  */
+ 	"french", 2, "Clef1?  ", "Clef2?  ", "Clef3?  ", "Usag?  ",
+ 	"Nouveau?", "Verifier", "Correct ", "PIN?    ", "Bloqu  ",
+ 	"Options?",
+ /*
+  * German
+  */
+ 	"german", 3, "Chiffre1", "Chiffre2", "Chiffre3", "Ident. #",
+ 	"Neue PIN", "Beweise ", "Karte OK", "PIN?    ", "Gesperrt",
+ 	"Auswahl?",
+ /*
+  * Italian
+  */
+ 	"italian", 4, "Chiave1?", "Chiave2?", "Chiave3?", "ID Usare",
+ 	"Nuovo?  ", "Verifica", "Carta OK", "PIN?    ", "Chiuso  ",
+ 	"Scelta? ",
+ 
+ /*
+  * Portuguese
+  */
+ 	"portuguese", 5, "Codig1?", "Codig2?", "Codig3?", "Nr.Conta",
+ 	"Nvo PIN", "Repetir ", "Correcto", "PIN?    ", "Nulo    ",
+ 	"Opes? ",
+ 
+ /*
+  * Swedish
+  */
+ 	"swedish", 6, "Tangent1", "Tangent2", "Tangent3", "Kund-ID?",
+ 	"Ny PIN? ", "Bekrfta", "Kort OK ", "PIN?    ", "Sprrad ",
+ 	"Val?    ",
+ 
+ /*
+  * Spanish
+  */
+ 	"spanish", 7, "Clave1? ", "Clave2? ", "Clave3? ", "Ident. #",
+ 	"Nuevo?  ", "Asegurar", "Correcto", "PIN?    ", "Atascado",
+ 	"Opciones",
+ 
+ 	NULL, -1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ 	NULL, NULL,
+ };
+ 
+ /*
+  * Internal functions
+  */
+ 
+ static void ktadd_usage();
+ static void print_card_info(krb5_keyblock *, char *, int, char *, int);
+ static void initialize_card(krb5_keyblock *, char *, int, char *, int, char *);
+ static void get_options(char [3][4], int, int);
+ 
+ static int card_in(int);
+ static int send_byte(int, int);
+ static int send_byte_initializer(int, int);
+ static int check_card_buffer(int, char *);
+ static int send_decimal(int, char *);
+ static int send_octal(int, char *);
+ static void send_error(int);
+ 
+ /*
+  * External references needed by kadmin
+  */
+ 
+ extern char *whoami;
+ extern krb5_context context;
+ extern void *handle;
+ 
+ /*
+  * Main routine.  This is the routine called by the kadmin cli
+  */
+ 
+ void
+ kadmin_ktadd_cryptocard(int argc, char **argv)
+ {
+ 	krb5_principal princ = NULL;
+ 	krb5_keyblock *keys, *key;
+ 	krb5_error_code retval;
+ 	int initializer = 0, nkeys = 0, i;
+ 	char *user = NULL;
+ 	char *port = NULL;
+ 	char *initial_pin = "1111";
+ 	int minimum_length = 4;
+ 	int language = -1;
+ 
+ 	/*
+ 	 * Perform basic argument parsing
+ 	 */
+ 
+ 	argc--; argv++;
+ 
+ 	while (argc) {
+ 		if (strncmp(*argv, "-i", 2) == 0) {
+ 			initializer++;
+ 		} else if (strncmp(*argv, "-u", 2) == 0) {
+ 			argc--; argv++;
+ 			if (! argc || user) {
+ 				ktadd_usage();
+ 				return;
+ 			}
+ 			user = *argv;
+ 		} else if (strncmp(*argv, "-d", 2) == 0) {
+ 			argc--; argv++;
+ 			if (! argc || port) {
+ 				ktadd_usage();
+ 				return;
+ 			}
+ 			port = *argv;
+ 		} else if (strncmp(*argv, "-p", 2) == 0) {
+ 			argc--; argv++;
+ 			if (! argc) {
+ 				ktadd_usage();
+ 				return;
+ 			}
+ 			initial_pin = *argv;
+ 		} else if (strncmp(*argv, "-n", 2) == 0) {
+ 			argc--; argv++;
+ 			if (! argc || atoi(*argv) == 0) {
+ 				ktadd_usage();
+ 				return;
+ 			}
+ 			minimum_length = atoi(*argv);
+ 			if (minimum_length < 3 || minimum_length > 8) {
+ 				fprintf(stderr, "Minimum PIN length must be "
+ 					"between 3 and 8 characters\n");
+ 				return;
+ 			}
+ 			if (minimum_length == 8)
+ 				minimum_length = 0;
+ 		} else if (strncmp(*argv, "-l", 2) == 0) {
+ 			argc--; argv++;
+ 			if (! argc || language != -1) {
+ 				ktadd_usage();
+ 				return;
+ 			}
+ 			for (lang_ptr = language_table;
+ 				      lang_ptr->lang_code != -1; lang_ptr++)
+ 				if (!strcmp(*argv, lang_ptr->language_name)) {
+ 					language = lang_ptr->lang_code;
+ 					break;
+ 				}
+ 			if (language == -1) {
+ 				fprintf(stderr, "Invalid language: "
+ 					"\"%s\"\n", *argv);
+ 				return;
+ 			}
+ 		} else
+ 			break;
+ 		argc--; argv++;
+ 	}
+ 
+ 	if (argc != 1) {
+ 		ktadd_usage();
+ 		return;
+ 	}
+ 
+ 	if (language == -1)
+ 		language = 0;
+ 
+ 	if (! port || ! (port = getenv("CRYPTOCARD_PORT")))
+ 		port = DEFAULT_PORT;
+ 
+ 	if ((retval = krb5_parse_name(context, argv[0], &princ))) {
+ 		com_err(whoami, retval, "while parsing principal name %s",
+ 			argv[0]);
+ 		goto cleanup;
+ 	}
+ 
+ 	/*
+ 	 * Get a new key for the specified principal.  Note that this
+ 	 * will destroy the current key (I think that it's probably better
+ 	 * to do this checking before we try talking to the initializer)
+ 	 */
+ 
+ 	if ((retval = kadm5_randkey_principal(handle, princ, &keys, &nkeys))) {
+ 		if (retval == KADM5_UNK_PRINC) {
+ 			fprintf(stderr, "%s: Principal %s does not exist.\n",
+ 				whoami, argv[0]);
+ 		} else
+ 			com_err(whoami, retval, "while getting new key for %s",
+ 				argv[0]);
+ 		goto cleanup;
+ 	}
+ 
+ 	/*
+ 	 * The RB-1 can only handle a DES key, so make sure we got one
+ 	 */
+ 
+ 	for (i = 0; i < nkeys; i++) {
+ 		if (keys[i].enctype == ENCTYPE_DES_CBC_CRC ||
+ 		    keys[i].enctype == ENCTYPE_DES_CBC_MD4 ||
+ 		    keys[i].enctype == ENCTYPE_DES_CBC_MD5 ||
+ 		    keys[i].enctype == ENCTYPE_DES_CBC_RAW) {
+ 			key = &keys[i];
+ 			break;
+ 		}
+ 	}
+ 
+ 	if (key == NULL) {
+ 		fprintf(stderr, "%s: No DES key found for principal %s",
+ 			whoami, argv[0]);
+ 		return;
+ 	}
+ 
+ 	if (!user)
+ 		user = krb5_princ_name(context, princ)->data;
+ 
+ 	if (!initializer) {
+ 		print_card_info(key, initial_pin, minimum_length, user,
+ 				language);
+ 	} else {
+ 		initialize_card(key, initial_pin, minimum_length, user,
+ 				language, port);
+ 	}
+ 
+ cleanup:
+ 	if (nkeys) {
+ 		for (i = 0; i < nkeys; i++)
+ 			krb5_free_keyblock_contents(context, &keys[i]);
+ 		free(keys);
+ 	}
+ 	if (princ)
+ 		krb5_free_principal(context, princ);
+ 
+ 	return;
+ }
+ 
+ /*
+  * Print out all of the stuff a human needs to program the card
+  */
+ 
+ static void
+ print_card_info(krb5_keyblock *key, char *pin, int length, char *userid,
+ 		int language)
+ {
+ 	krb5_encrypt_block eblock;
+ 	krb5_error_code retval;
+ 	int i;
+ 	char options[3][4];
+ 	char inputblock[8], outputblock[8], ivec[8];
+ 
+ 	printf("Token programming sequence:\n");
+ 	printf("\t225371 after power-on for administrative reset\n");
+ 
+ 	get_options(options, length, language);
+ 
+ 	printf("\tOptions are:\n");
+ 	printf("\t\t%s -> %s -> %s -> ENT\n", options[0], options[1],
+ 	       options[2]);
+ 	
+ 	/*
+ 	 * Note that the encryption key has to be printed in octal
+ 	 */
+ 
+ 	printf("\tEncryption key:\n\t\t");
+ 
+ 	for (i = 0; i < 8; i++)
+ 		printf("%03o -> ", (unsigned char) key->contents[i]);
+ 
+ 	printf("ENT\n");
+ 
+ 	/*
+ 	 * The RB-1 prints the output of using the encryption block
+ 	 * on all zero's - calculate that and print it out as a
+ 	 * check against data entry errors
+ 	 */
+ 
+ 	memset(inputblock, 0, 8);
+ 	memset(ivec, 0, 8);
+ 
+ 	/* We need to use CBC_RAW to avoid the CRC junk */
+ 
+ 	krb5_use_enctype(context, &eblock, ENCTYPE_DES_CBC_RAW);
+ 	if ((retval = krb5_process_key(context, &eblock, key))) {
+ 		com_err(whoami, retval, "while processing RB-1 key for key test");
+ 		return;
+ 	}
+ 
+ 	if ((retval = krb5_encrypt(context, inputblock, outputblock, 8,
+ 				   &eblock, ivec))) {
+ 		com_err(whoami, retval, "while encrypting key test data");
+ 		krb5_finish_key(context, &eblock);
+ 		return;
+ 	}
+ 
+ 	krb5_finish_key(context, &eblock);
+ 
+ 	printf("\tResults of key encryption using binary NULs (press ENT to\n\taccept, CLR to reenter)\n\t\t");
+ 
+ 	for (i = 0; i < 4; i++)
+ 		printf("%02X", (unsigned char) outputblock[i]);
+ 	printf("\n");
+ 
+ 	/*
+ 	 * Because the userid needs to input in octal, print that out
+ 	 * as well
+ 	 */
+ 
+ 	printf("\tUser id:\n\t\t");
+ 
+ 	for (i = 0; (i < 8) && (userid[i] != 0); i++)
+ 		printf("%03o -> ", (unsigned char) userid[i]);
+ 
+ 	for (; i < 8; i++) {
+ 		printf("%03o -> ", ' ');
+ 	}
+ 
+ 	printf("ENT\n");
+ 
+ 	printf("\tASCII format userid (press ENT to accept, CLR to reenter):\n");
+ 	printf("\t\t%s\n", userid);
+ 
+ 	printf("\tInitial PIN:\n\t\t%s\n", pin);
+ 
+ }
+ 
+ /*
+  * Program a card using the RB Initializer hardware
+  *
+  * This box works in the following way:
+  *
+  * When RTS is asserted, you are talking to the initializer box itself.
+  * In this mode, each command is a byte, and controls what you want to
+  * do to the box.  You basically have a choice between lighting any
+  * of the four front LEDs, or engaging the box solenoid (which brings the
+  * initializer in contact with the contacts on the RB-1, and is required
+  * to do further programming).
+  *
+  * You get back a status byte after every command which has the low bit
+  * set if a card is inserted.
+  *
+  * Note that the so-called RESET LED seems to actually be wired to the
+  * on/off switch on the RB-1.  Engaging that will toggle the card on
+  * or off, depending on the card's current state.
+  *
+  * When RTS is deasserted, you are talking to the card itself.  This
+  * is simply the ASCII equivalants of whatever you would enter on the
+  * front panel (for example, you send a ASCII '0' character to simulate
+  * typing a 0 on the front panel).  The data you get back in this mode
+  * is whatever is printed on the LCD display.  To converse with the card,
+  * you simulate everything you would normally type on the front panel,
+  * and read back the results in ASCII.
+  * 
+  */
+ 
+ static void
+ initialize_card(krb5_keyblock *key, char *pin, int length, char *userid,
+ 		int language, char *port)
+ {
+ 	char *admincode = "225371";
+ 	int fd = -1, i;
+ 	struct termios term;
+ 	int state;
+ 	int linkflag = 0;
+ 	char options[3][4];
+ 	unsigned char inputblock[8], outputblock[8], ivec[8],
+ 		testbytes[9], keybyte[4];
+ 	krb5_encrypt_block eblock;
+ 	krb5_error_code retval;
+ 
+ 	/*
+ 	 * Start by opening up the terminal device and initializing
+ 	 * it to what we need (2400 baud, 8N1)
+ 	 */
+ 
+ 	if ((fd = open(port, O_RDWR | O_NONBLOCK)) < 0) {
+ 		com_err(whoami, errno, "while opening terminal device %s",
+ 			port);
+ 		goto cleanup;
+ 	}
+ 
+ 	if (tcgetattr(fd, &term) < 0) {
+ 		com_err(whoami, errno, "while getting terminal attributes");
+ 		goto cleanup;
+ 	}
+ 
+ 	/*
+ 	 * Sigh, you think after doing this so many times, I'd remember it
+ 	 * all ...
+ 	 */
+ 
+ 	term.c_cflag &= ~(CSIZE | PARENB | CRTSCTS);
+ 	term.c_cflag |= CS8 | CLOCAL | CREAD;
+ 	term.c_oflag &= ~(OPOST);
+ 	term.c_lflag = 0;
+ 	term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON | IXOFF);
+ 	term.c_iflag |= IGNBRK | IGNCR;
+ 	term.c_cc[VMIN] = 0;	/* 0 character minimum (this is for a reason! */
+ 	term.c_cc[VTIME] = 10;	/* 1 second timeout */
+ 
+ 	cfsetispeed(&term, B2400);	/* 2400 baud */
+ 	cfsetospeed(&term, B2400);	/* 2400 baud */
+ 
+ 	if (tcsetattr(fd, TCSAFLUSH, &term) < 0) {
+ 		com_err(whoami, errno, "while setting terminal attributes");
+ 		goto cleanup;
+ 	}
+ 
+ 	/*
+ 	 * Clear RTS and DTR lines (they have special meaning)
+ 	 */
+ 
+ 	state = TIOCM_RTS | TIOCM_DTR;
+ 	if (ioctl(fd, TIOCMBIC, &state) < 0) {
+ 		com_err(whoami, errno, "while clearing DTR and RTS");
+ 		goto cleanup;
+ 	}
+ 
+ 	/*
+ 	 * We really don't want non-blocking (but we need it so the open
+ 	 * doesn't hang if CD isn't asserted)
+ 	 */
+ 
+ 	state = fcntl(fd, F_GETFL, 0);
+ 	state &= ~O_NONBLOCK;
+ 	fcntl(fd, F_SETFL, state);
+ 
+ 	/*
+ 	 * Okay!  The port's all ready, so let's start talking ...
+ 	 */
+ 
+ 	if ((state = card_in(fd)) < 1) {
+ 		if (state < 0) {
+ 			fprintf(stderr, "We were unable to find a initializer "
+ 				"on port %s\n", port);
+ 			goto cleanup;
+ 		} else {
+ 			printf("Please insert the CRYPTOCard into the "
+ 			       "initializer\n");
+ 			while (! card_in(fd));
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * Alright, we've (supposedly) got a card in the initializer.
+ 	 * First off, let's engage the solenoid, and try turning the
+ 	 * card on by toggling the RESET LED.
+ 	 */
+ 
+ 	printf("Attempting to link up with card ...\n");
+ 
+ 	sleep(1);	/* Not sure if it's necessary, but their code
+ 			   does it ... */
+ 
+ 	if (send_byte_initializer(fd, SOL) < 0) {
+ 		fprintf(stderr, "Communication with initializer failed during "
+ 			"card link-up\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	/*
+ 	 * We're not sure if the card is on or off at this stage.  LED_RESET
+ 	 * toggles power, so toggle this once and check to see if the
+ 	 * card is on.  If it's not, try again, because the card might
+ 	 * have been on when it was placed in the initializer (and if
+ 	 * that doesn't work, then fail)
+ 	 */
+ 
+ 	for (i = 0; i < 2; i++) {
+ 		char adminbuf[17];
+ 
+ 		if (send_byte_initializer(fd, SOL | LED_RESET) < 0) {
+ 			fprintf(stderr, "Communication with initializer "
+ 				"failed during card probe\n");
+ 			send_error(fd);
+ 			goto cleanup;
+ 		}
+ 		sleep(1);
+ 		if (send_byte_initializer(fd, SOL) < 0) {
+ 			fprintf(stderr, "Communication with initializer "
+ 				"failed during card probe\n");
+ 			send_error(fd);
+ 			goto cleanup;
+ 		}
+ 
+ 		/*
+ 		 * We get 8 spaces at power-on
+ 		 */
+ 
+ 		state = check_card_buffer(fd, "        ");
+ 		if (state < 0) {
+ 			fprintf(stderr, "Unable to communicate with card "
+ 				"during card probe\n");
+ 			send_error(fd);
+ 			goto cleanup;
+ 		}
+ 
+ 		if (! state)
+ 			continue;
+ 
+ 		if (! send_decimal(fd, admincode)) {
+ 			fprintf(stderr, "Unable to communicate with card "
+ 				"during card probe\n");
+ 			send_error(fd);
+ 			goto cleanup;
+ 		}
+ 		
+ 		strcpy(adminbuf, "        ");
+ 		strcat(adminbuf, language_table[0].response[LOCKED]);
+ 
+ 		state = check_card_buffer(fd, adminbuf);
+ 
+ 		if (state < 0) {
+ 			fprintf(stderr, "Unable to communicate with card "
+ 				"during card probe\n");
+ 			send_error(fd);
+ 			goto cleanup;
+ 		}
+ 
+ 		if (state) {
+ 			linkflag = 1;
+ 			break;
+ 		}
+ 	}
+ 
+ 	if (! linkflag) {
+ 		fprintf(stderr, "Unable to link up with CRYPTOCard\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	printf("Connected to CRYPTOCard RB-1, starting download\n");
+ 
+ 	send_byte_initializer(fd, SOL | LED_INIT);
+ 
+ 	/*
+ 	 * Okay, the card is in, and we're talking to it.  Start downloading
+ 	 * everything we need.
+ 	 */
+ 
+ 	get_options(options, length, language);
+ 
+ 	/*
+ 	 * First, get out of the "Locked" state
+ 	 */
+ 
+ 	if (send_byte(fd, ENT_KEY) < 1) {
+ 		fprintf(stderr, "CRYPTOCard not responding\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	/*
+ 	 * See if we've got an "Options?" prompt.
+ 	 */
+ 
+ 	if (check_card_buffer(fd,
+ 		      language_table[0].response[OPTIONS]) < 1) {
+ 		fprintf(stderr, "No response from CRYPTOCard during "
+ 			"options programming\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	/* 
+ 	 * Send all of our options
+ 	 */
+ 
+ 	for (i = 0; i < 3; i++) {
+ 		if (! send_octal(fd, options[i])) {
+ 			fprintf(stderr, "No response from CRYPTOCard during "
+ 				"options programming\n");
+ 			send_error(fd);
+ 			goto cleanup;
+ 		}
+ 	}
+ 
+ 	send_byte(fd, ENT_KEY);
+ 
+ 	/*
+ 	 * Send encryption key
+ 	 */
+ 
+ 	if (check_card_buffer(fd,
+ 			language_table[language].response[KEY1]) < 1) {
+ 		fprintf(stderr, "No response from CRYPTOCard during "
+ 			"key programming\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	for (i = 0; i < 8; i++) {
+ 		sprintf(keybyte, "%03o", key->contents[i]);
+ 		if (! send_octal(fd, keybyte)) {
+ 			fprintf(stderr, "No response from CRYPTOCard during "
+ 				"key programming\n");
+ 			send_error(fd);
+ 			goto cleanup;
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * Send the ENTER key, and then check the reponse to make sure
+ 	 * it is correct (the CRYPTOCard encrypts a buffer of all
+ 	 * NULs and displays the upper 4 bytes as a check).
+ 	 */
+ 
+ 	send_byte(fd, ENT_KEY);
+ 
+ 	memset(inputblock, 0, 8);
+ 	memset(ivec, 0, 8);
+ 
+ 	/* We need to use CBC_RAW to avoid the CRC junk */
+ 
+ 	krb5_use_enctype(context, &eblock, ENCTYPE_DES_CBC_RAW);
+ 	if ((retval = krb5_process_key(context, &eblock, key))) {
+ 		com_err(whoami, retval, "while processing RB-1 key for key test");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	if ((retval = krb5_encrypt(context, inputblock, outputblock, 8,
+ 				   &eblock, ivec))) {
+ 		com_err(whoami, retval, "while encrypting key test data");
+ 		krb5_finish_key(context, &eblock);
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	krb5_finish_key(context, &eblock);
+ 
+ 	for (i = 0; i < 4; i++)
+ 		sprintf(&testbytes[i*2], "%02X", outputblock[i]);
+ 
+ 	if (check_card_buffer(fd, testbytes) < 1) {
+ 		fprintf(stderr, "Key test response did not match computed "
+ 			"result\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	send_byte(fd, ENT_KEY);
+ 
+ 	/*
+ 	 * Time to send the userid
+ 	 */
+ 
+ 	if (check_card_buffer(fd,
+ 			language_table[language].response[USER_ID]) < 1) {
+ 		fprintf(stderr, "No response from CRYPTOCard during "
+ 			"key programming\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	for (i = 0; i < 8 && userid[i] != 0; i++) {
+ 		sprintf(keybyte, "%03o", (unsigned char) userid[i]);
+ 		testbytes[i] = userid[i];
+ 		if (! send_octal(fd, keybyte)) {
+ 			fprintf(stderr, "No response from CRYPTOCard during "
+ 				"key programming\n");
+ 			send_error(fd);
+ 			goto cleanup;
+ 		}
+ 	}
+ 
+ 	for (; i < 8; i++) {
+ 		testbytes[i] = 0x20;
+ 		if (! send_octal(fd, "040")) {
+ 			fprintf(stderr, "No response from CRYPTOCard during "
+ 				"key programming\n");
+ 			send_error(fd);
+ 			goto cleanup;
+ 		}
+ 	}
+ 
+ 	send_byte(fd, ENT_KEY);
+ 
+ 	if (check_card_buffer(fd, testbytes) < 1) {
+ 		fprintf(stderr, "Userid test response did not match expected "
+ 			"result\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	send_byte(fd, ENT_KEY);
+ 
+ 	/*
+ 	 * Last, but not least, we need to send a PIN
+ 	 */
+ 
+ 	if (check_card_buffer(fd,
+ 			language_table[language].response[NEW_PIN]) < 1) {
+ 		fprintf(stderr, "No response from CRYPTOCard during "
+ 			"PIN programming\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	if (! send_decimal(fd, pin)) {
+ 		fprintf(stderr, "No response from CRYPTOCard during "
+ 			"PIN programming\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	send_byte(fd, ENT_KEY);
+ 
+ 	if (check_card_buffer(fd,
+ 			language_table[language].response[VERIFY]) < 1) {
+ 		fprintf(stderr, "No response from CRYPTOCard during "
+ 			"PIN verification\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	if (! send_decimal(fd, pin)) {
+ 		fprintf(stderr, "No response from CRYPTOCard during "
+ 			"PIN verification\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	send_byte(fd, ENT_KEY);
+ 
+ 	/*
+ 	 * We should get a CARD_OK message now
+ 	 */
+ 
+ 	if (check_card_buffer(fd,
+ 			language_table[language].response[CARD_OK]) < 1) {
+ 		fprintf(stderr, "Did not get final OK message from RB-1\n");
+ 		send_error(fd);
+ 		goto cleanup;
+ 	}
+ 
+ 	printf("CRYPTOCard programming successful!\n");
+ 
+ 	send_byte_initializer(fd, LED_DONE);
+ 
+ cleanup:
+ 	if (fd != -1)
+ 		close(fd);
+ 
+ 	return;
+ }
+ 
+ 
+ 
+ /*
+  * Find out if there is a card inserted into the initializer
+  */
+ 
+ static int
+ card_in(int fd)
+ {
+ 	int retval;
+ 
+ 	retval = send_byte_initializer(fd, LED_INSERT);
+ 
+ 	if (retval == -1)
+ 		return -1;
+ 	
+ 	/*
+ 	 * If we got something back, the low bit will be set if there's
+ 	 * a card in the initializer (I don't know what the other status
+ 	 * bits mean)
+ 	 */
+ 	
+ 	return retval & 0x01;
+ }
+ 
+ /*
+  * Send a byte to the RB-1 CRYPTOCard
+  */
+ 
+ static int send_byte(int fd, int byte) {
+ 	unsigned char data = byte;
+ 
+ 	return write(fd, &data, 1);
+ }
+ 
+ /*
+  * Send a byte to the RB Initializer hardware itself (by asserting RTS)
+  */
+ 
+ static int
+ send_byte_initializer(int fd, int byte)
+ {
+ 	int state, n;
+ 	unsigned char data;
+ 
+ 	state = TIOCM_RTS;
+ 	if (ioctl(fd, TIOCMBIS, &state) < 0)
+ 		return -1;
+ 	state = TIOCM_RTS;
+ 	
+ 	n = send_byte(fd, byte);
+ 
+ 	if (n != 1) {
+ 		ioctl(fd, TIOCMBIC, &state);
+ 		return -1;
+ 	}
+ 	
+ 	n = read(fd, &data, 1);
+ 	ioctl(fd, TIOCMBIC, &state);
+ 
+ 	if (n != 1)
+ 		return -1;
+ 	
+ 	return data;
+ }
+ 
+ /*
+  * Receive a buffer from the card, and see if it's what we were expecting
+  */
+ 
+ static int
+ check_card_buffer(int fd, char *buffer)
+ {
+ 	char *newbuf;
+ 	int length = strlen(buffer), i, cc;
+ 
+ 	newbuf = malloc(length + 1);
+ 
+ 	if (newbuf == NULL)
+ 		return -1;
+ 	
+ 	for (i = 0; i < length; i++) {
+ 		cc = read(fd, &newbuf[i], 1);
+ 		if (cc < 1) {
+ 			free(newbuf);
+ 			return 0;
+ 		}
+ 	}
+ 
+ 	if (strncmp(newbuf, buffer, length) == 0) {
+ 		free(newbuf);
+ 		return 1;
+ 	} else {
+ 		free(newbuf);
+ 		return 0;
+ 	}
+ }
+ 
+ /*
+  * Send a decimal string to the CRYPTOCard
+  */
+ 
+ static int
+ send_decimal(int fd, char *buffer)
+ {
+ 	int i, cc;
+ 
+ 	for (i = 0; i < strlen(buffer); i++) {
+ 		cc = send_byte(fd, (unsigned char) (buffer[i] - '0'));
+ 		if (cc < 1)
+ 			return 0;
+ 	}
+ 
+ 	return 1;
+ }
+ 
+ /*
+  * Send an octal string (with SCROLL key) to the CRYPTOCard
+  */
+ 
+ static int
+ send_octal(int fd, char *buffer)
+ {
+ 	int i;
+ 	char data;
+ 
+ 	for (i = 0; i < 3; i++) {
+ 		if (send_byte(fd, (unsigned char) (buffer[i] - '0')) < 1)
+ 			return 0;
+ 		read(fd, &data, 1);
+ 	}
+ 
+ 	if (send_byte(fd, SCROLL_KEY) < 1)
+ 		return 0;
+ 	
+ 	read(fd, &data, 1);
+ 
+ 	return 1;
+ }
+ 
+ /*
+  * Light error light, and return
+  */
+ 
+ static void
+ send_error(int fd)
+ {
+ 	send_byte_initializer(fd, LED_ERROR);
+ }
+ 
+ /*
+  * Get option strings based on our inputs
+  */
+ 
+ static void
+ get_options(char options[3][4], int length, int language)
+ {
+ 	/*
+ 	 * For now, we always default to user changeable PIN, hex display
+ 	 */
+ 
+ 	sprintf(options[0], "%03o", 0100);
+ 
+ 	/*
+ 	 * Default to Event-Synchronous with userid, unlimited number
+ 	 * of attempts allowed, and selectable minimum PIN length
+ 	 */
+ 
+ 	sprintf(options[1], "%03o", (3 << 6) + length);
+ 
+ 	/*
+ 	 * Turn-off after 60 seconds, single encryption key,
+ 	 * and selectable language
+ 	 */
+ 
+ 	sprintf(options[2], "%03o", (1 << 6) + (language << 3) + 1);
+ }
+ 
+ static void ktadd_usage()
+ {
+ 	fprintf(stderr, "Usage: card_add [options] principal\n");
+ 	fprintf(stderr, "\t options are: \n");
+ 	fprintf(stderr, "\t\t[-i [-d /dev/...]] [-l language] [-u userid]\n\t\t [-p initial pin] [-n minimum pin length]\n");
+ }
+ 
+ #else /* KADMIN_CRYPTOCARD */
+ 
+ void
+ kadmin_ktadd_cryptocard(int argc, char **argv)
+ {
+ 	fprintf(stderr,"card_add not supported on this system\n");
+ }
+ 
+ #endif /* KADMIN_CRYTPOCARD */
Index: kadmin/cli/kadmin.c
diff -c krb5/kadmin/cli/kadmin.c:1.1.1.1 krb5/kadmin/cli/kadmin.c:1.3
*** krb5/kadmin/cli/kadmin.c:1.1.1.1	Mon Jun  2 17:55:06 1997
--- krb5/kadmin/cli/kadmin.c	Wed Jun  3 12:11:47 1998
***************
*** 709,714 ****
--- 709,730 ----
  	    ++*randkey;
  	    continue;
  	}
+ 	if (strlen(argv[i]) == 13 &&
+ 	    !strcmp("-lastpwchange", argv[i])) {
+ 	    if (++i > argc - 2)
+ 		return -1;
+ 	    else {
+ 		date = get_date(argv[i], NULL);
+  		if (date == (time_t)-1) {
+ 		     fprintf(stderr, "Invalid date specification \"%s\".\n",
+ 			     argv[i]);
+ 		     return -1;
+  		}
+ 		oprinc->last_pwd_change = date;
+ 		*mask |= KADM5_LAST_PWD_CHANGE;
+ 		continue;
+ 	    }
+ 	}
  	for (j = 0; j < sizeof (flags) / sizeof (struct pflag); j++) {
  	    if (strlen(argv[i]) == flags[j].flaglen + 1 &&
  		!strcmp(flags[j].flagname,
***************
*** 762,768 ****
  {
       fprintf(stderr, "usage: %s [options] principal\n", func);
       fprintf(stderr, "\toptions are:\n");
!      fprintf(stderr, "\t\t[-expire expdate] [-pwexpire pwexpdate] [-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] [-clearpolicy]\n\t\t[-maxrenewlife maxrenewlife] [{+|-}attribute]\n");
       fprintf(stderr, "\tattributes are:\n");
       fprintf(stderr, "%s%s%s",
  	     "\t\tallow_postdated allow_forwardable allow_tgs_req allow_renewable\n",
--- 778,784 ----
  {
       fprintf(stderr, "usage: %s [options] principal\n", func);
       fprintf(stderr, "\toptions are:\n");
!      fprintf(stderr, "\t\t[-expire expdate] [-pwexpire pwexpdate] [-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] [-clearpolicy]\n\t\t[-maxrenewlife maxrenewlife] [-lastpwchange pwchangedate]\n\t\t[{+|-}attribute]\n");
       fprintf(stderr, "\tattributes are:\n");
       fprintf(stderr, "%s%s%s",
  	     "\t\tallow_postdated allow_forwardable allow_tgs_req allow_renewable\n",
***************
*** 785,791 ****
  
      if (dummybuf[0] == 0) {
  	 for (i = 0; i < 256; i++)
! 	      dummybuf[i] = (i+1) % 256;
      }
      
      /* Zero all fields in request structure */
--- 801,808 ----
  
      if (dummybuf[0] == 0) {
  	 for (i = 0; i < 256; i++)
! 	      /* Use (i*2+1) so that results passes cracklib */
! 	      dummybuf[i] = (i*2+1) % 256;
      }
      
      /* Zero all fields in request structure */
Index: kadmin/cli/kadmin_ct.ct
diff -c krb5/kadmin/cli/kadmin_ct.ct:1.1.1.1 krb5/kadmin/cli/kadmin_ct.ct:1.2
*** krb5/kadmin/cli/kadmin_ct.ct:1.1.1.1	Mon Jun  2 17:55:06 1997
--- krb5/kadmin/cli/kadmin_ct.ct	Fri Jun 19 12:01:53 1998
***************
*** 65,70 ****
--- 65,73 ----
  request kadmin_keytab_remove, "Remove entry(s) from a keytab",
  	ktremove, ktrem;
  
+ request kadmin_ktadd_cryptocard, "Get/Program an encryption key for a CRYPTOCard RB-1",
+ 	card_add, cardadd;
+ 
  # list_requests is generic -- unrelated to Kerberos
  request	ss_list_requests, "List available requests.",
  	list_requests, lr, "?";
Index: kadmin/dbutil/configure.in
diff -c krb5/kadmin/dbutil/configure.in:1.1.1.1 krb5/kadmin/dbutil/configure.in:1.2
*** krb5/kadmin/dbutil/configure.in:1.1.1.1	Mon Jun  2 17:55:08 1997
--- krb5/kadmin/dbutil/configure.in	Thu Sep 18 16:37:02 1997
***************
*** 12,16 ****
  USE_GSSAPI_LIBRARY
  KRB5_LIBRARIES
  V5_USE_SHARED_LIB
! AC_CHECK_HEADERS(krb_db.h kdc.h) dnl 
  V5_AC_OUTPUT_MAKEFILE
--- 12,16 ----
  USE_GSSAPI_LIBRARY
  KRB5_LIBRARIES
  V5_USE_SHARED_LIB
! AC_CHECK_HEADERS(krb_db.h kdc.h memory.h) dnl 
  V5_AC_OUTPUT_MAKEFILE
Index: kadmin/dbutil/dump.c
diff -c krb5/kadmin/dbutil/dump.c:1.1.1.1 krb5/kadmin/dbutil/dump.c:1.2
*** krb5/kadmin/dbutil/dump.c:1.1.1.1	Mon Jun  2 17:55:08 1997
--- krb5/kadmin/dbutil/dump.c	Mon Jul  7 16:12:42 1997
***************
*** 568,574 ****
      char		*name;
      krb5_tl_data	*tlp;
      krb5_key_data	*kdata;
!     int			counter, skip, i, j;
  
      /* Initialize */
      arg = (struct dump_args *) ptr;
--- 568,574 ----
      char		*name;
      krb5_tl_data	*tlp;
      krb5_key_data	*kdata;
!     int			counter, i, j;
  
      /* Initialize */
      arg = (struct dump_args *) ptr;
***************
*** 612,639 ****
  	/*
  	 * Make sure that the tagged list is reasonably correct.
  	 */
! 	counter = skip = 0;
! 	for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
! 	     /*
! 	      * don't dump tl data types we know aren't understood by
! 	      * earlier revisions [krb5-admin/89]
! 	      */
! 	     switch (tlp->tl_data_type) {
! 	     case KRB5_TL_KADM_DATA:
! 		  skip++;
! 		  break;
! 	     default:
! 		  counter++;
! 		  break;
! 	     }
! 	}
! 	
! 	if (counter + skip == entry->n_tl_data) {
  	    /* Pound out header */
  	    fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%s\t",
  		    (int) entry->len,
  		    strlen(name),
! 		    counter,
  		    (int) entry->n_key_data,
  		    (int) entry->e_length,
  		    name);
--- 612,626 ----
  	/*
  	 * Make sure that the tagged list is reasonably correct.
  	 */
! 	counter = 0;
! 	for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next)
! 	    counter++;
! 	if (counter == entry->n_tl_data) {
  	    /* Pound out header */
  	    fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%s\t",
  		    (int) entry->len,
  		    strlen(name),
! 		    (int) entry->n_tl_data,
  		    (int) entry->n_key_data,
  		    (int) entry->e_length,
  		    name);
***************
*** 648,656 ****
  		    entry->fail_auth_count);
  	    /* Pound out tagged data. */
  	    for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
- 		if (tlp->tl_data_type == KRB5_TL_KADM_DATA)
- 		     continue; /* see above, [krb5-admin/89] */
- 
  		fprintf(arg->ofile, "%d\t%d\t",
  			(int) tlp->tl_data_type,
  			(int) tlp->tl_data_length);
--- 635,640 ----
***************
*** 697,704 ****
  	}
  	else {
  	    fprintf(stderr, sdump_tl_inc_err,
! 		    arg->programname, name, counter+skip,
! 		    (int) entry->n_tl_data); 
  	    retval = EINVAL;
  	}
      }
--- 681,687 ----
  	}
  	else {
  	    fprintf(stderr, sdump_tl_inc_err,
! 		    arg->programname, name, counter, (int) entry->n_tl_data);
  	    retval = EINVAL;
  	}
      }
Index: kadmin/dbutil/ovload.c
diff -c krb5/kadmin/dbutil/ovload.c:1.1.1.1 krb5/kadmin/dbutil/ovload.c:1.2
*** krb5/kadmin/dbutil/ovload.c:1.1.1.1	Mon Jun  2 17:55:09 1997
--- krb5/kadmin/dbutil/ovload.c	Thu Sep 18 16:37:04 1997
***************
*** 1,7 ****
--- 1,9 ----
  #include    <unistd.h>
  #include    <string.h>
  #include    <stdlib.h>
+ #ifdef HAVE_MEMORY_H
  #include    <memory.h>
+ #endif
  
  #include    <kadm5/adb.h>
  #include    "import_err.h"
Index: kadmin/server/Makefile.in
diff -c krb5/kadmin/server/Makefile.in:1.1.1.1 krb5/kadmin/server/Makefile.in:1.2
*** krb5/kadmin/server/Makefile.in:1.1.1.1	Mon Jun  2 17:55:17 1997
--- krb5/kadmin/server/Makefile.in	Mon Aug  4 15:48:45 1997
***************
*** 1,7 ****
  CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
  
  PROG = kadmind
! OBJS = kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o misc.o server_glue_v1.o
  
  all:: $(PROG)
  
--- 1,7 ----
  CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
  
  PROG = kadmind
! OBJS = kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o schpw.o misc.o server_glue_v1.o
  
  all:: $(PROG)
  
Index: kadmin/server/configure.in
diff -c krb5/kadmin/server/configure.in:1.1.1.1 krb5/kadmin/server/configure.in:1.2
*** krb5/kadmin/server/configure.in:1.1.1.1	Mon Jun  2 17:55:18 1997
--- krb5/kadmin/server/configure.in	Thu Sep 18 16:37:09 1997
***************
*** 7,12 ****
--- 7,13 ----
  dnl CHECK_SETJMP
  dnl CHECK_WAIT_TYPE
  dnl ET_RULES
+ AC_CHECK_HEADERS(memory.h)
  USE_KADMSRV_LIBRARY
  USE_GSSRPC_LIBRARY
  USE_GSSAPI_LIBRARY
Index: kadmin/server/kadm_rpc_svc.c
diff -c krb5/kadmin/server/kadm_rpc_svc.c:1.1.1.2 krb5/kadmin/server/kadm_rpc_svc.c:1.3
*** krb5/kadmin/server/kadm_rpc_svc.c:1.1.1.2	Mon Nov  3 16:33:02 1997
--- krb5/kadmin/server/kadm_rpc_svc.c	Mon Nov  3 17:13:52 1997
***************
*** 5,10 ****
--- 5,18 ----
   * $Source$
   * 
   * $Log$
+  * Revision 1.3  1997/11/03 22:13:52  kenh
+  * Fix up conflicts from Release 1.0.2 import.
+  *
+  * Revision 1.2  1997/09/18 20:37:10  vwelch
+  * ConvexOS Port.
+  *
+  * Revision 1.1.1.1  1997/06/02 21:55:18  kenh
+  * Initial import of R1.0 from MIT.
   * Revision 1.1.1.2  1997/11/03 21:33:02  kenh
   * Import of Kerberos 5, Release 1.0.2
   *
***************
*** 77,83 ****
--- 85,93 ----
  #include <stdio.h>
  #include <rpc/rpc.h>
  #include <syslog.h>
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  #include <kadm5/kadm_rpc.h>
  #include <krb5.h>
  #include <kadm5/admin.h>
Index: kadmin/server/misc.c
diff -c krb5/kadmin/server/misc.c:1.1.1.2 krb5/kadmin/server/misc.c:1.2
*** krb5/kadmin/server/misc.c:1.1.1.2	Mon Nov  3 16:33:04 1997
--- krb5/kadmin/server/misc.c	Mon Jun  8 15:09:29 1998
***************
*** 1,6 ****
  /*
!  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
   *
   * $Header$
   */
  
--- 1,36 ----
  /*
!  * Copyright, OpenVision Technologies, Inc., 1996, All Rights Reserved
   *
+  * WARNING:  Retrieving the OpenVision Kerberos Administration system
+  * source code, as described below, indicates your acceptance of the
+  * following terms.  If you do not agree to the following terms, do not
+  * retrieve the OpenVision Kerberos administration system.
+  *
+  * You may freely use and distribute the Source Code and Object Code
+  * compiled from it, but this Source Code is provided to you "AS IS"
+  * EXCLUSIVE OF ANY WARRANTY, INCLUDING, WITHOUT LIMITATION, ANY
+  * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR
+  * ANY OTHER WARRANTY, WHETHER EXPRESS OR IMPLIED.  IN NO EVENT WILL
+  * OPENVISION HAVE ANY LIABILITY FOR ANY LOST PROFITS, LOSS OF DATA OR
+  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY
+  * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS
+  * AGREEMENT, INCLUDING, WITHOUT LIMITATION, THOSE RESULTING FROM THE
+  * USE OF THE SOURCE CODE, OR THE FAILURE OF THE SOURCE CODE TO PERFORM,
+  * OR FOR ANY OTHER REASON.
+  *
+  * OpenVision retains all rights, title, and interest in the donated
+  * Source Code.  With respect to OpenVision's copyrights in the donated
+  * Source Code, OpenVision also retains rights to derivative works of
+  * the Source Code whether created by OpenVision or a third party.
+  *
+  * OpenVision Technologies, Inc. has donated this Kerberos
+  * Administration system to MIT for inclusion in the standard Kerberos 5
+  * distribution. This donation underscores our commitment to continuing
+  * Kerberos technology development and our gratitude for the valuable
+  * work which has been performed by MIT and the Kerberos community.
+  */
+ 
+ /*
   * $Header$
   */
  
***************
*** 14,42 ****
  #include    "misc.h"
  
  /*
!  * Function: chpass_principal_wrapper
   * 
!  * Purpose: wrapper to kadm5_chpass_principal that checks to see if
   *	    pw_min_life has been reached. if not it returns an error.
-  *	    otherwise it calls kadm5_chpass_principal
   *
   * Arguments:
!  *	principal	(input) krb5_principals whose password we are
!  *				changing
!  *	passoword	(input) passowrd we are going to change to.
!  * 	<return value>	0 on sucsess error code on failure.
   *
   * Requires:
   *	kadm5_init to have been run.
   * 
   * Effects:
!  *	calls kadm5_chpass_principal which changes the kdb and the
!  *	the admin db.
   *
   */
  kadm5_ret_t
! chpass_principal_wrapper(void *server_handle,
! 			 krb5_principal principal, char *password)
  {
      krb5_int32			now;
      kadm5_ret_t			ret;
--- 44,67 ----
  #include    "misc.h"
  
  /*
!  * Function: check_policy_minlife
   * 
!  * Purpose: helper function that checks to see if
   *	    pw_min_life has been reached. if not it returns an error.
   *
   * Arguments:
!  *	principal	(input) krb5_principal to check
!  * 	<return value>	0 on success error code on failure.
   *
   * Requires:
   *	kadm5_init to have been run.
   * 
   * Effects:
!  *	none
   *
   */
  kadm5_ret_t
! check_policy_minlife(void *server_handle, krb5_principal principal)
  {
      krb5_int32			now;
      kadm5_ret_t			ret;
***************
*** 71,77 ****
      }
      if (ret = kadm5_free_principal_ent(handle->lhandle, &princ))
  	 return ret;
!     
      return kadm5_chpass_principal(server_handle, principal, password);
  }
  
--- 96,136 ----
      }
      if (ret = kadm5_free_principal_ent(handle->lhandle, &princ))
  	 return ret;
! 
!     return(KADM5_OK);
! }
! 
! 
! /*
!  * Function: chpass_principal_wrapper
!  * 
!  * Purpose: wrapper to kadm5_chpass_principal that checks to see if
!  *	    pw_min_life has been reached. if not it returns an error.
!  *	    otherwise it calls kadm5_chpass_principal
!  *
!  * Arguments:
!  *	principal	(input) krb5_principals whose password we are
!  *				changing
!  *	password	(input) password we are going to change to.
!  * 	<return value>	0 on success error code on failure.
!  *
!  * Requires:
!  *	kadm5_init to have been run.
!  * 
!  * Effects:
!  *	calls kadm5_chpass_principal which changes the kdb and the
!  *	the admin db.
!  *
!  */
! kadm5_ret_t
! chpass_principal_wrapper(void *server_handle,
! 			 krb5_principal principal, char *password)
! {
!     kadm5_ret_t			ret;
! 
!     if (ret = check_policy_minlife(server_handle, principal))
! 	 return(ret);
! 
      return kadm5_chpass_principal(server_handle, principal, password);
  }
  
***************
*** 100,138 ****
  			  krb5_principal principal,
  			  krb5_keyblock **keys, int *n_keys)
  {
- 
-     krb5_int32			now;
      kadm5_ret_t			ret;
-     kadm5_policy_ent_rec	pol;
-     kadm5_principal_ent_rec	princ;
-     kadm5_server_handle_t	handle = server_handle;
  
!     if (ret = krb5_timeofday(handle->context, &now))
! 	return ret;
  
-     if((ret = kadm5_get_principal(handle->lhandle,
- 				  principal, &princ,
- 				  KADM5_PRINCIPAL_NORMAL_MASK)) !=
-        OSA_ADB_OK) 
- 	 return ret;
-     if(princ.aux_attributes & KADM5_POLICY) {
- 	if((ret=kadm5_get_policy(handle->lhandle,
- 				 princ.policy, &pol)) != KADM5_OK) {
- 	    (void) kadm5_free_principal_ent(handle->lhandle, &princ);
- 	    return ret;
- 	}
- 	if((now - princ.last_pwd_change) < pol.pw_min_life &&
- 	   !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
- 	    (void) kadm5_free_policy_ent(handle->lhandle, &pol);
- 	    (void) kadm5_free_principal_ent(handle->lhandle, &princ);
- 	    return KADM5_PASS_TOOSOON;
- 	}
- 	if (ret = kadm5_free_policy_ent(handle->lhandle, &pol)) {
- 	    (void) kadm5_free_principal_ent(handle->lhandle, &princ);
- 	    return ret;
-         }
-     }
-     if (ret = kadm5_free_principal_ent(handle->lhandle, &princ))
- 	 return ret;
      return kadm5_randkey_principal(server_handle, principal, keys, n_keys);
  }
--- 159,169 ----
  			  krb5_principal principal,
  			  krb5_keyblock **keys, int *n_keys)
  {
      kadm5_ret_t			ret;
  
!     if (ret = check_policy_minlife(server_handle, principal))
! 	 return(ret);
  
      return kadm5_randkey_principal(server_handle, principal, keys, n_keys);
  }
+ 
Index: kadmin/server/misc.h
diff -c krb5/kadmin/server/misc.h:1.1.1.2 krb5/kadmin/server/misc.h:1.2
*** krb5/kadmin/server/misc.h:1.1.1.2	Mon Nov  3 16:33:07 1997
--- krb5/kadmin/server/misc.h	Mon Jun  8 15:09:30 1998
***************
*** 4,9 ****
--- 4,13 ----
   * $Header$
   * 
   * $Log$
+  * Revision 1.2  1998/06/08 19:09:30  kenh
+  * More fixes from Marc Horowitz for the minimum password lifetime bug
+  * in schpw.c.
+  *
   * Revision 1.1.1.2  1997/11/03 21:33:07  kenh
   * Import of Kerberos 5, Release 1.0.2
   *
***************
*** 47,52 ****
--- 51,58 ----
  				      krb5_principal principal,
  				      krb5_keyblock **key,
  				      int *n_keys);
+ kadm5_ret_t check_policy_minlife(void *server_handle,
+ 				 krb5_principal principal);
  
  kadm5_ret_t kadm5_get_principal_v1(void *server_handle,
  				   krb5_principal principal, 
Index: kadmin/server/ovsec_kadmd.c
diff -c krb5/kadmin/server/ovsec_kadmd.c:1.1.1.3 krb5/kadmin/server/ovsec_kadmd.c:1.5
*** krb5/kadmin/server/ovsec_kadmd.c:1.1.1.3	Wed May 12 13:22:29 1999
--- krb5/kadmin/server/ovsec_kadmd.c	Wed May 12 14:55:55 1999
***************
*** 76,82 ****
  void log_badauth_display_status(char *msg, OM_uint32 major, OM_uint32 minor);
  void log_badauth_display_status_1(char *m, OM_uint32 code, int type,
  				  int rec);
! 	
  
  /*
   * Function: usage
--- 76,89 ----
  void log_badauth_display_status(char *msg, OM_uint32 major, OM_uint32 minor);
  void log_badauth_display_status_1(char *m, OM_uint32 code, int type,
  				  int rec);
! 
! int schpw;
! void do_schpw(int s, kadm5_config_params *params);
! kadm5_config_params params;
! krb5_error_code process_chpw_request(krb5_context context, void *server_handle,
! 				     char *realm, int s, krb5_keytab keytab,
! 				     struct sockaddr_in *sin,
! 				     krb5_data *req, krb5_data *rep);
  
  /*
   * Function: usage
***************
*** 115,121 ****
       int s;
       short port = 0;
       auth_gssapi_name names[4];
-      kadm5_config_params params;
  
       names[0].name = names[1].name = names[2].name = names[3].name = NULL;
       names[0].type = names[1].type = names[2].type = names[3].type =
--- 122,127 ----
***************
*** 222,227 ****
--- 228,243 ----
  	  exit(1);
       }
  
+      if ((schpw = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ 	  krb5_klog_syslog(LOG_ERR, "Cannot create simple chpw socket: %s",
+ 			  error_message(errno));
+ 	  fprintf(stderr, "Cannot create simple chpw socket: %s",
+ 		  error_message(errno));
+ 	  kadm5_destroy(global_server_handle);
+ 	  krb5_klog_close();	  
+ 	  exit(1);
+      }
+ 
  #ifdef SO_REUSEADDR
       /* the old admin server turned on SO_REUSEADDR for non-default
  	port numbers.  this was necessary, on solaris, for the tests
***************
*** 248,253 ****
--- 264,282 ----
  	     krb5_klog_close();	  
  	     exit(1);
  	 }
+ 	 if (setsockopt(schpw,
+ 			SOL_SOCKET,
+ 			SO_REUSEADDR,
+ 			(char *) &allowed,
+ 			sizeof(allowed)) < 0) {
+ 	     krb5_klog_syslog(LOG_ERR, "Cannot set SO_REUSEADDR on simple "
+ 			      "chpw socket: %s", error_message(errno));
+ 	     fprintf(stderr, "Cannot set SO_REUSEADDR on simple "
+ 		     "chpw socket: %s", error_message(errno));
+ 	     kadm5_destroy(global_server_handle);
+ 	     krb5_klog_close();	  
+ 	     exit(1);
+ 	 }
       }
  #endif /* SO_REUSEADDR */
       if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
***************
*** 283,289 ****
--- 312,351 ----
  	  krb5_klog_close();	  
  	  exit(1);
       }
+ 
+      memset(&addr, 0, sizeof(addr));
+      addr.sin_family = AF_INET;
+      addr.sin_addr.s_addr = INADDR_ANY;
+      /* XXX */
+      addr.sin_port = htons(params.kpasswd_port);
       
+      if (bind(schpw, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ 	  int oerrno = errno;
+ 	  fprintf(stderr, "%s: Cannot bind socket.\n", whoami);
+ 	  fprintf(stderr, "bind: %s\n", error_message(oerrno));
+ 	  errno = oerrno;
+ 	  krb5_klog_syslog(LOG_ERR, "Cannot bind simple chpw socket: %s",
+ 			   error_message(errno));
+ 	  if(oerrno == EADDRINUSE) {
+ 	       char *w = strrchr(whoami, '/');
+ 	       if (w) {
+ 		    w++;
+ 	       }
+ 	       else {
+ 		    w = whoami;
+ 	       }
+ 	       fprintf(stderr,
+ "This probably means that another %s process is already\n"
+ "running, or that another program is using the server port (number %d).\n"
+ "If another %s is already running, you should kill it before\n"
+ "restarting the server.\n",
+ 		       w, ntohs(addr.sin_port), w, w, w);
+ 	  }
+ 	  kadm5_destroy(global_server_handle);
+ 	  krb5_klog_close();	  
+ 	  exit(1);
+      }
+ 
       transp = svctcp_create(s, 0, 0);
       if(transp == NULL) {
  	  fprintf(stderr, "%s: Cannot create RPC service.\n", whoami);
***************
*** 429,434 ****
--- 491,497 ----
  	  timeout.tv_sec = TIMEOUT;
  	  timeout.tv_usec = 0;
  	  rfd = svc_fdset;
+ 	  FD_SET(schpw, &rfd);
  	  switch(select(sz, (fd_set *) &rfd, NULL, NULL, &timeout)) {
  	  case -1:
  	       if(errno == EINTR)
***************
*** 439,445 ****
  	       reset_db();
  	       break;
  	  default:
! 	       svc_getreqset(&rfd);
  	  }
       }
  }
--- 502,511 ----
  	       reset_db();
  	       break;
  	  default:
! 	       if (FD_ISSET(schpw, &rfd))
! 		    do_schpw(schpw, &params);
! 	       else 
! 	            svc_getreqset(&rfd);
  	  }
       }
  }
***************
*** 559,564 ****
--- 625,631 ----
  
  void request_exit(int signum)
  {
+      signal(signum, request_exit);	/* Reset signal */
       krb5_klog_syslog(LOG_DEBUG, "Got signal to request exit");
       signal_request_exit = 1;
       return;
***************
*** 575,580 ****
--- 642,648 ----
   */
  void sig_pipe(int unused)
  {
+      signal(SIGPIPE, sig_pipe);		/* Reset signal */
       krb5_klog_syslog(LOG_NOTICE, "Warning: Received a SIGPIPE; probably a "
  	    "client aborted.  Continuing.");
       return;
***************
*** 787,790 ****
--- 855,951 ----
  	  if (!msg_ctx)
  	       break;
       }
+ }
+ 
+ void do_schpw(int s1, kadm5_config_params *params)
+ {
+      krb5_error_code ret;
+      /* XXX buffer = ethernet mtu */
+      char req[1500];
+      int len;
+      struct sockaddr_in from;
+      int fromlen;
+      krb5_keytab kt;
+      krb5_data reqdata, repdata;
+      int s2;
+ 
+      fromlen = sizeof(from);
+      if ((len = recvfrom(s1, req, sizeof(req), 0, (struct sockaddr *)&from,
+ 			 &fromlen)) < 0) {
+ 	  krb5_klog_syslog(LOG_ERR, "chpw: Couldn't receive request from %s: "
+ 			   "%s", inet_ntoa(from.sin_addr),
+ 			   error_message(errno));
+ 	  return;
+      }
+ 
+      if (ret = krb5_kt_resolve(context, params->admin_keytab, &kt)) {
+ 	  krb5_klog_syslog(LOG_ERR, "chpw: Couldn't open admin keytab: %s: %s",
+ 			   inet_ntoa(from.sin_addr), error_message(ret));
+ 	  return;
+      }
+ 
+      reqdata.length = len;
+      reqdata.data = req;
+ 
+     /* this is really obscure.  s1 is used for all communications.  it
+        is left unconnected in case the server is multihomed and routes
+        are asymmetric.  s2 is connected to resolve routes and get
+        addresses.  this is the *only* way to get proper addresses for
+        multihomed hosts if routing is asymmetric.
+ 
+        A related problem in the server, but not the client, is that
+        many os's have no way to disconnect a connected udp socket, so
+        the s2 socket needs to be closed and recreated for each
+        request.  The s1 socket must not be closed, or else queued
+        requests will be lost.
+ 
+        A "naive" client implementation (one socket, no connect,
+        hostname resolution to get the local ip addr) will work and
+        interoperate if the client is single-homed. */
+ 
+      if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ 	  krb5_klog_syslog(LOG_ERR, "main: cannot create connecting socket: %s",
+ 			   error_message(errno));
+ 	  fprintf(stderr, "Cannot create connecting socket: %s",
+ 		  error_message(errno));
+ 	  kadm5_destroy(global_server_handle);
+ 	  krb5_klog_close();
+ 	  exit(1);
+      }
+ 
+      if (connect(s2, (struct sockaddr *) &from, sizeof(from)) < 0) {
+ 	  krb5_klog_syslog(LOG_ERR, "chpw: Couldn't connect to client %s: %s",
+ 			   inet_ntoa(from.sin_addr), error_message(errno));
+ 	  return;
+      }
+ 
+      if (ret = process_chpw_request(context, global_server_handle,
+ 				    params->realm, s2, kt, &from,
+ 				    &reqdata, &repdata)) {
+ 	  krb5_klog_syslog(LOG_ERR, "chpw: Error processing request from %s: "
+ 			   "%s", inet_ntoa(from.sin_addr),
+ 			   error_message(errno));
+      }
+ 
+      close(s2);
+ 
+      if (repdata.length == 0)
+ 	  /* just qreturn.  This means something really bad happened */
+ 	  return;
+ 
+      len = sendto(s1, repdata.data, repdata.length, 0,
+ 		  (struct sockaddr *) &from, sizeof(from));
+ 
+      if (len < repdata.length) {
+ 	  krb5_xfree(repdata.data);
+ 
+ 	  krb5_klog_syslog(LOG_ERR, "chpw: Error sending reply to %s: %s",
+ 			   inet_ntoa(from.sin_addr), error_message(errno));
+ 
+ 	  return;
+      }
+ 
+      krb5_xfree(repdata.data);
+ 
+      return;
  }
Index: kadmin/server/schpw.c
diff -c /dev/null krb5/kadmin/server/schpw.c:1.2
*** /dev/null	Thu Sep 23 15:41:04 1999
--- krb5/kadmin/server/schpw.c	Mon Jun  8 10:06:26 1998
***************
*** 0 ****
--- 1,428 ----
+ #define NEED_SOCKETS
+ #include "k5-int.h"
+ #include <kadm5/admin.h>
+ /* sigh */
+ #include "kadm5/admin_internal.h"
+ 
+ #include <stdio.h>
+ #include <errno.h>
+ #include <time.h>
+ 
+ krb5_error_code
+ process_chpw_request(context, server_handle, realm, s, keytab, sin, req, rep)
+      krb5_context context;
+      void *server_handle;
+      char *realm;
+      int s;
+      krb5_keytab keytab;
+      struct sockaddr_in *sin;
+      krb5_data *req;
+      krb5_data *rep;
+ {
+     krb5_error_code ret;
+     char *ptr;
+     int plen, vno;
+     krb5_address local_kaddr, remote_kaddr;
+     krb5_data ap_req, ap_rep;
+     krb5_auth_context auth_context;
+     krb5_principal changepw;
+     krb5_ticket *ticket;
+     krb5_data cipher, clear;
+     struct sockaddr local_addr, remote_addr;
+     int addrlen;
+     krb5_replay_data replay;
+     krb5_error krberror;
+     int numresult;
+     char strresult[1024];
+ 
+     ret = 0;
+     rep->length = 0;
+ 
+     auth_context = NULL;
+     changepw = NULL;
+     ap_rep.length = 0;
+     ticket = NULL;
+     clear.length = 0;
+     cipher.length = 0;
+ 
+     if (req->length < 4) {
+ 	/* either this, or the server is printing bad messages,
+ 	   or the caller passed in garbage */
+ 	ret = KRB5KRB_AP_ERR_MODIFIED;
+ 	numresult = KRB5_KPASSWD_MALFORMED;
+ 	strcpy(strresult, "Request was truncated");
+ 	goto chpwfail;
+     }
+ 
+     ptr = req->data;
+ 
+     /* verify length */
+ 
+     plen = (*ptr++ & 0xff);
+     plen = (plen<<8) | (*ptr++ & 0xff);
+ 
+     if (plen != req->length)
+ 	return(KRB5KRB_AP_ERR_MODIFIED);
+ 
+     /* verify version number */
+ 
+     vno = (*ptr++ & 0xff) ;
+     vno = (vno<<8) | (*ptr++ & 0xff);
+ 
+     if (vno != 1) {
+ 	ret = KRB5KDC_ERR_BAD_PVNO;
+ 	numresult = KRB5_KPASSWD_MALFORMED;
+ 	sprintf(strresult,
+ 		"Request contained unknown protocol version number %d", vno);
+ 	goto chpwfail;
+     }
+ 
+     /* read, check ap-req length */
+ 
+     ap_req.length = (*ptr++ & 0xff);
+     ap_req.length = (ap_req.length<<8) | (*ptr++ & 0xff);
+ 
+     if (ptr + ap_req.length >= req->data + req->length) {
+ 	ret = KRB5KRB_AP_ERR_MODIFIED;
+ 	numresult = KRB5_KPASSWD_MALFORMED;
+ 	strcpy(strresult, "Request was truncated in AP-REQ");
+ 	goto chpwfail;
+     }
+ 
+     /* verify ap_req */
+ 
+     ap_req.data = ptr;
+     ptr += ap_req.length;
+ 
+     if (ret = krb5_auth_con_init(context, &auth_context)) {
+ 	numresult = KRB5_KPASSWD_HARDERROR;
+ 	strcpy(strresult, "Failed initializing auth context");
+ 	goto chpwfail;
+     }
+ 
+     if (ret = krb5_auth_con_setflags(context, auth_context,
+ 				     KRB5_AUTH_CONTEXT_DO_SEQUENCE)) {
+ 	numresult = KRB5_KPASSWD_HARDERROR;
+ 	strcpy(strresult, "Failed initializing auth context");
+ 	goto chpwfail;
+     }
+ 	
+     if (ret = krb5_build_principal(context, &changepw, strlen(realm), realm,
+ 				   "kadmin", "changepw", NULL)) {
+ 	numresult = KRB5_KPASSWD_HARDERROR;
+ 	strcpy(strresult, "Failed building kadmin/changepw principal");
+ 	goto chpwfail;
+     }
+ 
+     ret = krb5_rd_req(context, &auth_context, &ap_req, changepw, keytab,
+ 		      NULL, &ticket);
+ 
+     if (ret) {
+ 	numresult = KRB5_KPASSWD_AUTHERROR;
+ 	strcpy(strresult, "Failed reading application request");
+ 	goto chpwfail;
+     }
+ 
+     /* set up address info */
+ 
+     addrlen = sizeof(local_addr);
+ 
+     if (getsockname(s, &local_addr, &addrlen) < 0) {
+ 	ret = errno;
+ 	numresult = KRB5_KPASSWD_HARDERROR;
+ 	strcpy(strresult, "Failed getting server internet address");
+ 	goto chpwfail;
+     }
+ 
+     /* some brain-dead OS's don't return useful information from
+      * the getsockname call.  Namely, windows and solaris.  */
+ 
+     if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0) {
+ 	local_kaddr.addrtype = ADDRTYPE_INET;
+ 	local_kaddr.length =
+ 	    sizeof(((struct sockaddr_in *) &local_addr)->sin_addr);
+ 	local_kaddr.contents = 
+ 	    (char *) &(((struct sockaddr_in *) &local_addr)->sin_addr);
+     } else {
+ 	krb5_address **addrs;
+ 
+ 	krb5_os_localaddr(context, &addrs);
+ 	local_kaddr.magic = addrs[0]->magic;
+ 	local_kaddr.addrtype = addrs[0]->addrtype;
+ 	local_kaddr.length = addrs[0]->length;
+ 	local_kaddr.contents = malloc(addrs[0]->length);
+ 	memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length);
+ 
+ 	krb5_free_addresses(context, addrs);
+     }
+ 
+     addrlen = sizeof(remote_addr);
+ 
+     if (getpeername(s, &remote_addr, &addrlen) < 0) {
+ 	ret = errno;
+ 	numresult = KRB5_KPASSWD_HARDERROR;
+ 	strcpy(strresult, "Failed getting client internet address");
+ 	goto chpwfail;
+     }
+ 
+     remote_kaddr.addrtype = ADDRTYPE_INET;
+     remote_kaddr.length =
+ 	sizeof(((struct sockaddr_in *) &remote_addr)->sin_addr);
+     remote_kaddr.contents = 
+ 	(char *) &(((struct sockaddr_in *) &remote_addr)->sin_addr);
+     
+     remote_kaddr.addrtype = ADDRTYPE_INET;
+     remote_kaddr.length = sizeof(sin->sin_addr);
+     remote_kaddr.contents = (char *) &sin->sin_addr;
+     
+     /* mk_priv requires that the local address be set.
+        getsockname is used for this.  rd_priv requires that the
+        remote address be set.  recvfrom is used for this.  If
+        rd_priv is given a local address, and the message has the
+        recipient addr in it, this will be checked.  However, there
+        is simply no way to know ahead of time what address the
+        message will be delivered *to*.  Therefore, it is important
+        that either no recipient address is in the messages when
+        mk_priv is called, or that no local address is passed to
+        rd_priv.  Both is a better idea, and I have done that.  In
+        summary, when mk_priv is called, *only* a local address is
+        specified.  when rd_priv is called, *only* a remote address
+        is specified.  Are we having fun yet?  */
+ 
+     if (ret = krb5_auth_con_setaddrs(context, auth_context, NULL,
+ 				     &remote_kaddr)) {
+ 	numresult = KRB5_KPASSWD_HARDERROR;
+ 	strcpy(strresult, "Failed storing client internet address");
+ 	goto chpwfail;
+     }
+ 
+     /* verify that this is an AS_REQ ticket */
+ 
+     if (!(ticket->enc_part2->flags & TKT_FLG_INITIAL)) {
+ 	numresult = KRB5_KPASSWD_AUTHERROR;
+ 	strcpy(strresult, "Ticket must be derived from a password");
+ 	goto chpwfail;
+     }
+ 
+     /* construct the ap-rep */
+ 
+     if (ret = krb5_mk_rep(context, auth_context, &ap_rep)) {
+ 	numresult = KRB5_KPASSWD_AUTHERROR;
+ 	strcpy(strresult, "Failed replying to application request");
+ 	goto chpwfail;
+     }
+ 
+     /* decrypt the new password */
+ 
+     cipher.length = (req->data + req->length) - ptr;
+     cipher.data = ptr;
+ 
+     if (ret = krb5_rd_priv(context, auth_context, &cipher, &clear, &replay)) {
+ 	numresult = KRB5_KPASSWD_HARDERROR;
+ 	strcpy(strresult, "Failed decrypting request");
+ 	goto chpwfail;
+     }
+ 
+     /* make sure the principal's min_life has been exceeded */
+ 
+     if (ret = check_policy_minlife(server_handle, ticket->enc_part2->client)) {
+        /* zap the password */
+        memset(clear.data, 0, clear.length);
+        krb5_xfree(clear.data);
+        clear.length = 0;
+ 
+        if (ret != KADM5_PASS_TOOSOON) {
+ 	  numresult = KRB5_KPASSWD_HARDERROR;
+ 	  strcpy(strresult, "Failed checking minimum password life");
+        } else {
+ 	  /* most of this is stolen from chpass_util.c */
+ 
+ 	  kadm5_principal_ent_rec princ_ent;
+ 	  kadm5_policy_ent_rec policy_ent;
+ 	  time_t until;
+ 	  char *time_string, *ptr;
+ 	  int code;
+ 
+ 	  if (code = kadm5_get_principal(server_handle,
+ 					 ticket->enc_part2->client,
+ 					 &princ_ent,
+ 					 KADM5_PRINCIPAL_NORMAL_MASK)) {
+ 	     numresult = KRB5_KPASSWD_HARDERROR;
+ 	     goto chpwfail;
+ 	  }
+ 
+ 	  if (code = kadm5_get_policy(server_handle, princ_ent.policy,
+ 				      &policy_ent)) {
+ 	     kadm5_free_principal_ent(server_handle, &princ_ent);
+ 	     numresult = KRB5_KPASSWD_HARDERROR;
+ 	     goto chpwfail;
+ 	  }
+ 	     
+ 	  until = princ_ent.last_pwd_change + policy_ent.pw_min_life;
+ 
+ 	  time_string = ctime(&until);
+ 	  if (*(ptr = &time_string[strlen(time_string)-1]) == '\n')
+ 	     *ptr = '\0';
+ 
+ 	  sprintf(strresult, error_message(CHPASS_UTIL_PASSWORD_TOO_SOON), 
+ 		  time_string);
+ 
+ 	  (void) kadm5_free_principal_ent(server_handle, &princ_ent);
+ 	  (void) kadm5_free_policy_ent(server_handle, &policy_ent);
+ 
+ 	  numresult = KRB5_KPASSWD_SOFTERROR;
+        }
+        goto chpwfail;
+     }
+ 	  
+     /* change the password */
+ 
+     ptr = (char *) malloc(clear.length+1);
+     memcpy(ptr, clear.data, clear.length);
+     ptr[clear.length] = '\0';
+ 
+     ret = kadm5_chpass_principal_util(server_handle, ticket->enc_part2->client,
+ 				      ptr, NULL, strresult);
+ 
+     /* zap the password */
+     memset(clear.data, 0, clear.length);
+     memset(ptr, 0, clear.length);
+     krb5_xfree(clear.data);
+     free(ptr);
+     clear.length = 0;
+ 
+     if (ret) {
+ 	if ((ret != KADM5_PASS_Q_TOOSHORT) && 
+ 	    (ret != KADM5_PASS_REUSE) && (ret != KADM5_PASS_Q_CLASS) && 
+ 	    (ret != KADM5_PASS_Q_DICT) && (ret != KADM5_PASS_TOOSOON))
+ 	    numresult = KRB5_KPASSWD_HARDERROR;
+ 	else
+ 	    numresult = KRB5_KPASSWD_SOFTERROR;
+ 
+ 	/* strresult set by kadb5_chpass_principal_util() */
+ 	goto chpwfail;
+     }
+ 
+     /* success! */
+ 
+     numresult = KRB5_KPASSWD_SUCCESS;
+     strcpy(strresult, "");
+ 
+ chpwfail:
+ 
+     clear.length = 2 + strlen(strresult);
+     clear.data = (char *) malloc(clear.length);
+ 
+     ptr = clear.data;
+ 
+     *ptr++ = (numresult>>8) & 0xff;
+     *ptr++ = numresult & 0xff;
+ 
+     memcpy(ptr, strresult, strlen(strresult));
+ 
+     cipher.length = 0;
+ 
+     if (ap_rep.length) {
+ 	if (ret = krb5_auth_con_setaddrs(context, auth_context, &local_kaddr,
+ 					 NULL)) {
+ 	    numresult = KRB5_KPASSWD_HARDERROR;
+ 	    strcpy(strresult,
+ 		   "Failed storing client and server internet addresses");
+ 	} else {
+ 	    if (ret = krb5_mk_priv(context, auth_context, &clear, &cipher,
+ 				   &replay)) {
+ 		numresult = KRB5_KPASSWD_HARDERROR;
+ 		strcpy(strresult, "Failed encrypting reply");
+ 	    }
+ 	}
+     }
+ 
+     /* if no KRB-PRIV was constructed, then we need a KRB-ERROR.
+        if this fails, just bail.  there's nothing else we can do. */
+ 
+     if (cipher.length == 0) {
+ 	/* clear out ap_rep now, so that it won't be inserted in the
+            reply */
+ 
+ 	if (ap_rep.length) {
+ 	    krb5_xfree(ap_rep.data);
+ 	    ap_rep.length = 0;
+ 	}
+ 
+ 	krberror.ctime = 0;
+ 	krberror.cusec = 0;
+ 	krberror.susec = 0;
+ 	if (ret = krb5_timeofday(context, &krberror.stime))
+ 	    goto bailout;
+ 
+ 	/* this is really icky.  but it's what all the other callers
+ 	   to mk_error do. */
+ 	krberror.error = ret;
+ 	krberror.error -= ERROR_TABLE_BASE_krb5;
+ 	if (krberror.error < 0 || krberror.error > 128)
+ 	    krberror.error = KRB_ERR_GENERIC;
+ 
+ 	krberror.client = NULL;
+ 	if (ret = krb5_build_principal(context, &krberror.server,
+ 				       strlen(realm), realm,
+ 				       "kadmin", "changepw", NULL))
+ 	    goto bailout;
+ 	krberror.text.length = 0;
+ 	krberror.e_data = clear;
+ 
+ 	ret = krb5_mk_error(context, &krberror, &cipher);
+ 
+ 	krb5_free_principal(context, krberror.server);
+ 
+ 	if (ret)
+ 	    goto bailout;
+     }
+ 
+     /* construct the reply */
+ 
+     rep->length = 6 + ap_rep.length + cipher.length;
+     rep->data = (char *) malloc(rep->length);
+     ptr = rep->data;
+ 
+     /* length */
+ 
+     *ptr++ = (rep->length>>8) & 0xff;
+     *ptr++ = rep->length & 0xff;
+ 
+     /* version == 0x0001 big-endian */
+ 
+     *ptr++ = 0;
+     *ptr++ = 1;
+ 
+     /* ap_rep length, big-endian */
+ 
+     *ptr++ = (ap_rep.length>>8) & 0xff;
+     *ptr++ = ap_rep.length & 0xff;
+ 
+     /* ap-rep data */
+ 
+     if (ap_rep.length) {
+ 	memcpy(ptr, ap_rep.data, ap_rep.length);
+ 	ptr += ap_rep.length;
+     }
+ 
+     /* krb-priv or krb-error */
+ 
+     memcpy(ptr, cipher.data, cipher.length);
+ 
+ bailout:
+     if (auth_context)
+ 	krb5_auth_con_free(context, auth_context);
+     if (changepw)
+ 	krb5_free_principal(context, changepw);
+     if (ap_rep.length)
+ 	krb5_xfree(ap_rep.data);
+     if (ticket)
+ 	krb5_free_ticket(context, ticket);
+     if (clear.length)
+ 	krb5_xfree(clear.data);
+     if (cipher.length)
+ 	krb5_xfree(cipher.data);
+ 
+     return(ret);
+ }
Index: kadmin/v5passwdd/srv_net.c
diff -c krb5/kadmin/v5passwdd/srv_net.c:1.1.1.1 krb5/kadmin/v5passwdd/srv_net.c:1.2
*** krb5/kadmin/v5passwdd/srv_net.c:1.1.1.1	Mon Jun  2 17:55:36 1997
--- krb5/kadmin/v5passwdd/srv_net.c	Tue Jun  9 15:58:42 1998
***************
*** 632,639 ****
  	goto done;
      }
  
!     /* If we have a non-default port number, then allow reuse of address */
!     if (net_server_addr.sin_port != htons(KRB5_ADM_DEFAULT_PORT)) {
  	int	allowed;
  
  	allowed = 1;
--- 632,639 ----
  	goto done;
      }
  
!     /* Allow reuse of address */
!     {
  	int	allowed;
  
  	allowed = 1;
Index: kdc/Makefile.in
diff -c krb5/kdc/Makefile.in:1.1.1.1 krb5/kdc/Makefile.in:1.2
*** krb5/kdc/Makefile.in:1.1.1.1	Mon Jun  2 17:54:07 1997
--- krb5/kdc/Makefile.in	Sat Aug  9 00:22:34 1997
***************
*** 37,42 ****
--- 37,45 ----
  	replay.o \
  	kerberos_v4.o
  
+ EXTRA_OBJS= @EXTRA_OBJS@
+ EXTRA_LIBS= @EXTRA_LIBS@
+ 
  all::	krb5kdc
  
  depend:: kdc5_err.c
***************
*** 52,59 ****
  
  kdc5_err.o: kdc5_err.h
  
! krb5kdc: $(OBJS) $(DEPLIBS)
! 	$(LD) $(LDFLAGS) $(LDARGS) -o krb5kdc $(OBJS) $(LIBS)
  
  install::
  	$(INSTALL_PROGRAM) krb5kdc ${DESTDIR}$(SERVER_BINDIR)/krb5kdc
--- 55,62 ----
  
  kdc5_err.o: kdc5_err.h
  
! krb5kdc: $(OBJS) $(EXTRA_OBJS) $(DEPLIBS)
! 	$(LD) $(LDFLAGS) $(LDARGS) -o krb5kdc $(OBJS) $(EXTRA_OBJS) $(LIBS) $(EXTRA_LIBS)
  
  install::
  	$(INSTALL_PROGRAM) krb5kdc ${DESTDIR}$(SERVER_BINDIR)/krb5kdc
Index: kdc/configure.in
diff -c krb5/kdc/configure.in:1.1.1.1 krb5/kdc/configure.in:1.4
*** krb5/kdc/configure.in:1.1.1.1	Mon Jun  2 17:54:07 1997
--- krb5/kdc/configure.in	Thu Jul 23 12:58:29 1998
***************
*** 32,38 ****
  	AC_DEFINE(KRBCONF_KDC_MODIFIES_KDB)
  fi
  dnl
! 
  dnl
  dnl This is a horrible hack, based on the fact that we have to drag 
  dnl stuff from alt_prof.c, which depends on str_conv.c, which depends on
--- 32,82 ----
  	AC_DEFINE(KRBCONF_KDC_MODIFIES_KDB)
  fi
  dnl
! dnl --with-afs-name-change enables code that supports the case where
! dnl the name of the realm (cell) changed when going from AFS to Kerberos 5
! dnl
! AC_ARG_WITH([afs-name-change],
! [  --with-afs-name-change	Support an AFS cell with a different name],
! if test "$withval" = yes; then
! 	AC_DEFINE(KRB5_KDC_AFS3_USE_CONTENTS)
! fi)
! dnl
! dnl --with-securid-preauth turns on code from ARL to allow the use of a
! dnl SecurID token to be used as a hardware preauthentication mechanism
! dnl
! AC_ARG_WITH([securid-preauth],
! [  --with-securid-preuath=DIR	Support SecurID as preauth, client libs in DIR
!   --without-securid-preauth	Do not add in SecurID support (default)],
! ,
! withval=no)dnl
! if test "$withval" != "no"; then
! 	if test ! -f $withval/sdiclient.a; then
! 		echo "Cannot find sdclient.a in $withval, exiting"
! 		exit 1
! 	fi
! 	if test ! -f $withval/sdconf.h; then
! 		echo "Cannot find sdconf.h in $withval, exiting"
! 		exit 1
! 	fi
! 	AC_MSG_RESULT(Enabling support for SecurID tokens)
! 	AC_DEFINE(ARL_SECURID_PREAUTH)
! 	CPPFLAGS="$CPPFLAGS -I$withval"
! 	EXTRA_LIBS=$withval/sdiclient.a
! 	EXTRA_OBJS=securid.o
! fi
! dnl
! dnl --with-cryptocard-validate turns on code that enables a special preauth
! dnl to allow one to simply validate a CRYPTOCard RB-1 hardware token for
! dnl a user without having that user's secret key
! dnl
! AC_ARG_WITH([cryptocard-validate],
! [  --with-cryptocard-validate	Allow validation of a RB-1 with a host key
!   --without-cryptocard-validate	Don't enable RB-1 validation code (default)],
! ,
! withval=no)dnl
! if test "$withval" = yes; then
! 	AC_DEFINE(KRB5_CRYPTOCARD_VALIDATE)
! fi
  dnl
  dnl This is a horrible hack, based on the fact that we have to drag 
  dnl stuff from alt_prof.c, which depends on str_conv.c, which depends on
***************
*** 46,51 ****
--- 90,99 ----
  USE_GSSRPC_LIBRARY
  USE_GSSAPI_LIBRARY
  USE_DYN_LIBRARY
+ dnl
+ dnl
+ AC_SUBST(EXTRA_LIBS)
+ AC_SUBST(EXTRA_OBJS)
  dnl
  dnl
  USE_KDB5_LIBRARY
Index: kdc/do_as_req.c
diff -c krb5/kdc/do_as_req.c:1.1.1.2 krb5/kdc/do_as_req.c:1.2
*** krb5/kdc/do_as_req.c:1.1.1.2	Thu Nov 20 01:13:31 1997
--- krb5/kdc/do_as_req.c	Thu Jul 23 12:58:30 1998
***************
*** 82,87 ****
--- 82,88 ----
      ticket_reply.enc_part.ciphertext.data = 0;
      e_data.data = 0;
      encrypting_key.contents = 0;
+     reply.padata = 0;
  
  #ifdef KRB5_USE_INET
      if (from->address->addrtype == ADDRTYPE_INET)
***************
*** 289,295 ****
       * preauthentication, verify that the proper kind of
       * preauthentication was carried out.
       */
!     status = missing_required_preauth(&client, &server, &enc_tkt_reply);
      if (status) {
  	errcode = KRB5KDC_ERR_PREAUTH_REQUIRED;
  	get_preauth_hint_list(request, &client, &server, &e_data);
--- 290,297 ----
       * preauthentication, verify that the proper kind of
       * preauthentication was carried out.
       */
!     status = missing_required_preauth(&client, &server, &enc_tkt_reply,
! 				      request);
      if (status) {
  	errcode = KRB5KDC_ERR_PREAUTH_REQUIRED;
  	get_preauth_hint_list(request, &client, &server, &e_data);
***************
*** 473,478 ****
--- 475,482 ----
  	       ticket_reply.enc_part.ciphertext.length);
  	free(ticket_reply.enc_part.ciphertext.data);
      }
+     if (reply.padata)
+ 	krb5_free_pa_data(kdc_context, reply.padata);
      if (e_data.data)
  	krb5_xfree(e_data.data);
      
Index: kdc/do_tgs_req.c
diff -c krb5/kdc/do_tgs_req.c:1.1.1.3 krb5/kdc/do_tgs_req.c:1.4
*** krb5/kdc/do_tgs_req.c:1.1.1.3	Wed Feb 25 17:23:42 1998
--- krb5/kdc/do_tgs_req.c	Thu Feb 26 11:38:35 1998
***************
*** 163,169 ****
  	 * might be a request for a TGT for some other realm; we
  	 * should do our best to find such a TGS in this db
  	 */
! 	if (firstpass && krb5_princ_size(kdc_context, request->server) == 2) {
  	    krb5_data *server_1 = krb5_princ_component(kdc_context, request->server, 1);
  	    krb5_data *tgs_1 = krb5_princ_component(kdc_context, tgs_server, 1);
  
--- 163,169 ----
  	 * might be a request for a TGT for some other realm; we
  	 * should do our best to find such a TGS in this db
  	 */
! 	if (firstpass && krb5_is_tgs_principal(request->server) == TRUE) {
  	    krb5_data *server_1 = krb5_princ_component(kdc_context, request->server, 1);
  	    krb5_data *tgs_1 = krb5_princ_component(kdc_context, tgs_server, 1);
  
Index: kdc/extern.c
diff -c krb5/kdc/extern.c:1.1.1.1 krb5/kdc/extern.c:1.2
*** krb5/kdc/extern.c:1.1.1.1	Mon Jun  2 17:54:07 1997
--- krb5/kdc/extern.c	Fri Jul 25 02:10:55 1997
***************
*** 33,37 ****
--- 33,38 ----
  krb5_data empty_string = {0, 0, ""};
  krb5_timestamp kdc_infinity = KRB5_INT32_MAX; /* XXX */
  krb5_rcache	kdc_rcache = (krb5_rcache) NULL;
+ krb5_deltat	kdc_warn_pwexpire = 0;
  
  volatile int signal_requests_exit = 0;	/* gets set when signal hits */
Index: kdc/extern.h
diff -c krb5/kdc/extern.h:1.1.1.1 krb5/kdc/extern.h:1.2
*** krb5/kdc/extern.h:1.1.1.1	Mon Jun  2 17:54:07 1997
--- krb5/kdc/extern.h	Fri Jul 25 02:10:56 1997
***************
*** 93,98 ****
--- 93,99 ----
  extern krb5_data 	empty_string;	/* an empty string */
  extern krb5_timestamp 	kdc_infinity;	/* greater than all other timestamps */
  extern krb5_rcache	kdc_rcache;	/* replay cache */
+ extern krb5_deltat	kdc_warn_pwexpire; /* Time to warn about exp pw's */
  
  extern volatile int signal_requests_exit;
  #endif /* __KRB5_KDC_EXTERN__ */
Index: kdc/kdc_preauth.c
diff -c krb5/kdc/kdc_preauth.c:1.1.1.3 krb5/kdc/kdc_preauth.c:1.10
*** krb5/kdc/kdc_preauth.c:1.1.1.3	Thu Nov 20 01:13:34 1997
--- krb5/kdc/kdc_preauth.c	Fri Jan 29 13:53:38 1999
***************
*** 28,33 ****
--- 28,35 ----
  #include "extern.h"
  #include <stdio.h>
  
+ #include <syslog.h>
+ 
  typedef krb5_error_code (*verify_proc)
      KRB5_PROTOTYPE((krb5_context, krb5_db_entry *client,
  		    krb5_kdc_req *request,
***************
*** 54,59 ****
--- 56,66 ----
      return_proc return_padata;
  } krb5_preauth_systems;
  
+ typedef struct _krb5_rb1_track_data {
+     char ascii_response[9];
+     char new_challenge[8];
+ } krb5_rb1_track_data;
+ 
  static krb5_error_code verify_enc_timestamp
      KRB5_PROTOTYPE((krb5_context, krb5_db_entry *client,
  		    krb5_kdc_req *request,
***************
*** 71,76 ****
--- 78,91 ----
  		    krb5_keyblock *encrypting_key,
  		    krb5_pa_data **send_pa));
  
+ static krb5_error_code return_pa_as_rep
+     KRB5_PROTOTYPE((krb5_context, krb5_pa_data * padata, 
+ 		    krb5_db_entry *client,
+ 		    krb5_kdc_req *request, krb5_kdc_rep *reply,
+ 		    krb5_key_data *client_key,
+ 		    krb5_keyblock *encrypting_key,
+ 		    krb5_pa_data **send_pa));
+ 
  /* SAM preauth support */
  static krb5_error_code verify_sam_response
      KRB5_PROTOTYPE((krb5_context, krb5_db_entry *client,
***************
*** 81,86 ****
--- 96,102 ----
      KRB5_PROTOTYPE((krb5_context, krb5_kdc_req *request,
  		    krb5_db_entry *client, krb5_db_entry *server,
  		    krb5_pa_data *data));
+ 
  /*
   * Preauth property flags
   */
***************
*** 124,129 ****
--- 140,154 ----
  	0,
  	0
      },
+ #ifdef KRB5_CRYPTOCARD_VALIDATE
+     {
+ 	KRB5_PADATA_AS_REP,
+ 	0,
+ 	0,
+ 	0,
+ 	return_pa_as_rep,
+     },
+ #endif /* KRB5_CRYPTOCARD_VALIDATE */
      { -1,}
  };
  
***************
*** 144,152 ****
      return 0;
  } 
  
! const char *missing_required_preauth(client, server, enc_tkt_reply)
      krb5_db_entry *client, *server;
      krb5_enc_tkt_part *enc_tkt_reply;
  {
  #if 0
      /*
--- 169,178 ----
      return 0;
  } 
  
! const char *missing_required_preauth(client, server, enc_tkt_reply, request)
      krb5_db_entry *client, *server;
      krb5_enc_tkt_part *enc_tkt_reply;
+     krb5_kdc_req *request;
  {
  #if 0
      /*
***************
*** 169,174 ****
--- 195,215 ----
  	!isflagset(enc_tkt_reply->flags, TKT_FLG_HW_AUTH))
  	return "NEEDED_HW_PREAUTH";
  
+ #ifdef KRB5_CRYPTOCARD_VALIDATE
+     /*
+      * Sigh, this is a bit weird.
+      *
+      * We want the client to be able to initiatate hardware preauthentication,
+      * because he may not always want it (for example, a "trusted" client
+      * may require hardware preauth for root access, but not otherwise).
+      */
+ 
+     if (isflagset(request->kdc_options, KDC_OPT_HW_AUTH) &&
+ 	!isflagset(enc_tkt_reply->flags, TKT_FLG_HW_AUTH))
+ 	return "REQUESTED_HW_PREAUTH";
+ 
+ #endif /* KRB5_CRYPTOCARD_VALIDATE */
+ 
      return 0;
  }
  
***************
*** 187,193 ****
      e_data->length = 0;
      e_data->data = 0;
      
!     hw_only = isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH);
      pa_data = malloc(sizeof(krb5_pa_data *) * (MAX_PREAUTH_SYSTEMS+1));
      if (pa_data == 0)
  	return;
--- 228,235 ----
      e_data->length = 0;
      e_data->data = 0;
      
!     hw_only = isflagset(client->attributes, KRB5_KDB_REQUIRES_HW_AUTH) ||
! 	      isflagset(request->kdc_options, KDC_OPT_HW_AUTH);
      pa_data = malloc(sizeof(krb5_pa_data *) * (MAX_PREAUTH_SYSTEMS+1));
      if (pa_data == 0)
  	return;
***************
*** 216,221 ****
--- 258,285 ----
      }
      retval = encode_krb5_padata_sequence((const krb5_pa_data **) pa_data,
  					 &edat);
+ 
+     if (hw_only && pa_data && !(*pa_data)) {
+       /* We are requiring Hardware authentication but have no way of
+        * dealing with it (no SAM methods defined or no preauth mechs
+        * available for KDC to suggest to client.
+        *
+        *
+        * Don't send back ANY error text to client since this will cause
+        * get_in_tkt() to loop.  This should only happen when the user
+        * has not been set up properly in the database (w/ SAM hwauth
+        * principal.  This gives admins a better error message.  [tadhack]
+        */
+ 
+       krb5_klog_syslog(LOG_INFO,
+ 		"HW_AUTH required for user %s, but no valid method found",
+ 		client->princ->data[0].data);
+       if (edat && edat->data) {
+ 	free(edat->data);
+ 	edat->length = 0;
+       }
+     }
+    
      if (retval)
  	goto errout;
      *e_data = *edat;
***************
*** 549,554 ****
--- 613,640 ----
  	   do the work. In the future, add a kdc configuration
  	   variable that specifies the old cell name. */
  	padata->pa_type = KRB5_PADATA_AFS3_SALT;
+ #ifdef KRB5_KDC_AFS3_USE_CONTENTS
+ 	/*
+ 	 * Check to see if key_data_contents[1] contains information
+ 	 * and if it does, use that for the salt instead of our realm.
+ 	 * The intention is that afs2k5db will put the old AFS cell
+ 	 * name here and we want to use that in cases where it
+ 	 * differs from the Kerberos 5 realm name.
+ 	 */
+ 	if (client_key->key_data_length[1]) {
+ 	    	padata->length = client_key->key_data_length[1];
+ 		if ((padata->contents = malloc(padata->length)) == NULL) {
+ 		    retval = ENOMEM;
+ 		    goto cleanup;
+ 		}
+ 		memcpy(padata->contents, client_key->key_data_contents[1],
+ 		       client_key->key_data_length[1]);
+ 		padata->length = client_key->key_data_length[1];
+ 		break;
+ 	}
+ 	/* else fall through */
+ #endif /* KRB5_KDC_AFS3_USE_CONTENTS */
+ 
  	/* it would be just like ONLYREALM, but we need to pass the 0 */
  	scratch = krb5_princ_realm(kdc_context, request->client);
  	if ((padata->contents = malloc(scratch->length+1)) == NULL) {
***************
*** 591,596 ****
--- 677,854 ----
      return retval;
  }
  
+ #ifdef KRB5_CRYPTOCARD_VALIDATE
+ static krb5_error_code
+ return_pa_as_rep(context, in_padata, client, request, reply, client_key,
+ 	         encrypting_key, send_pa)
+     krb5_context	context;
+     krb5_pa_data *	in_padata;
+     krb5_db_entry *	client;
+     krb5_kdc_req *	request;
+     krb5_kdc_rep *	reply;
+     krb5_key_data *	client_key;
+     krb5_keyblock *	encrypting_key;
+     krb5_pa_data **	send_pa;
+ {
+     int c_nprincs = 0;
+     krb5_principal	sprinc = NULL;
+     krb5_db_entry	server;
+     krb5_key_data *	server_key;
+     krb5_keyblock 	server_keyblock;
+     krb5_error_code	code = 0;
+     krb5_boolean	more;
+     krb5_pa_data *	padata;
+     krb5_data		encoded_data;
+     krb5_data *		response;
+     krb5_enc_kdc_rep_part reply_encpart;
+     krb5_timestamp	kdc_time;
+     char *		sname = NULL;
+ 
+     /*
+      * Don't send anything if we didn't ask for it, or if we don't have
+      * hardware preauth.
+      */
+ 
+     if (! in_padata || !isflagset(reply->ticket->enc_part2->flags,
+ 				  TKT_FLG_HW_AUTH))
+ 	return 0;
+ 
+     server_keyblock.contents = NULL;
+ 
+     /*
+      * Decode the principal that was sent in this message
+      */
+ 
+     encoded_data.data = in_padata->contents;
+     encoded_data.length = in_padata->length;
+ 
+     if ((code = decode_krb5_principal(&encoded_data, &sprinc))) {
+ 	krb5_klog_syslog(LOG_INFO, "Can't decode encryption principal for "
+ 			 "PA-AS-REP: %s", error_message(code));
+ 	goto out;
+     }
+ 
+     if ((code = krb5_unparse_name(kdc_context, sprinc, &sname))) {
+ 	krb5_klog_syslog(LOG_INFO, "Can't unparse encrpytion principal for "
+ 			 "PA-AS-REP: %s", error_message(code));
+ 	goto out;
+     }
+ 
+     limit_string(sname);
+ 
+     /*
+      * The principal the key is encrypted in is sent in the in_padata
+      * field.
+      */
+ 
+     c_nprincs = 1;
+     
+     if ((code = krb5_db_get_principal(kdc_context, sprinc,
+ 				      &server, &c_nprincs, &more))) {
+ 	krb5_klog_syslog(LOG_INFO, "Can't find encryption principal %s for "
+ 			 " PA-AS-REP: %s", sname, error_message(code));
+ 	goto out;
+     }
+ 
+     if (more) {
+ 	krb5_klog_syslog(LOG_INFO, "More than one principal %s for PA-AS-REP",
+ 			 sname);
+ 	goto out;
+     } else if (c_nprincs != 1) {
+ 	
+ 	krb5_klog_syslog(LOG_INFO, "%s not found for PA-AS-REP", sname);
+ 	goto out;
+     }
+ 
+     if ((code = krb5_dbe_find_enctype(kdc_context, &server,
+ 				      -1, /* Ignore keytype */
+ 				      -1, /* Ignore salttype */
+ 				      0, /* Get highest kvno */
+ 				      &server_key))) {
+ 	krb5_klog_syslog(LOG_INFO, "Error while looking up key for principal "
+ 			 "%s for PA-AS-REP: %s", sname, error_message(code));
+ 	goto out;
+     }
+ 
+     if ((code = krb5_dbekd_decrypt_key_data(kdc_context, &master_encblock,
+ 					    server_key, &server_keyblock,
+ 					    NULL))) {
+ 	krb5_klog_syslog(LOG_INFO, "Error while decrypting principal %s key "
+ 			 "data for PA-AS-REP: %s", sname, error_message(code));
+ 	goto out;
+     }
+ 
+     /*
+      * _Whew_!  We've got the principal key, _FINALLY_.  Make a complete
+      * AS-REP, but put it in the preauth message.
+      */
+ 
+     if ((padata = malloc(sizeof(krb5_pa_data))) == NULL) {
+ 	code = ENOMEM;
+ 	goto errout;
+     }
+ 
+     /*
+      * Unfortunately, since we didn't get passed in the reply_encpart,
+      * we need to generate our own here.
+      */
+ 
+     reply_encpart.session = reply->ticket->enc_part2->session;
+     if ((code = fetch_last_req_info(client, &reply_encpart.last_req))) {
+ 	krb5_klog_syslog(LOG_INFO, "Cannot fetch client LAST-REQ info: %s",
+ 			 error_message(code));
+ 	goto out;
+     }
+ 
+     reply_encpart.nonce = request->nonce;
+     reply_encpart.key_exp = client->expiration;
+     reply_encpart.flags = reply->ticket->enc_part2->flags;
+     reply_encpart.server = reply->ticket->server;
+     reply_encpart.times = reply->ticket->enc_part2->times;
+ 
+     if ((code = krb5_timeofday(kdc_context, &kdc_time))) {
+ 	krb5_klog_syslog(LOG_INFO, "Cannot get time of day for PA-AS-REP: %s",
+ 			 error_message(code));
+ 	goto out;
+     }
+ 
+     reply_encpart.times.authtime = kdc_time;
+     reply_encpart.caddrs = reply->ticket->enc_part2->caddrs;
+     reply->enc_part.enctype = server_keyblock.enctype;
+ 
+     if ((code = krb5_encode_kdc_rep(kdc_context, KRB5_AS_REP, &reply_encpart,
+ 				    &server_keyblock, reply, &response))) {
+ 	krb5_klog_syslog(LOG_INFO, "Failed to encode KDC reply for PA-AS-REP: "
+ 			 "%s", error_message(code));
+ 	goto out;
+     }
+ 
+     padata->pa_type = KRB5_PADATA_AS_REP;
+     padata->length = response->length;
+     padata->contents = response->data;
+     krb5_xfree(response);
+     *send_pa = padata;
+     padata = NULL;
+ 
+ out:
+     code = 0;
+ errout:
+     if (padata)
+ 	free(padata);
+     if (sname)
+ 	free(sname);
+     if (server_keyblock.contents) {
+ 	memset((char *) server_keyblock.contents, 0, server_keyblock.length);
+ 	krb5_xfree(server_keyblock.contents);
+     }
+     if (sprinc)
+ 	krb5_free_principal(kdc_context, sprinc);
+     if (c_nprincs)
+ 	krb5_db_free_principal(kdc_context, &server, c_nprincs);
+ 
+     return code;
+ }
+ #endif /* KRB5_CRYPTOCARD_VALIDATE */
      
  static struct {
    char* name;
***************
*** 599,604 ****
--- 857,863 ----
    "SNK4", PA_SAM_TYPE_DIGI_PATH,
    "SECURID", PA_SAM_TYPE_SECURID,
    "GRAIL", PA_SAM_TYPE_GRAIL,
+   "RB1", PA_SAM_TYPE_CRYPTOCARD,
    0, 0
  };
  
***************
*** 621,626 ****
--- 880,895 ----
      char response[9];
      char inputblock[8];
      krb5_data predict_response;
+     krb5_db_entry assoc;
+     int npr = 0;
+ 
+ 
+     /*
+      * Make sure we don't segfault in cleanup if encrypting.key_length
+      * isn't initialized.
+      */
+     memset((char *) &encrypting_key, 0, sizeof(encrypting_key));
+ 
  
      /* Given the client name we can figure out what type of preauth
         they need. The spec is currently for querying the database for
***************
*** 637,645 ****
  
      {
        char *uname;
-       int npr = 1;
        krb5_boolean more;
-       krb5_db_entry assoc;
        krb5_key_data  *assoc_key;
        krb5_principal newp;
        int newlen;
--- 906,912 ----
***************
*** 662,668 ****
  	krb5_princ_component(kdc_context,newp,probeslot)->data = sam_ptr->name;
  	krb5_princ_component(kdc_context,newp,probeslot)->length = 
  	  strlen(sam_ptr->name);
- 	npr = 1;
  	retval = krb5_db_get_principal(kdc_context, newp, &assoc, &npr, &more);
  	if(!retval && npr) {
  	  sc.sam_type = sam_ptr->sam_type;
--- 929,934 ----
***************
*** 711,716 ****
--- 977,999 ----
      sc.sam_flags = KRB5_SAM_USE_SAD_AS_KEY;
  
      switch (sc.sam_type) {
+ #ifdef ARL_SECURID_PREAUTH
+     case PA_SAM_TYPE_SECURID:
+       if (pa_data->length) {
+ 	retval = 0;
+ 	break;
+       }
+       if (retval = get_securid_edata(context, &sc))
+ 	goto cleanup;
+       if (retval = encode_krb5_sam_challenge(&sc, &scratch))
+ 	goto cleanup;
+       pa_data->magic = KV5M_PA_DATA;
+       pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE;
+       pa_data->contents = scratch->data;
+       pa_data->length = scratch->length;
+       retval = 0;
+       break;
+ #endif /* ARL_SECURID_PREAUTH */
      case PA_SAM_TYPE_GRAIL:
        sc.sam_type_name.data = "Experimental System";
        sc.sam_type_name.length = strlen(sc.sam_type_name.data);
***************
*** 801,807 ****
  	if (session_key->length != 8) {
  	  com_err("krb5kdc", retval = KRB5KDC_ERR_ETYPE_NOSUPP,
  		  "keytype didn't match code expectations");
! 	  return retval;
  	}
  	for(i = 0; i<6; i++) {
  	  inputblock[i] = '0' + ((session_key->contents[i]/2) % 10);
--- 1084,1090 ----
  	if (session_key->length != 8) {
  	  com_err("krb5kdc", retval = KRB5KDC_ERR_ETYPE_NOSUPP,
  		  "keytype didn't match code expectations");
! 	  goto cleanup;
  	}
  	for(i = 0; i<6; i++) {
  	  inputblock[i] = '0' + ((session_key->contents[i]/2) % 10);
***************
*** 821,826 ****
--- 1104,1110 ----
  
  	if (retval) {
  	  com_err("krb5kdc", retval, "snk4 processing key");
+ 	  goto cleanup;
  	}
  
  	{
***************
*** 831,837 ****
  	}
  	if (retval) {
  	  com_err("krb5kdc", retval, "snk4 response generation failed");
! 	  return retval;
  	}
  	/* now output block is the raw bits of the response; convert it
  	   to display form */
--- 1115,1126 ----
  	}
  	if (retval) {
  	  com_err("krb5kdc", retval, "snk4 response generation failed");
! 	  goto cleanup;
! 	}
! 	retval = krb5_finish_key(kdc_context, &eblock);
! 	if (retval) {
! 	  com_err("krb5kdc", retval, "snk4 key post-processing");
! 	  goto cleanup;
  	}
  	/* now output block is the raw bits of the response; convert it
  	   to display form */
***************
*** 915,924 ****
        
        retval = 0;
        break;
      }
  
  cleanup:
!     memset((char *)encrypting_key.contents, 0, encrypting_key.length);
      krb5_xfree(encrypting_key.contents);
      return retval;
  }
--- 1204,1420 ----
        
        retval = 0;
        break;
+     /*
+      * The CryptoCard RB-1 is sort of like the Digital Pathways cards;
+      * they're straight DES encryptors, but the output is slightly
+      * different.  They also have a way of doing challenge precomputation
+      */
+     case PA_SAM_TYPE_CRYPTOCARD:
+     {
+       krb5_tl_data tl_data;
+       krb5_rb1_track_data rb1_track_data;
+       char outputblock[8];
+ 
+       sc.sam_type_name.data = "CryptoCard RB-1";
+       sc.sam_type_name.length = strlen(sc.sam_type_name.data);
+ 
+       tl_data.tl_data_type = KRB5_TL_RB1_CHALLENGE;
+ 
+       if ((retval = krb5_dbe_lookup_tl_data(kdc_context, &assoc, &tl_data)) ||
+ 	  (tl_data.tl_data_length == 0)) {
+ 	  /*
+ 	   * No precomputed challenge, so let's make a new one
+ 	   *
+ 	   * What happens here is close to the Digital Pathways challenge
+ 	   * generation: We generate a random key and take each byte,
+ 	   * divide by 2 and do a mod 10.  Note that we do this for
+ 	   * 8 bytes, instead of the SNK 6 bytes.  The challenge length
+ 	   * should probably be configurable ...
+ 	   */
+ 
+ 	  krb5_encrypt_block eblock;
+ 	  krb5_keyblock *session_key = 0;
+ 	  int i;
+ 	  memset(inputblock, 0, 8);
+           sc.sam_challenge_label.data = "Press CH/MAC and enter this on the keypad";
+ 	  krb5_use_enctype(kdc_context, &eblock, ENCTYPE_DES_CBC_CRC);
+ 	  retval = krb5_random_key(kdc_context, &eblock, 
+ 				   krb5_enctype_array[ENCTYPE_DES_CBC_CRC]->random_sequence,
+ 				   &session_key);
+ 	  if (retval) {
+ 	    /* random key failed */
+ 	    com_err("krb5kdc", retval,"generating random challenge for preauth");
+ 	    return retval;
+ 	  }
+ 	  /* now session_key has a key which we can pick bits out of */
+ 	  /* we need eight decimal digits. Grab 8 bytes, div 2, mod 10 each. */
+ 	  if (session_key->length != 8) {
+ 	    com_err("krb5kdc", retval = KRB5KDC_ERR_ETYPE_NOSUPP,
+ 		    "keytype didn't match code expectations");
+ 	    goto cleanup;
+ 	  }
+ 	  for(i = 0; i<8; i++) {
+ 	    inputblock[i] = '0' + ((session_key->contents[i]/2) % 10);
+ 	  }
+ 	  if (session_key)
+ 	    krb5_free_keyblock(kdc_context, session_key);
+ 
+ 	  sc.sam_challenge.data = inputblock;
+ 	  sc.sam_challenge.length = 8;
+         } else {
+ 	  /*
+ 	   * We had precomputed a challenge from before.  Use that instead
+ 	   */
+ 	  sc.sam_challenge_label.data = "Press ENTER and compare this challenge to the one on your display";
+ 	  sc.sam_challenge.data = tl_data.tl_data_contents;
+ 	  sc.sam_challenge.length = tl_data.tl_data_length;
+ 	  memcpy(inputblock, tl_data.tl_data_contents, tl_data.tl_data_length);
+ 	}
+ 
+ 	sc.sam_challenge_label.length = strlen(sc.sam_challenge_label.data);
+ 
+ 	krb5_use_enctype(kdc_context, &eblock, ENCTYPE_DES_CBC_RAW);
+ 	/* I don't think this is necessary ... */
+ 	encrypting_key.enctype = ENCTYPE_DES_CBC_RAW;
+ 	/* do any necessary key pre-processing */
+ 	retval= krb5_process_key(kdc_context, &eblock, &encrypting_key);
+ 
+ 	if (retval) {
+ 	  com_err("krb5kdc", retval, "rb1 processing key");
+ 	  goto cleanup;
+ 	}
+       
+ 	{
+ 	  char ivec[8];
+ 	  memset(ivec,0,8);
+ 	  retval = krb5_encrypt(kdc_context, inputblock, outputblock, 8,
+ 				&eblock, ivec);
+ 	}
+ 
+ 	retval = krb5_finish_key(kdc_context, &eblock);
+ 
+ 	if (retval) {
+ 	  com_err("krb5kdc", retval, "rb1 key post-processing");
+ 	  goto cleanup;
+ 	}
+ 
+ 	if (retval) {
+ 	  com_err("krb5kdc", retval, "rb1 response generation failed");
+ 	  goto cleanup;
+ 	}
+ 
+ 	/*
+ 	 * Now convert the output block to something visible.  Turn
+ 	 * the upper four bytes into ASCII (Also from SNK code).  Note
+ 	 * that we want to use raw hex as the output from the RB-1,
+ 	 * so it's a little different than the SNK code.
+ 	 */
+ 	for (i=0; i<4; i++) {
+ 	  char n[2];
+ 	  n[0] = outputblock[i] & 0xf;
+ 	  n[1] = (outputblock[i]>>4) & 0xf;
+ 	  /* for v4, we keygen: *(j+(char*)&key1) = (n[1]<<4) | n[0]; */
+ 	  /* for v5, we just generate a string */
+ 	  rb1_track_data.ascii_response[2*i+0] = n[1] > 9 ?
+ 						n[1] - 10 + 'A' : '0' + n[1];
+ 	  rb1_track_data.ascii_response[2*i+1] = n[0] > 9 ?
+ 						n[0] - 10 + 'A' : '0' + n[0];
+ 	  /* and now, response has what we work with. */
+ 	}
+ 	rb1_track_data.ascii_response[8] = 0;
+ 	predict_response.data = rb1_track_data.ascii_response;
+ 	predict_response.length = 8;
+ 
+ 	/*
+ 	 * We diverge from the SNK code here.
+ 	 *
+ 	 * Since we want to include both the response and the precomputed
+ 	 * challenge for next time, we don't use predicted_sam_response
+ 	 * but create our own structure for the track data (that's allowed
+ 	 * by the spec).  First off, let's use the current response
+ 	 * to generate the new challenge.
+ 	 */
+ 
+ 	/*
+ 	 * Simply take the full encrypted response block, convert it
+ 	 * to ASCII numerals, and convert 0xa - 0xf to 0x0 - 0x05
+ 	 */
+ 
+ 	for (i = 0; i < 8; i++) {
+ 	  rb1_track_data.new_challenge[i] = (outputblock[i] & 0x0f) | 0x30;
+ 	  if (rb1_track_data.new_challenge[i] > 0x39)
+ 	    rb1_track_data.new_challenge[i] -= 10;
+ 	}
+ 
+ 	{
+ 	  krb5_enc_data tmpdata;
+ 	  krb5_data scratch_data;
+ 
+ 	  scratch_data.data = (void *) &rb1_track_data;
+ 	  scratch_data.length = sizeof(rb1_track_data);
+ 
+ 	  retval = krb5_encrypt_data(context, master_encblock.key, 0,
+ 				     &scratch_data, &tmpdata);
+ 	  sc.sam_track_id = tmpdata.ciphertext;
+ 	}
+ 
+ 	if (retval) goto cleanup;
+ 
+ 	sc.sam_response_prompt.data = "Enter the displayed response";
+ 	sc.sam_response_prompt.length = strlen(sc.sam_response_prompt.data);
+ 	sc.sam_pk_for_sad.length = 0;
+ 	sc.sam_nonce = 0;
+ 	/* Generate checksum */
+ 	sc.sam_cksum.contents = (krb5_octet *)
+ 	  malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES));
+ 	if (sc.sam_cksum.contents == NULL) {
+ 	  retval = ENOMEM;
+ 	  goto cleanup;
+ 	}
+         {
+ 	  const krb5_enctype type = ENCTYPE_DES_CBC_MD5;
+ 	  if (!valid_enctype(type)) return KRB5_PROG_ETYPE_NOSUPP;
+ 	  krb5_use_enctype(context, &eblock, type);
+ 	  retval = krb5_string_to_key(context, &eblock, 
+ 				      &psr.sam_key, &predict_response, 
+ 				      0 /* salt */);
+ 	  if (retval) { free(sc.sam_cksum.contents); goto cleanup; }
+ 
+ 	  retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES,
+ 					   sc.sam_challenge.data,
+ 					   sc.sam_challenge.length,
+ 					   psr.sam_key.contents, /* key */
+ 					   psr.sam_key.length, /* key length */
+ 					   &sc.sam_cksum);
+ 	  krb5_free_keyblock_contents(context, &psr.sam_key);
+ 	  if (retval) { free(sc.sam_cksum.contents); goto cleanup; }
+ 	}
+ 
+ 	retval = encode_krb5_sam_challenge(&sc, &scratch);
+ 	if (retval) goto cleanup;
+ 	pa_data->magic = KV5M_PA_DATA;
+ 	pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE;
+ 	pa_data->contents = scratch->data;
+ 	pa_data->length = scratch->length;
+ 
+ 	break;
+     }
+ #ifdef ARL_SECURID_PREAUTH
+     default:
+       pa_data->magic = KV5M_PA_DATA;
+       pa_data->pa_type = KRB5_PADATA_SAM_CHALLENGE;
+       pa_data->contents = 0;
+       pa_data->length = 0;
+       return(retval);
+       break;
+ #endif /* ARL_SECURID_PREAUTH */
      }
  
  cleanup:
!     if (npr)
!        krb5_db_free_principal(kdc_context, &assoc, npr);
!     if (encrypting_key.contents)
!       memset((char *)encrypting_key.contents, 0, encrypting_key.length);
      krb5_xfree(encrypting_key.contents);
      return retval;
  }
***************
*** 945,984 ****
      if (retval) com_err("krb5kdc", retval, "decode_krb5_sam_response failed");
      if (retval) goto cleanup;
  
!     {
!       krb5_enc_data tmpdata;
!       tmpdata.ciphertext = sr->sam_track_id;
!       retval = krb5_decrypt_data(context, master_encblock.key, 0, 
! 				 &tmpdata, &scratch);
!       if (retval) com_err("krb5kdc", retval, "decrypt track_id failed");
!     }
!     if (retval) goto cleanup;
!     retval = decode_krb5_predicted_sam_response(&scratch, &psr);
!     if (retval) com_err("krb5kdc", retval, "decode_krb5_predicted_sam_response failed");
!     if (retval) goto cleanup;
!     {
!       /* now psr.sam_key is what we said to use... */
!       retval = krb5_decrypt_data(context, &psr->sam_key, 0, 
! 				 &sr->sam_enc_nonce_or_ts, &scratch);
!       if (retval) com_err("krb5kdc", retval, "decrypt nonce_or_ts failed");
!     }
!     if (retval) goto cleanup;
!     retval = decode_krb5_enc_sam_response_enc(&scratch, &esre);
!     if (retval) com_err("krb5kdc", retval, "decode_krb5_enc_sam_response_enc failed");
!     if (retval) goto cleanup;
!     if (esre->sam_timestamp != sr->sam_patimestamp) {
!       retval = KRB5KDC_ERR_PREAUTH_FAILED;
!       goto cleanup;
!     }
!     retval = krb5_timeofday(context, &timenow);
!     if (retval) goto cleanup;
!     
!     if (labs(timenow - sr->sam_patimestamp) > context->clockskew) {
! 	retval = KRB5KRB_AP_ERR_SKEW;
! 	goto cleanup;
!     }
  
      setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH);
    cleanup:
      if (retval) com_err("krb5kdc", retval, "sam verify failure");
      if (sr) krb5_xfree(sr);
--- 1441,1664 ----
      if (retval) com_err("krb5kdc", retval, "decode_krb5_sam_response failed");
      if (retval) goto cleanup;
  
!     switch(sr->sam_type) {
!       case PA_SAM_TYPE_DIGI_PATH:               /* Is this DIGI_PATH ?? */
! 	if (sr->sam_track_id.length) {
!            krb5_enc_data tmpdata;
!            tmpdata.ciphertext = sr->sam_track_id;
!            retval = krb5_decrypt_data(context, master_encblock.key, 0,
!                               &tmpdata, &scratch);
!            if (retval) {
!               com_err("krb5kdc", retval, "decrypt track_id failed");
!               goto cleanup;
!            }
! 	   retval = decode_krb5_predicted_sam_response(&scratch, &psr);
!            if (retval) {
!               com_err("krb5kdc", retval,
!                 "decode_krb5_predicted_sam_response failed");
!               goto cleanup;
!            }
!            /* now psr.sam_key is what we said to use... */
!            retval = krb5_decrypt_data(context, &psr->sam_key, 0,
!                                  &sr->sam_enc_nonce_or_ts, &scratch);
!            if (retval) {
!              com_err("krb5kdc", retval, "decrypt nonce_or_ts failed");
!              goto cleanup;
!            }
!            retval = decode_krb5_enc_sam_response_enc(&scratch, &esre);
!            if (retval) {
!              com_err("krb5kdc", retval,
! 		"decode_krb5_enc_sam_response_enc failed");
!              goto cleanup;
!            }
!            if (esre->sam_timestamp != sr->sam_patimestamp) {
!              retval = KRB5KDC_ERR_PREAUTH_FAILED;
!              goto cleanup;
!            }
!            retval = krb5_timeofday(context, &timenow);
!            if (retval) goto cleanup;
! 
!            if (labs(timenow - sr->sam_patimestamp) > context->clockskew) {
!              retval = KRB5KRB_AP_ERR_SKEW;
!              goto cleanup;
!            }
! 	} else {        /* sr->sam_track_id.length = 0 */
!            retval = KRB5KDC_ERR_PREAUTH_FAILED;
!            com_err("krb5kdc",retval,"Digital Pathways track_id data not found");
!            goto cleanup;
! 	}
! 	break;
!       case PA_SAM_TYPE_CRYPTOCARD:		/* Cryptocard, perhaps? */
! 	/*
! 	 * Yes, this looks a lot like the SNK code; sue me
! 	 */
! 	if (sr->sam_track_id.length) {
!            krb5_enc_data tmpdata;
! 	   krb5_rb1_track_data *rb1_track_data;
! 	   krb5_encrypt_block eblock;
! 	   krb5_keyblock keyblock;
! 	   krb5_tl_data tl_data;
! 	   krb5_db_entry kdb;
! 	   krb5_principal newp;
! 	   int npr = 0, probeslot;
! 	   krb5_boolean more;
! 
!            tmpdata.ciphertext = sr->sam_track_id;
!            retval = krb5_decrypt_data(context, master_encblock.key, 0,
!                               &tmpdata, &scratch);
!            if (retval) {
!               com_err("krb5kdc", retval, "decrypt track_id failed");
!               retval = KRB5KDC_ERR_PREAUTH_FAILED;
!               goto cleanup;
!            }
! 
! 	   rb1_track_data = (krb5_rb1_track_data *) scratch.data;
! 
! 	   /* eblock is just to set the enctype */
! 	   {
! 	     krb5_data tmpdata;
! 	     const krb5_enctype type = ENCTYPE_DES_CBC_MD5;
! 	     if (!valid_enctype(type)) {
! 	       com_err("krb5kdc", retval, "Trying to use unsupported enctype!");
! 	       retval = KRB5_PROG_ETYPE_NOSUPP;
! 	       goto cleanup;
! 	     }
! 	     krb5_use_enctype(context, &eblock, type); 
! 	     tmpdata.data = rb1_track_data->ascii_response;
! 	     tmpdata.length = 8;
! 	     retval = krb5_string_to_key(context, &eblock,
! 				         &keyblock, &tmpdata, 0 /* salt */);
! 	     if (retval) {
! 	       com_err("krb5kdc", retval, "trying to convert response to encryption key");
! 	       goto cleanup;
! 	     }
! 	   }
! 	   /*
! 	    * Now that we've run the response through string_to_key,
! 	    * let's try decrypting the nonce.
! 	    */
!            retval = krb5_decrypt_data(context, &keyblock, 0,
!                                  &sr->sam_enc_nonce_or_ts, &scratch);
! 	   krb5_free_keyblock_contents(context, &keyblock);
!            if (retval) {
!              com_err("krb5kdc", retval, "decrypt nonce_or_ts failed");
!              goto cleanup;
!            }
!            retval = decode_krb5_enc_sam_response_enc(&scratch, &esre);
!            if (retval) {
!              com_err("krb5kdc", retval,
! 		"decode_krb5_enc_sam_response_enc failed");
!              goto cleanup;
!            }
!            if (esre->sam_timestamp != sr->sam_patimestamp) {
!              retval = KRB5KDC_ERR_PREAUTH_FAILED;
! 	     com_err("krb5kdc", retval, "timestamp compare failed");
!              goto cleanup;
!            }
!            retval = krb5_timeofday(context, &timenow);
!            if (retval) goto cleanup;
! 
!            if (labs(timenow - sr->sam_patimestamp) > context->clockskew) {
!              retval = KRB5KRB_AP_ERR_SKEW;
!              goto cleanup;
!            }
! 	   /*
! 	    * Looks good.  Save the precomputed challenge for next time.
! 	    * Don't bail out if we get an error here.
! 	    */
! 
! 	   retval = krb5_copy_principal(kdc_context, client->princ, &newp);
! 
! 	   if (retval) {
! 	      com_err("krb5kdc", retval, "while copying client name for challenge update");
! 	      goto noupdate;
! 	   }
! 
! 	   /*
! 	    * Sigh ... this deserves an explanation.
! 	    *
! 	    * Since we store all of this in the magical xxx/RB1 principal,
! 	    * we need to find the one associated with this principal.
! 	    * Since we don't get that information, we need to go through
! 	    * all of these gyrations (the same ones done in get_sam_edata())
! 	    * to _get_ that principal name, just so we can store this
! 	    * extra tl_data in it.
! 	    */
! 
! 	   for (sam_ptr = sam_inst_map; sam_ptr->name; sam_ptr++)
! 	      if (sam_ptr->sam_type == PA_SAM_TYPE_CRYPTOCARD)
! 		 break;
! 
! 	   if (sam_ptr->name == 0) {
! 	      com_err("krb5kdc", KRB5_PREAUTH_BAD_TYPE, "while getting CryptoCard info - this shouldn't happen!");
! 	      krb5_free_principal(kdc_context, newp);
! 	      goto noupdate;
! 	   }
! 
! 	   probeslot = krb5_princ_size(kdc_context, newp)++;
! 	   krb5_princ_name(kdc_context, newp) =
! 	      realloc(krb5_princ_name(kdc_context, newp),
! 		      krb5_princ_size(context, newp) * sizeof(krb5_data));
! 	   
! 	   krb5_princ_component(kdc_context, newp, probeslot)->data =
! 	      strdup(sam_ptr->name);
! 	   krb5_princ_component(kdc_context, newp, probeslot)->length =
! 	      strlen(sam_ptr->name);
! 	
! 	   retval = krb5_db_get_principal(kdc_context, newp, &kdb, &npr, &more);
  
+ 	   if (retval) {
+ 	      com_err("krb5kdc", retval, "while getting preauth principal - this shouldn't happen!");
+ 	      krb5_free_principal(kdc_context, newp);
+ 	      goto noupdate;
+ 	   }
+ 	   
+ 	   tl_data.tl_data_type = KRB5_TL_RB1_CHALLENGE;
+ 	   tl_data.tl_data_length = sizeof(rb1_track_data->new_challenge);
+ 	   tl_data.tl_data_contents = rb1_track_data->new_challenge;
+ 
+ 	   retval = krb5_dbe_update_tl_data(kdc_context, &kdb, &tl_data);
+ 	   if (retval) {
+ 	      com_err("krb5kdc", retval, "while updating RB-1 challenge tl_data");
+ 	      krb5_free_principal(kdc_context, newp);
+ 	      krb5_db_free_principal(kdc_context, &kdb, npr);
+ 	      goto noupdate;
+ 	   }
+ 
+ 	   retval = krb5_db_put_principal(kdc_context, &kdb, &npr);
+ 	   if (retval) {
+ 	      com_err("krb5kdc", retval, "while storing RB-1 challenge tl_data");
+ 	      krb5_free_principal(kdc_context, newp);
+ 	      krb5_db_free_principal(kdc_context, &kdb, npr);
+ 	      goto noupdate;
+ 	   }
+ 
+ 	   krb5_free_principal(kdc_context, newp);
+ 	   krb5_db_free_principal(kdc_context, &kdb, npr);
+ noupdate:
+ 	/* At this point, things are non-fatal */
+ 	retval = 0;
+ 	} else {        /* sr->sam_track_id.length = 0 */
+            retval = KRB5KDC_ERR_PREAUTH_FAILED;
+            com_err("krb5kdc",retval,"CryptoCard track_id data not found");
+            goto cleanup;
+ 	}
+ 	break;
+ #ifdef ARL_SECURID_PREAUTH
+       case PA_SAM_TYPE_SECURID:
+ 	/* SecurID passcode checking goes here */
+ 	retval = verify_securid_data(context,client,sr,enc_tkt_reply);
+ 	goto cleanup;
+         /*NOTREACHED*/
+ #endif /* ARL_SECURID_PREAUTH */
+       default:
+ 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ 	goto cleanup;
+     }  /* switch(sr->sam_type) */
+     /* Successful HW Preautentication */
      setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH);
+     setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH);
+ 
    cleanup:
      if (retval) com_err("krb5kdc", retval, "sam verify failure");
      if (sr) krb5_xfree(sr);
Index: kdc/kdc_util.c
diff -c krb5/kdc/kdc_util.c:1.1.1.4 krb5/kdc/kdc_util.c:1.8
*** krb5/kdc/kdc_util.c:1.1.1.4	Wed May 12 13:21:44 1999
--- krb5/kdc/kdc_util.c	Wed May 12 14:55:55 1999
***************
*** 412,423 ****
  static krb5_last_req_entry nolrentry = { KV5M_LAST_REQ_ENTRY, KRB5_LRQ_NONE, 0 };
  static krb5_last_req_entry *nolrarray[] = { &nolrentry, 0 };
  
  krb5_error_code
  fetch_last_req_info(dbentry, lrentry)
  krb5_db_entry *dbentry;
  krb5_last_req_entry ***lrentry;
  {
!     *lrentry = nolrarray;
      return 0;
  }
  
--- 412,446 ----
  static krb5_last_req_entry nolrentry = { KV5M_LAST_REQ_ENTRY, KRB5_LRQ_NONE, 0 };
  static krb5_last_req_entry *nolrarray[] = { &nolrentry, 0 };
  
+ static krb5_last_req_entry pwexpentry = { KV5M_LAST_REQ_ENTRY,
+ 					  KRB5_LRQ_PW_EXPTIME, 0 };
+ static krb5_last_req_entry *pwexparray[] = { &pwexpentry, 0 };
+ 
  krb5_error_code
  fetch_last_req_info(dbentry, lrentry)
  krb5_db_entry *dbentry;
  krb5_last_req_entry ***lrentry;
  {
!     krb5_timestamp timenow;
!     krb5_error_code retval;
! 
!     if (kdc_warn_pwexpire == 0 || dbentry->pw_expiration == 0) {
! 	*lrentry = nolrarray;
! 	return 0;
!     }
! 
!     if ((retval = krb5_timeofday(kdc_context, &timenow)) != 0)
! 	return retval;
! 		    
!     if (dbentry->pw_expiration > timenow + kdc_warn_pwexpire) {
! 	*lrentry = nolrarray;
! 	return 0;
!     }
! 
!     pwexpentry.value = dbentry->pw_expiration;
! 
!     *lrentry = pwexparray;
! 
      return 0;
  }
  
***************
*** 802,808 ****
   */
  #define AS_OPTIONS_HANDLED (KDC_OPT_FORWARDABLE | KDC_OPT_PROXIABLE | \
  			     KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED | \
! 			     KDC_OPT_RENEWABLE | KDC_OPT_RENEWABLE_OK)
  int
  validate_as_request(request, client, server, kdc_time, status)
  register krb5_kdc_req *request;
--- 825,832 ----
   */
  #define AS_OPTIONS_HANDLED (KDC_OPT_FORWARDABLE | KDC_OPT_PROXIABLE | \
  			     KDC_OPT_ALLOW_POSTDATE | KDC_OPT_POSTDATED | \
! 			     KDC_OPT_RENEWABLE | KDC_OPT_RENEWABLE_OK | \
! 			     KDC_OPT_HW_AUTH)
  int
  validate_as_request(request, client, server, kdc_time, status)
  register krb5_kdc_req *request;
Index: kdc/kdc_util.h
diff -c krb5/kdc/kdc_util.h:1.1.1.2 krb5/kdc/kdc_util.h:1.3
*** krb5/kdc/kdc_util.h:1.1.1.2	Wed May 12 13:21:44 1999
--- krb5/kdc/kdc_util.h	Wed May 12 14:55:56 1999
***************
*** 130,136 ****
  /* kdc_preauth.c */
  const char * missing_required_preauth
      PROTOTYPE((krb5_db_entry *client, krb5_db_entry *server,
! 	       krb5_enc_tkt_part *enc_tkt_reply));
  void get_preauth_hint_list PROTOTYPE((krb5_kdc_req * request,
  				      krb5_db_entry *client,
  				      krb5_db_entry *server,
--- 130,136 ----
  /* kdc_preauth.c */
  const char * missing_required_preauth
      PROTOTYPE((krb5_db_entry *client, krb5_db_entry *server,
! 	       krb5_enc_tkt_part *enc_tkt_reply, krb5_kdc_req *request));
  void get_preauth_hint_list PROTOTYPE((krb5_kdc_req * request,
  				      krb5_db_entry *client,
  				      krb5_db_entry *server,
Index: kdc/kerberos_v4.c
diff -c krb5/kdc/kerberos_v4.c:1.1.1.3 krb5/kdc/kerberos_v4.c:1.7
*** krb5/kdc/kerberos_v4.c:1.1.1.3	Wed May 12 13:21:45 1999
--- krb5/kdc/kerberos_v4.c	Mon May 24 12:00:43 1999
***************
*** 43,52 ****
  #include <arpa/inet.h>
  #include <netdb.h>
  #include <signal.h>
- #ifndef POSIX_TERMIOS
- #include <sgtty.h>
- #endif
- #include <sys/ioctl.h>
  #ifdef HAVE_SYS_TIME_H
  #include <sys/time.h>
  #ifdef TIME_WITH_SYS_TIME
--- 43,48 ----
***************
*** 87,95 ****
  /* take this out when we don't need it anymore */
  int krbONE = 1;
  
- #ifdef notdef
- static struct sockaddr_in sin = {AF_INET};
- #endif
  int     f;
  
  /* XXX several files in libkdb know about this */
--- 83,88 ----
***************
*** 156,161 ****
--- 149,251 ----
  void kerb_err_reply PROTOTYPE((struct sockaddr_in *, KTEXT, long, char *));
  int set_tgtkey PROTOTYPE((char *));
   
+ /* Attributes converted from V5 to V4 - internal representation */
+ #define V4_KDB_REQUIRES_PREAUTH  0x1
+ #define V4_KDB_DISALLOW_ALL_TIX  0x2
+ #define V4_KDB_REQUIRES_PWCHANGE 0x4
+ 
+ 
+ /* v4 compatibitly mode switch */
+ #define KDC_V4_NONE		0	/* Don't even respond to packets */
+ #define KDC_V4_DISABLE		1	/* V4 requests return an error */
+ #define	KDC_V4_FULL		2	/* Preauth required go through */
+ #define KDC_V4_NOPREAUTH	3	/* Preauth required disallowed */
+ 
+ #define KDC_V4_DEFAULT_MODE KDC_V4_NOPREAUTH
+ /* Flag on how to handle v4 */
+ static int		kdc_v4;
+ 
+ struct v4mode_lookup_entry {
+     int                 mode;                   /* Mode setting */
+     const char *	v4_specifier;		/* How to recognize it	*/
+ };
+ 
+ static const struct v4mode_lookup_entry  v4mode_table[] = {
+ /*  mode                input specifier */
+ { KDC_V4_NONE,          "none"          },
+ { KDC_V4_DISABLE,       "disable"       }, 
+ { KDC_V4_FULL,          "full"          },
+ { KDC_V4_NOPREAUTH,     "nopreauth"     }
+ };
+ 
+ static const int v4mode_table_nents = sizeof(v4mode_table)/
+ 				      sizeof(v4mode_table[0]);
+ 
+ void process_v4_mode(progname, string)
+     const char          *progname;
+     const char          *string;
+ {
+     int i, found;
+ 
+     found = 0;
+     kdc_v4 = KDC_V4_DEFAULT_MODE;
+ 
+     if(!string) return;  /* Set to default mode */
+     
+     for (i=0; i<v4mode_table_nents; i++) {
+ 	if (!strcasecmp(string, v4mode_table[i].v4_specifier)) {
+ 	    found = 1;
+ 	    kdc_v4 = v4mode_table[i].mode;
+ 	    break;
+ 	}
+     }
+ 
+     if(!found) {
+       /* It is considered fatal if we request a mode that is not found */
+ 	com_err(progname, 0, "invalid v4_mode %s", string);
+ 	exit(1);
+     }
+     return;
+ }
+ 
+ #define klog v4_klog
+ #ifdef HAVE_STDARG_H
+ char * v4_klog( int type, const char *format, ...)
+ #else
+ char * v4_klog( type, format, va_alist)
+     int type;
+     char *format;
+     va_dcl
+ #endif
+ {
+     int logpri = LOG_INFO;
+     va_list pvar;
+ #ifdef HAVE_STDARG_H
+     va_start(pvar, format);
+ #else
+     va_start(pvar);
+ #endif
+ 
+     switch (type) {
+     case L_ERR_SEXP:
+     case L_ERR_NKY:
+     case L_ERR_NUN:
+     case L_ERR_UNK:
+     case L_KRB_PERR:
+ 	logpri = LOG_ERR;
+     case L_INI_REQ:
+     case L_NTGT_INTK:
+     case L_TKT_REQ:
+     case L_APPL_REQ:
+ 	strcpy(log_text, "PROCESS_V4:");
+ 	vsprintf(log_text+strlen(log_text), format, pvar);
+ 	krb5_klog_syslog(logpri, "%s", log_text);
+     /* ignore the other types... */
+     }
+     va_end(pvar);
+     return(log_text);
+ }
+ 
  krb5_error_code
  process_v4( pkt, client_fulladdr, is_secondary, resp)
  const krb5_data *pkt;
***************
*** 198,264 ****
      v4_pkt.length = pkt->length;
      memcpy( v4_pkt.dat, pkt->data, pkt->length);
  
      kerberos_v4( &client_sockaddr, &v4_pkt);
      *resp = response;
      return(retval);
  }
- #if 0
- /* convert k4's klog() levels into corresponding errors for v5: */
- int type_2_v5err[] = { 0,	/* 		0 No error		     */
-     KDC_ERR_NONE,		/* L_NET_ERR	1 Error in network code      */
-     KDC_ERR_NONE,		/* L_NET_INFO	2 Info on network activity   */
-     KRB_AP_ERR_BADVERSION,	/* L_KRB_PERR	3 Kerberos protocol errors   */
-     KDC_ERR_NONE,		/* L_KRB_PINFO	4 Kerberos protocol info     */
-     KDC_ERR_NONE,		/* L_INI_REQ	5 Request for initial ticket */
-     KRB_AP_ERR_BADVERSION,	/* L_NTGT_INTK	6 Initial request not for TGT*/
-     KDC_ERR_NONE,		/* L_DEATH_REQ	7 Request for server death   */
-     KDC_ERR_NONE,		/* L_TKT_REQ	8 All ticket requests w/ tgt */
-     KDC_ERR_SERVICE_EXP,	/* L_ERR_SEXP	9 Service expired	     */
-     KDC_ERR_C_OLD_MAST_KVNO,	/* L_ERR_MKV	10 Master key version old    */
-     KDC_ERR_NULL_KEY,		/* L_ERR_NKY    11 User's key is null        */
-     KDC_ERR_PRINCIPAL_NOT_UNIQUE, /* L_ERR_NUN	12 Principal not unique      */
-     KDC_ERR_C_PRINCIPAL_UNKNOWN,  /* L_ERR_UNK	13 Principal Unknown         */
-     KDC_ERR_NONE,		/* L_ALL_REQ    14 All requests	     	     */
-     KDC_ERR_NONE,		/* L_APPL_REQ   15 Application requests w/tgt*/
-     KRB_AP_ERR_BADVERSION	/* L_KRB_PWARN  16 Protocol warning messages */
- };
- #endif
- #ifdef HAVE_STDARG_H
- char * v4_klog( int type, const char *format, ...)
- #else
- char * v4_klog( type, format, va_alist)
-     int type;
-     char *format;
-     va_dcl
- #endif
- {
-     int logpri = LOG_INFO;
-     va_list pvar;
- #ifdef HAVE_STDARG_H
-     va_start(pvar, format);
- #else
-     va_start(pvar);
- #endif
- 
-     switch (type) {
-     case L_ERR_SEXP:
-     case L_ERR_NKY:
-     case L_ERR_NUN:
-     case L_ERR_UNK:
-     case L_KRB_PERR:
- 	logpri = LOG_ERR;
-     case L_INI_REQ:
-     case L_NTGT_INTK:
-     case L_TKT_REQ:
-     case L_APPL_REQ:
- 	strcpy(log_text, "PROCESS_V4:");
- 	vsprintf(log_text+strlen(log_text), format, pvar);
- 	krb5_klog_syslog(logpri, log_text);
-     /* ignore the other types... */
-     }
-     va_end(pvar);
-     return(log_text);
- }
  
  static
  int krb4_sendto(s, msg, len, flags, to, to_len)
--- 288,304 ----
      v4_pkt.length = pkt->length;
      memcpy( v4_pkt.dat, pkt->data, pkt->length);
  
+     /* Check if disabled completely */
+     if (kdc_v4 == KDC_V4_NONE) {
+ 	(void) klog(L_KRB_PERR,
+ 	"Disabled KRB V4 request");
+ 	return KRB5KDC_ERR_BAD_PVNO;
+     }
+ 
      kerberos_v4( &client_sockaddr, &v4_pkt);
      *resp = response;
      return(retval);
  }
  
  static
  int krb4_sendto(s, msg, len, flags, to, to_len)
***************
*** 424,438 ****
       */
      v4_time = (entries.max_life + MIN5 - 1) / MIN5;
      principal->max_life = v4_time > HR21 ? HR21 : (unsigned char) v4_time;
!     principal->exp_date = (unsigned long) entries.expiration;
  /*    principal->mod_date = (unsigned long) entries.mod_date; */
  /* Set the master key version to 1. It's not really useful because all keys
   * will be encrypted in the same master key version, and digging out the 
!  * actuall key version will be harder than it's worth --proven */
  /*    principal->kdc_key_ver = entries.mkvno; */
      principal->kdc_key_ver = 1;
      principal->key_version = pkey->key_data_kvno;
      principal->attributes = 0;
  
      /* set up v4 format of each date's text: */
      for ( date = &principal->exp_date, text = principal->exp_date_txt;
--- 464,499 ----
       */
      v4_time = (entries.max_life + MIN5 - 1) / MIN5;
      principal->max_life = v4_time > HR21 ? HR21 : (unsigned char) v4_time;
!     /*
!      * This is weird, but the intent is that the expiration is the minimum
!      * of the principal expiration and key expiration
!      */
!     principal->exp_date = (unsigned long) 
!         entries.expiration && entries.pw_expiration ?
!         min(entries.expiration, entries.pw_expiration) :
!         (entries.pw_expiration ? entries.pw_expiration :
!         entries.expiration);
  /*    principal->mod_date = (unsigned long) entries.mod_date; */
  /* Set the master key version to 1. It's not really useful because all keys
   * will be encrypted in the same master key version, and digging out the 
!  * actual key version will be harder than it's worth --proven */
  /*    principal->kdc_key_ver = entries.mkvno; */
      principal->kdc_key_ver = 1;
      principal->key_version = pkey->key_data_kvno;
+     /* We overload the attributes with the relevant v5 ones */
      principal->attributes = 0;
+     if (isflagset(entries.attributes,  KRB5_KDB_REQUIRES_HW_AUTH) ||
+ 	isflagset(entries.attributes,  KRB5_KDB_REQUIRES_PRE_AUTH)) {
+           principal->attributes |= V4_KDB_REQUIRES_PREAUTH;
+     }
+     if (isflagset(entries.attributes,  KRB5_KDB_DISALLOW_ALL_TIX)) {
+           principal->attributes |= V4_KDB_DISALLOW_ALL_TIX;
+     }
+     if (isflagset(entries.attributes,  KRB5_KDB_REQUIRES_PWCHANGE)) {
+           principal->attributes |= V4_KDB_REQUIRES_PWCHANGE;
+     }
+ 
+ 
  
      /* set up v4 format of each date's text: */
      for ( date = &principal->exp_date, text = principal->exp_date_txt;
***************
*** 507,512 ****
--- 568,584 ----
  
      req_act_vno = req_version;
  
+     /* check if disabled, but we tell client */
+     if (kdc_v4 == KDC_V4_DISABLE) {
+ 	lt = klog(L_KRB_PERR,
+ 	"KRB will not handle v4 request from %s",
+ 		  inet_ntoa(client_host));
+ 	/* send an error reply */
+ 	req_name_ptr = req_inst_ptr = req_realm_ptr = "";
+ 	kerb_err_reply(client, pkt, KERB_ERR_PKT_VER, lt);
+ 	return;
+     }
+ 
      /* check packet version */
      if (req_version != KRB_PROT_VERSION) {
  	lt = klog(L_KRB_PERR,
***************
*** 793,830 ****
  }
  
  
- #ifndef BACKWARD_COMPAT
- /*
-  * setup_disc 
-  *
-  * disconnect all descriptors, remove ourself from the process
-  * group that spawned us. 
-  */
- 
- setup_disc()
- {
- 
-     int     s;
- 
-     for (s = 0; s < 3; s++) {
- 	(void) close(s);
-     }
- 
-     (void) open("/dev/null", 0);
-     (void) dup2(0, 1);
-     (void) dup2(0, 2);
- 
-     s = open("/dev/tty", 2);
- 
-     if (s >= 0) {
- 	ioctl(s, TIOCNOTTY, (struct sgttyb *) 0);
- 	(void) close(s);
-     }
-     (void) chdir("/tmp");
-     return;
- }
- #endif /* BACKWARD_COMPAT */
- 
  
  /*
   * kerb_er_reply creates an error reply packet and sends it to the
--- 865,870 ----
***************
*** 852,885 ****
  
  }
  
- #ifndef BACKWARD_COMPAT
- /*
-  * Make sure that database isn't stale.
-  *
-  * Exit if it is; we don't want to tell lies.
-  */
- 
- static void check_db_age()
- {
-     long age;
-     
-     if (max_age != -1) {
- 	/* Requires existance of kerb_get_db_age() */
- 	gettimeofday(&kerb_time, 0);
- 	age = kerb_get_db_age();
- 	if (age == 0) {
- 	    klog(L_KRB_PERR, "Database currently being updated!");
- 	    hang();
- 	}
- 	if ((age + max_age) < kerb_time.tv_sec) {
- 	    klog(L_KRB_PERR, "Database out of date!");
- 	    hang();
- 	    /* NOTREACHED */
- 	}
-     }
- }
- #endif /* BACKWARD_COMPAT */
- 
  /*
   * Given a pointer to a long containing the number of seconds
   * since the beginning of time (midnight 1 Jan 1970 GMT), return
--- 892,897 ----
***************
*** 898,905 ****
  
      adjusted_time = *t /* - CONVERT_TIME_EPOCH */;
      tm = localtime(&adjusted_time);
!     (void) sprintf(st,"%4d-%s-%02d %02d:%02d:%02d",tm->tm_mday+1900,
!                    month_sname(tm->tm_mon + 1),tm->tm_year,
                     tm->tm_hour, tm->tm_min, tm->tm_sec);
      return st;
  }
--- 910,917 ----
  
      adjusted_time = *t /* - CONVERT_TIME_EPOCH */;
      tm = localtime(&adjusted_time);
!     (void) sprintf(st,"%2d-%s-%4d %02d:%02d:%02d",tm->tm_mday,
!                    month_sname(tm->tm_mon + 1),tm->tm_year+1900,
                     tm->tm_hour, tm->tm_min, tm->tm_sec);
      return st;
  }
***************
*** 943,948 ****
--- 955,996 ----
  		  p_name, instance, 0);
  	return KERB_ERR_PRINCIPAL_NOT_UNIQUE;
      }
+ 
+     /*
+      * Check our V5 stuff first.
+      */
+ 
+     /*
+      * Does the principal have REQUIRES_PWCHANGE set?
+      */
+     if (isflagset(p->attributes, V4_KDB_REQUIRES_PWCHANGE)) {
+ 	lt = klog(L_ERR_SEXP, "V5 REQUIRES_PWCHANGE set "
+ 		  "\"%s\" \"%s\"", p_name, instance);
+ 	return KERB_ERR_NAME_EXP;
+     }
+ 
+     /*
+      * Does the principal have DISALLOW_ALL_TIX set?
+      */
+     if (isflagset(p->attributes, V4_KDB_DISALLOW_ALL_TIX)) {
+ 	lt = klog(L_ERR_SEXP, "V5 DISALLOW_ALL_TIX set: "
+ 		  "\"%s\" \"%s\"", p_name, instance);
+ 	/* Not sure of a better error to return */
+ 	return KERB_ERR_NAME_EXP;
+     }
+ 
+     /*
+      * Does the principal require preauthentication?
+      */
+     if ((kdc_v4 == KDC_V4_NOPREAUTH) &&
+ 	isflagset(p->attributes, V4_KDB_REQUIRES_PREAUTH)) {
+         lt = klog(L_ERR_SEXP, "V5 REQUIRES_PREAUTH set: "
+ 		  "\"%s\" \"%s\"", p_name, instance);
+ 	/* Not sure of a better error to return */
+ 	return KERB_ERR_AUTH_EXP;
+ /*	return KERB_ERR_NAME_EXP;*/
+     }
+ 
      /* If the user's key is null, we want to return an error */
      if ((p->key_low == 0) && (p->key_high == 0)) {
  	/* User has a null key */
***************
*** 993,1016 ****
      return (KSUCCESS);
  }
  
- #ifndef BACKWARD_COMPAT
- static void
- hang()
- {
-     if (pause_int == -1) {
- 	klog(L_KRB_PERR, "Kerberos will pause so as not to loop init");
- 	for (;;)
- 	    pause();
-     } else {
- 	char buf[256];
- 	sprintf(buf,  "Kerberos will wait %d seconds before dying so as not to loop init", pause_int);
- 	klog(L_KRB_PERR, buf);
- 	sleep(pause_int);
- 	klog(L_KRB_PERR, "Do svedania....\n");
- 	exit(1);
-     }
- }
- #endif /* BACKWARD_COMPAT */
  #else	/* KRB5_KRB4_COMPAT */
  #include "k5-int.h"
  #endif /* KRB5_KRB4_COMPAT */
--- 1041,1046 ----
Index: kdc/main.c
diff -c krb5/kdc/main.c:1.1.1.2 krb5/kdc/main.c:1.4
*** krb5/kdc/main.c:1.1.1.2	Wed May 12 13:21:45 1999
--- krb5/kdc/main.c	Wed May 12 14:55:56 1999
***************
*** 691,697 ****
  usage(name)
  char *name;
  {
!     fprintf(stderr, "usage: %s [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-n]\n", name);
      return;
  }
  
--- 691,697 ----
  usage(name)
  char *name;
  {
!     fprintf(stderr, "usage: %s [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-4 v4mode] [-n]\n", name);
      return;
  }
  
***************
*** 713,718 ****
--- 713,722 ----
      char		*default_ports = 0;
      krb5_pointer	aprof;
      const char		*hierarchy[3];
+ #ifdef KRB5_KRB4_COMPAT
+     char		*v4mode = 0;
+ #endif
+     krb5_int32		pw_warn_expire;
      extern char *optarg;
  
      if (!krb5_aprof_init(DEFAULT_KDC_PROFILE, KDC_PROFILE_ENV, &aprof)) {
***************
*** 721,726 ****
--- 725,738 ----
  	hierarchy[2] = (char *) NULL;
  	if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &default_ports))
  	    default_ports = 0;
+ 	hierarchy[1] = "kdc_warn_pwexpire";
+ 	if (krb5_aprof_get_deltat(aprof, hierarchy, TRUE, &kdc_warn_pwexpire))
+ 		kdc_warn_pwexpire = 0;
+ #ifdef KRB5_KRB4_COMPAT
+ 	hierarchy[1] = "v4_mode";
+ 	if (krb5_aprof_get_string(aprof, hierarchy, TRUE, &v4mode))
+ 	    v4mode = 0;
+ #endif
  	/* aprof_init can return 0 with aprof == NULL */
  	if (aprof)
  	     krb5_aprof_finish(aprof);
***************
*** 732,738 ****
       * Loop through the option list.  Each time we encounter a realm name,
       * use the previously scanned options to fill in for defaults.
       */
!     while ((c = getopt(argc, argv, "r:d:mM:k:R:e:p:s:n")) != EOF) {
  	switch(c) {
  	case 'r':			/* realm name for db */
  	    if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) {
--- 744,750 ----
       * Loop through the option list.  Each time we encounter a realm name,
       * use the previously scanned options to fill in for defaults.
       */
!     while ((c = getopt(argc, argv, "r:d:mM:k:R:e:p:s:n4:")) != EOF) {
  	switch(c) {
  	case 'r':			/* realm name for db */
  	    if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) {
***************
*** 775,786 ****
--- 787,812 ----
  		free(default_ports);
  	    default_ports = strdup(optarg);
  	    break;
+ 	case '4':
+ #ifdef KRB5_KRB4_COMPAT
+ 	    if (v4mode)
+ 		free(v4mode);
+ 	    v4mode = strdup(optarg);
+ #endif
+ 	    break;
  	case '?':
  	default:
  	    usage(argv[0]);
  	    exit(1);
  	}
      }
+ 
+ #ifdef KRB5_KRB4_COMPAT
+     /*
+      * Setup the v4 mode 
+      */
+     process_v4_mode(argv[0], v4mode);
+ #endif
  
      /*
       * Check to see if we processed any realms.
Index: kdc/network.c
diff -c krb5/kdc/network.c:1.1.1.1 krb5/kdc/network.c:1.4
*** krb5/kdc/network.c:1.1.1.1	Mon Jun  2 17:54:09 1997
--- krb5/kdc/network.c	Mon Feb  9 20:04:07 1998
***************
*** 44,49 ****
--- 44,50 ----
  
  static int *udp_port_fds = (int *) NULL;
  static u_short *udp_port_nums = (u_short *) NULL;
+ static struct in_addr *udp_port_addrs = (struct in_addr *) NULL;
  static int n_udp_ports = 0;
  static int max_udp_ports = 0;
  static fd_set select_fds;
***************
*** 51,66 ****
  
  #define safe_realloc(p,n) ((p)?(realloc(p,n)):(malloc(n)))
  
! static krb5_error_code add_port(port)
       u_short port;
  {
      int	i;
      int *new_fds;
      u_short *new_ports;
      int new_max;
  
      for (i=0; i < n_udp_ports; i++) {
! 	if (udp_port_nums[i] == port)
  	    return 0;
      }
      
--- 52,70 ----
  
  #define safe_realloc(p,n) ((p)?(realloc(p,n)):(malloc(n)))
  
! static krb5_error_code add_port(port, interface)
       u_short port;
+      struct in_addr *interface;
  {
      int	i;
      int *new_fds;
      u_short *new_ports;
+     struct in_addr *new_addrs;
      int new_max;
  
      for (i=0; i < n_udp_ports; i++) {
! 	if (udp_port_nums[i] == port &&
! 	    memcmp(&udp_port_addrs[i], interface, sizeof(struct in_addr)) == 0)
  	    return 0;
      }
      
***************
*** 76,84 ****
  	    return ENOMEM;
  	udp_port_nums = new_ports;
  
  	max_udp_ports = new_max;
      }
! 	
      udp_port_nums[n_udp_ports++] = port;
      return 0;
  }
--- 80,95 ----
  	    return ENOMEM;
  	udp_port_nums = new_ports;
  
+ 	new_addrs = safe_realloc(udp_port_addrs, new_max *
+ 				 sizeof(struct in_addr));
+ 	if (new_addrs == 0)
+ 	    return ENOMEM;
+ 	udp_port_addrs = new_addrs;
+ 
  	max_udp_ports = new_max;
      }
! 
!     memcpy(&udp_port_addrs[n_udp_ports], interface, sizeof(struct in_addr));
      udp_port_nums[n_udp_ports++] = port;
      return 0;
  }
***************
*** 89,102 ****
  const char *prog;
  {
      struct sockaddr_in sin;
      krb5_error_code retval;
      u_short port;
      char *cp;
!     int i;
  
      FD_ZERO(&select_fds);
      select_nfds = 0;
      memset((char *)&sin, 0, sizeof(sin));
  
      /* Handle each realm's ports */
      for (i=0; i<kdc_numrealms; i++) {
--- 100,133 ----
  const char *prog;
  {
      struct sockaddr_in sin;
+     struct in_addr saddr;
      krb5_error_code retval;
      u_short port;
      char *cp;
!     int i, j, numaddrs;
!     krb5_address **localaddrs;
!     const int on = 1; 
  
      FD_ZERO(&select_fds);
      select_nfds = 0;
      memset((char *)&sin, 0, sizeof(sin));
+     sin.sin_family = AF_INET;
+     saddr.s_addr = INADDR_ANY;
+ 
+     /*
+      * Sigh.  We need to bind to all of the interfaces individually
+      * in addition to the wildcard address, since that's the only
+      * way to deal with multihomed hosts and asymmetric routing.
+      * So first, get a list of all local interfaces.
+      */
+ 
+     retval = krb5_os_localaddr(kdc_context, &localaddrs);
+     if (retval) {
+ 	com_err(prog, 0, "Cannot find local addresses");
+ 	return(retval);
+     }
+ 
+     for (numaddrs = 0; localaddrs[numaddrs] != NULL; numaddrs++) ;
  
      /* Handle each realm's ports */
      for (i=0; i<kdc_numrealms; i++) {
***************
*** 109,117 ****
  	    port = strtol(cp, &cp, 10);
  	    if (cp == 0)
  		break;
! 	    retval = add_port(port);
  	    if (retval)
  		return retval;
  	}
      }
  
--- 140,164 ----
  	    port = strtol(cp, &cp, 10);
  	    if (cp == 0)
  		break;
! 	    /*
! 	     * We first add an interface for the wildcard address.
! 	     */
! 	    retval = add_port(port, &saddr);
  	    if (retval)
  		return retval;
+ 	    /*
+ 	     * Next, add ports for all of the network interfaces
+ 	     */
+ 	    for (j = 0; j < numaddrs; j++) {
+ 		struct in_addr tsaddr;
+ 		if (localaddrs[j]->addrtype == ADDRTYPE_INET) {
+ 		    memcpy((char *)&tsaddr, (char *) localaddrs[j]->contents,
+ 			   localaddrs[j]->length);
+ 		    retval = add_port(port, &tsaddr);
+ 		    if (retval)
+ 			return retval;
+ 		}
+ 	    }
  	}
      }
  
***************
*** 122,127 ****
--- 169,192 ----
  		    udp_port_nums[i]);
  	    return(retval);
  	}
+ 
+ 	/*
+ 	 * Turn on SO_REUSEADDR on this socket (since we're now creating
+ 	 * more than one socket per port).
+ 	 */
+ 
+ 	if (setsockopt(udp_port_fds[i], SOL_SOCKET, SO_REUSEADDR, (char *)&on,
+ 		       sizeof(on)) != 0) {
+ 	    com_err(prog, errno, "setsockopt(udp, reuseaddr)");
+ 	    /* This isn't _that_ serious ... */
+ 	}
+ 
+ 	/*
+ 	 * Copy over the appropriate local address to bind to
+ 	 */
+ 	memcpy((char *)&sin.sin_addr, (char *) &udp_port_addrs[i],
+ 	       sizeof(struct in_addr));
+ 
  	sin.sin_port = htons(udp_port_nums[i]);
  	if (bind(udp_port_fds[i], (struct sockaddr *) &sin,
  		 sizeof(sin)) == -1) {
***************
*** 134,139 ****
--- 199,206 ----
  	if (udp_port_fds[i]+1 > select_nfds)
  	    select_nfds = udp_port_fds[i]+1;
      }
+ 
+     krb5_free_addresses(kdc_context, localaddrs);
  
      return 0;
  }
Index: kdc/replay.c
diff -c krb5/kdc/replay.c:1.1.1.2 krb5/kdc/replay.c:1.2
*** krb5/kdc/replay.c:1.1.1.2	Wed May 12 13:21:46 1999
--- krb5/kdc/replay.c	Tue Jul  6 13:16:45 1999
***************
*** 54,60 ****
  		    !memcmp((ptr)->req_packet->data, inpkt->data,	\
  			    inpkt->length) &&				\
  		    ((ptr)->addr->length == from->address->length) &&	\
! 		    !memcmp((ptr)->addr->contents, from->address,	\
  			    from->address->length)&&			\
  		    ((ptr)->db_age == db_age))
  /* XXX
--- 54,60 ----
  		    !memcmp((ptr)->req_packet->data, inpkt->data,	\
  			    inpkt->length) &&				\
  		    ((ptr)->addr->length == from->address->length) &&	\
! 		    !memcmp((ptr)->addr->contents, from->address->contents,\
  			    from->address->length)&&			\
  		    ((ptr)->db_age == db_age))
  /* XXX
Index: kdc/rtest.c
diff -c krb5/kdc/rtest.c:1.1.1.1 krb5/kdc/rtest.c:1.2
*** krb5/kdc/rtest.c:1.1.1.1	Mon Jun  2 17:54:09 1997
--- krb5/kdc/rtest.c	Tue Oct  7 15:44:52 1997
***************
*** 26,31 ****
--- 26,59 ----
  #include "k5-int.h"
  #include <stdio.h>
  #include "kdc_util.h"
+ #include "extern.h"
+ 
+ krb5_principal 
+ make_princ(ctx, str, prog)
+     krb5_context ctx;
+     const char *str;
+     const char *prog;
+ {
+     krb5_principal ret;
+     char *dat;
+ 
+     if(!(ret = (krb5_principal) malloc(sizeof(krb5_principal_data)))) {
+ 	  com_err(prog, ENOMEM, "while allocating principal data");
+ 	  exit(3);
+     }
+     memset(ret, 0, sizeof(krb5_principal_data));
+ 
+     /* We do not include the null... */
+     if(!(dat = (char *) malloc(strlen(str)))) {
+ 	  com_err(prog, ENOMEM, "while allocating principal realm data");
+ 	  exit(3);
+     }
+     memcpy(dat, str, strlen(str));
+     krb5_princ_set_realm_data(ctx, ret, dat);
+     krb5_princ_set_realm_length(ctx, ret, strlen(str));
+     
+     return ret;
+ }
  
  void
  main(argc,argv)
***************
*** 34,80 ****
      {
  	krb5_data otrans;
  	krb5_data ntrans;
! 
! 	krb5_data *tgnames[10];
! 	krb5_principal tgs = tgnames;
! 	krb5_data tgsrlm;
! 
! 	krb5_data *cnames[10];
! 	krb5_principal cl = cnames;
! 	krb5_data crlm;
! 
! 	krb5_data *snames[10];
! 	krb5_principal sv = snames;
! 	krb5_data srlm;
  
  	if (argc < 4) {
  	    fprintf(stderr, "not enough args\n");
  	    exit(1);
  	}
  	ntrans.length = 0;
! 	otrans.length = strlen(argv[1]) + 1;
  	otrans.data = (char *) malloc(otrans.length);
! 	strcpy(otrans.data,argv[1]);
  
! 	tgsrlm.length = strlen(argv[2]) + 1;
! 	tgsrlm.data = (char *) malloc(tgsrlm.length);
! 	strcpy(tgsrlm.data,argv[2]);
! 	tgs[0] = &tgsrlm;
! 
! 	crlm.length = strlen(argv[3]) + 1;
! 	crlm.data = (char *) malloc(crlm.length);
! 	strcpy(crlm.data,argv[3]);
! 	cl[0] = &crlm;
! 
! 	srlm.length = strlen(argv[4]) + 1;
! 	srlm.data = (char *) malloc(srlm.length);
! 	strcpy(srlm.data,argv[4]);
! 	sv[0] = &srlm;
  	
  	add_to_transited(&otrans,&ntrans,tgs,cl,sv);
  
  	printf("%s\n",ntrans.data);
  
      }
  
! krb5_encrypt_block master_encblock;
--- 62,111 ----
      {
  	krb5_data otrans;
  	krb5_data ntrans;
! 	krb5_principal tgs, cl, sv;
! 	krb5_error_code kret;
! 	kdc_realm_t	kdc_realm;
  
  	if (argc < 4) {
  	    fprintf(stderr, "not enough args\n");
  	    exit(1);
  	}
+ 
+ 
+ 	/* Get a context */
+ 	kret = krb5_init_context(&kdc_realm.realm_context);
+ 	if (kret) {
+ 	  com_err(argv[0], kret, "while getting krb5 context");
+ 	  exit(2);
+ 	}
+ 	/* Needed so kdc_context will work */
+ 	kdc_active_realm = &kdc_realm;
+ 
  	ntrans.length = 0;
! 	ntrans.data = 0;
! 
! 	otrans.length = strlen(argv[1]);
  	otrans.data = (char *) malloc(otrans.length);
! 	memcpy(otrans.data,argv[1], otrans.length);
  
! 	tgs = make_princ(kdc_context, argv[2], argv[0]);
! 	cl  = make_princ(kdc_context, argv[3], argv[0]);
! 	sv  = make_princ(kdc_context, argv[4], argv[0]);
  	
  	add_to_transited(&otrans,&ntrans,tgs,cl,sv);
  
  	printf("%s\n",ntrans.data);
  
+ 	/* Free up all memory so we can profile for leaks */
+ 	free(otrans.data);
+ 	free(ntrans.data);
+ 
+ 	krb5_free_principal(kdc_realm.realm_context, tgs);
+ 	krb5_free_principal(kdc_realm.realm_context, cl);
+ 	krb5_free_principal(kdc_realm.realm_context, sv);
+ 	krb5_free_context(kdc_realm.realm_context);
+ 
+ 	exit(0);
      }
  
! void krb5_klog_syslog() {}
Index: kdc/securid.c
diff -c /dev/null krb5/kdc/securid.c:1.2
*** /dev/null	Thu Sep 23 15:41:14 1999
--- krb5/kdc/securid.c	Sat Aug  9 00:22:37 1997
***************
*** 0 ****
--- 1,562 ----
+ /*	S E C U R I D . C   - -
+  *
+  *		SecurID helper routines for SAM preauthentication.
+  *
+  *	Author: Kenneth D. Renard
+  *		Army Research Lab
+  *	Date:	9 Oct 96
+  *	Version: 1.0
+  */
+ 
+ #include "k5-int.h"
+ #include "kdc_util.h"
+ #include "extern.h"
+ #include <stdio.h>
+ 
+ #ifdef SLAVE
+ #include <unistd.h>
+ #endif
+ 
+ #include <sdi_athd.h>
+ #include <sdi_defs.h>
+ #include <sdconf.h>
+ #include <sdacmvls.h>
+ 
+ union config_record configure;
+ int need_to_creadcfg = 1;
+ int need_to_sd_init = 1;
+ static krb5_sam_challenge sam_challenge;
+ 
+ /*
+  * Structure to hold SecurID track data.  This keeps state data in place
+  * between requests.
+  */
+ 
+ struct securid_track_data {
+ 	char 	state;				/* What state we're in */
+ #define SECURID_STATE_NEW_PIN		1	/* Ask for a new pin */
+ #define SECURID_STATE_NEW_PIN_AGAIN	2	/* Ask for new pin again */
+ #define SECURID_STATE_NEXT_CODE		3	/* Ask for the next pin code */
+ 	char	passcode[LENPRNST+1];		/* Previous passcode for _AGAIN */
+ 	struct SD_CLIENT sd_info;		/* SecurID state information */
+ };
+ 
+ 
+ /*	krb5_error_code get_securid_key():
+  *		inputs:  context:  from KDC process
+  *			 client:   database entry of client executing
+  *				   SecurID SAM preauthentication
+  *		outputs: client_securid_key: pointer to krb5_keyblock
+  *				   which is key for the client's SecurID
+  *				   database entry.
+  *		returns: 0 on success
+  *			 KRB5 error codes otherwise
+  *
+  *		builds pricipal name with final instance of "SECURID" and
+  *		finds the database entry, decrypts the key out of the database
+  *		and passes the key back to the calling process
+  */
+ 
+ krb5_error_code get_securid_key(context, client, client_securid_key)
+     krb5_context context;
+     krb5_db_entry *client;
+     krb5_keyblock *client_securid_key;
+ {
+     krb5_db_entry client_securid_entry;
+     krb5_key_data *client_securid_key_data = 0;
+     krb5_error_code retval = 0;
+     krb5_principal newp;
+     krb5_int32 slot = 0;
+     int nprinc, more;
+ 
+     retval = krb5_copy_principal(context, client->princ, &newp);
+     if (retval) {
+ 	com_err("krb5kdc", retval,
+ 		"copying client name for SecurID preauth probe");
+ 	return(KRB5_PREAUTH_NO_KEY);
+     }
+     slot = krb5_princ_size(context, newp)++;
+     krb5_princ_name(kdc_context, newp) =
+ 		realloc(krb5_princ_name(kdc_context, newp),
+ 		krb5_princ_size(context, newp) * sizeof(krb5_data));
+     krb5_princ_component(context,newp,slot)->data = "SECURID";
+     krb5_princ_component(context,newp,slot)->length =
+ 		strlen("SECURID");
+     nprinc = 1;
+     retval = krb5_db_get_principal(context, newp,
+ 		&client_securid_entry, &nprinc, &more);
+ 
+     /* Memory Management */
+     krb5_princ_component(context,newp,slot)->length = 0;
+     krb5_princ_component(context,newp,slot)->data = 0;
+     krb5_princ_size(context, newp)--;
+     krb5_free_principal(context,newp);
+ 
+     if (retval || (nprinc != 1)) {
+ 	com_err("krb5kdc", retval,
+ 		"Cannot find client's SecurID entry in database");
+ 	return(KRB5_PREAUTH_NO_KEY);
+     }
+     retval = krb5_dbe_find_enctype(context, &client_securid_entry,
+ 		ENCTYPE_DES_CBC_RAW, KRB5_KDB_SALTTYPE_NORMAL, 0,
+ 		&client_securid_key_data);
+     if (retval) {
+ 	com_err("krb5kdc", retval,
+ 		"Cannot find enc-type for client's SecurID entry");
+ 	return(KRB5_PREAUTH_NO_KEY);
+     }
+     retval = krb5_dbekd_decrypt_key_data(context, &master_encblock,
+ 		client_securid_key_data, client_securid_key, NULL);
+     if (retval) {
+ 	com_err("krb5kdc", retval,
+ 		"Cannot decrypt key for client's SecurID entry");
+ 	return(KRB5_PREAUTH_NO_KEY);
+     }
+     return(0);
+ }
+ 
+ /*  krb5_error_code get_securid_edata()
+  *		inputs:  context from KDC
+  *			 static sd_dat structure
+  *		outputs: sam_challenge structure contents to be encoded
+  *			 and sent as a AS_ERR message by calling routine
+  *		returns: 0 on success
+  *			 KRB5 error codes otherwise
+  *
+  *		This routine is called when insufficient preauth data is
+  *		sent to the KDC.  The edata returned is either a generic
+  *		SecurID prompt or a "Next Card Code" prompt with associated
+  *		(encrypted) sam_track_id data.  If SecurID card is in NEXT
+  *		PRN mode, the static sam_challenge struct will be non-null,
+  *		having been filled in by the call to verify_securid_data().
+  */
+ 
+ krb5_error_code get_securid_edata(context, sc)
+     krb5_context context;
+     krb5_sam_challenge *sc;
+ {
+     krb5_error_code retval = 0;
+ 
+     if (sam_challenge.sam_type != 0) {
+ 	sc->magic = KV5M_SAM_CHALLENGE;
+ 	sc->sam_type = sam_challenge.sam_type;
+ 	sc->sam_flags = sam_challenge.sam_flags;
+ 	sc->sam_type_name.length = sam_challenge.sam_type_name.length;
+ 	sc->sam_type_name.data = sam_challenge.sam_type_name.data;
+ 	sc->sam_track_id.length = sam_challenge.sam_track_id.length;
+ 	sc->sam_track_id.data = sam_challenge.sam_track_id.data;
+ 	sc->sam_challenge_label.length =
+ 		 sam_challenge.sam_challenge_label.length;
+ 	sc->sam_challenge_label.data = sam_challenge.sam_challenge_label.data;
+ 	sc->sam_challenge.length = sam_challenge.sam_challenge.length;
+ 	sc->sam_challenge.data = sam_challenge.sam_challenge.data;
+ 	sc->sam_response_prompt.length =
+ 		sam_challenge.sam_response_prompt.length;
+ 	sc->sam_response_prompt.data = sam_challenge.sam_response_prompt.data;
+ 	sc->sam_pk_for_sad.length = sam_challenge.sam_pk_for_sad.length;
+ 	sc->sam_pk_for_sad.data = sam_challenge.sam_pk_for_sad.data;
+ 	sc->sam_nonce = sam_challenge.sam_nonce;
+ 	sc->sam_cksum.checksum_type = sam_challenge.sam_cksum.checksum_type;
+ 	sc->sam_cksum.length = sam_challenge.sam_cksum.length;
+ 	sc->sam_cksum.contents = sam_challenge.sam_cksum.contents;
+     } else {
+ 	sc->sam_type_name.length = 0;
+ 	sc->sam_challenge_label.length = 0;
+ 	sc->sam_challenge.length = 0;
+ 	sc->sam_response_prompt.data = "SecurID Passcode";
+ 	sc->sam_response_prompt.length = strlen("SecurID Passcode");
+ 	sc->sam_pk_for_sad.length = 0;
+ 	sc->sam_nonce = 0;
+ 	sc->sam_cksum.contents = (char *)0;
+ 	sc->sam_cksum.length = 0;
+ 	sc->sam_flags = KRB5_SAM_SEND_ENCRYPTED_SAD;
+ 	sc->sam_track_id.length = 0;
+ 	sc->sam_track_id.data = (char *)0;
+ 	sc->sam_track_id.magic = 0;
+     }
+     return (retval);
+ }
+ 
+ /*	krb5_error_code verify_securid_data()
+  *		inputs:   context: context from KDC
+  *			  client: db entry of client executing SecurID preauth
+  *			  sr: sam_response from client
+  *			  enc_tkt_reply: encrypted part of TGT reply for
+  *					 setting flags
+  *		outputs:  static sam_challenge structure
+  *		returns:  0 if passcode check was successful (even if
+  *				card is in NEXT_PRN mode)
+  *			  KRB5_PREAUTH_FAILED for invalid SecurID code
+  *			  other KRB5 error codes
+  *
+  *		Zeroes out static sam_challenge structure, decrypts and
+  *		decodes enc_sam_response_enc (using client's "password")
+  *		to get passcode data.  If sam_track_id.data is present,
+  *		decrypt this data with client's SecurID key and use it as
+  *		sd_dat structure to pass to sd_next().  If sd_next is
+  *		successful, set enc_tkt_reply flags and return.  If no
+  *		sam_track_id.data is present, initialize SecurID communications
+  *		and check passcode.  If passcode is correct, set enc_tkt_reply
+  *		flags and return success, if card in NEXT_PRN mode, set
+  *		PREAUTH flag, but not HW_AUTH flag, build sam_challnge in
+  *		static space, and set sam_track_id to encrypted sd_dat struct.
+  *		get_securid_edata will pick this data up and pass it back in
+  *		AS_ERR message.
+  */
+ 
+ krb5_error_code verify_securid_data(context, client, sr, enc_tkt_reply)
+     krb5_context context;
+     krb5_db_entry *client;
+     krb5_sam_response *sr;
+     krb5_enc_tkt_part *enc_tkt_reply;
+ {
+     struct SD_CLIENT sd_dat, *sd;
+     struct securid_track_data s_track, *securid_track;
+     krb5_error_code retval = -1;
+     krb5_principal newp;
+     krb5_keyblock client_key;
+     krb5_keyblock client_securid_key;
+     krb5_data scratch, *tmp_data;
+     krb5_enc_data tmp_enc_data;
+     krb5_enc_sam_response_enc *esre = 0;
+     char passcode[LENPRNST+1];
+     char *user = (char *)0;
+     char *cp;
+ 
+     memset(&sam_challenge, 0, sizeof(sam_challenge));
+ 
+     retval = krb5_dbekd_decrypt_key_data(kdc_context, &master_encblock,
+               client->key_data, &client_key, NULL);
+     if (retval) {
+       com_err("krb5kdc",retval,"Cannot get client's key from database");
+       goto securid_cleanup;
+     }
+ 
+     client_key.enctype = sr->sam_enc_nonce_or_ts.enctype;
+     if (!(sr->sam_enc_nonce_or_ts.ciphertext.data)) {
+       com_err("krb5kdc",KRB5KDC_ERR_PREAUTH_FAILED,
+               "SecurID Preauth data not found");
+       goto securid_cleanup;
+     }
+ 
+     retval = krb5_decrypt_data(context, &client_key, 0,
+               &sr->sam_enc_nonce_or_ts, &scratch);
+ 
+     /* Memory Management */
+     krb5_free_keyblock_contents(context, &client_key);
+ 
+     if (retval) {
+         com_err("krb5kdc",retval,"cannot decrypt SecurID preauth data");
+         goto securid_cleanup;
+     }
+     retval = decode_krb5_enc_sam_response_enc(&scratch, &esre);
+     if (retval) {
+         com_err("krb5kdc",retval,"cannot decode SecurID preauth data");
+         goto securid_cleanup;
+     }
+ 
+     /* Check nonce */
+     if (esre->sam_nonce != sr->sam_nonce) {
+         com_err("krb5kdc",KRB5KDC_ERR_PREAUTH_FAILED,
+               "decryption of SecurID preauth data failed (nonce)");
+         goto securid_cleanup;
+     }
+     /* Check passcode */
+     if (!(esre->sam_passcode.length) || !(esre->sam_passcode.data) ) {
+         com_err("krb5kdc", KRB5KDC_ERR_PREAUTH_REQUIRED,
+               "No SecurID passcode");
+         retval = KRB5KDC_ERR_PREAUTH_FAILED;
+         goto securid_cleanup;
+     }
+     if (need_to_creadcfg) {
+       creadcfg();
+       need_to_creadcfg = 0;
+     }
+     memset(&sd_dat, 0, sizeof(sd_dat));
+ 
+     if (retval = krb5_unparse_name(context, client->princ, &user)) {
+         com_err("krb5kdc", retval, "Cannot unparse name for SecurID check");
+         return(retval);
+     }
+     if (cp = strchr(user, '@'))
+         *cp = (char )0;
+ 
+     if (sr->sam_track_id.length) {
+ 	krb5_data scratch1;
+ 
+         /* This is second time around to this routine, either NEXT_PRN
+          * or NEW_PIN
+          */
+ 	retval = get_securid_key(context, client, &client_securid_key);
+ 	if (retval) goto securid_cleanup;
+ 
+ 	tmp_enc_data.ciphertext.data = sr->sam_track_id.data;
+ 	tmp_enc_data.ciphertext.length = sr->sam_track_id.length;
+ 	tmp_enc_data.enctype = client_securid_key.enctype;
+ 	tmp_enc_data.kvno = 0;
+ 
+ 	retval = krb5_decrypt_data(context, &client_securid_key, 0,
+ 		&tmp_enc_data, &scratch1);
+ 
+ 	/* Memory Management */
+ 	krb5_free_keyblock_contents(context, &client_securid_key);
+ 
+ 	if (retval) {
+ 	  com_err("krb5kdc", retval, "cannot decrypt track_id data");
+ 	  return(retval);
+ 	}
+ 
+ 	securid_track = (struct securid_track_data *) scratch1.data;
+ 	sd = &(securid_track->sd_info);
+ 
+ 	if (esre->sam_passcode.length > LENPRNST) /* Avoid overrunning buffer */
+ 	  esre->sam_passcode.length = LENPRNST;
+ 	memcpy(&passcode, esre->sam_passcode.data, esre->sam_passcode.length);
+         passcode[esre->sam_passcode.length] = (char)0;
+ 
+ 	switch(securid_track->state) {
+ 	  case SECURID_STATE_NEW_PIN_AGAIN:
+ 		if (strcmp(passcode, securid_track->passcode) != 0) {
+ 		  retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ 		  com_err("krb5kdc", retval, "PIN codes did not match");
+ 		  break;
+ 		}
+ 		retval = sd_pin(passcode, (char)0, sd);
+ 		if (retval == ACM_NEW_PIN_ACCEPTED) {
+ 		  com_err("krb5kdc",KRB5KDC_ERR_NONE, "New PIN Accepted");
+ 		  retval = 0;
+ 		} else
+ 		  com_err("krb5kdc",KRB5KDC_ERR_PREAUTH_FAILED,
+ 			  "New PIN Rejected");
+ 		break;
+ 	  case SECURID_STATE_NEXT_CODE:
+ 		retval = sd_next(passcode, sd);
+ 		if (retval == ACM_OK) {
+ 		  com_err("krb5kdc",KRB5KDC_ERR_NONE,"Next Code Accepted");
+ 		  retval = 0;
+ 		} else
+ 			com_err("krb5kdc",KRB5KDC_ERR_PREAUTH_FAILED,
+ 				"Next Code Rejected");
+ 		break;
+ 	  case SECURID_STATE_NEW_PIN:
+ 		retval = get_securid_key(context, client, &client_securid_key);
+ 		if (retval) goto securid_cleanup;
+ 
+ 		securid_track->state = SECURID_STATE_NEW_PIN_AGAIN;
+ 		strcpy(securid_track->passcode, passcode);
+ 		scratch.data = (char *)securid_track;
+                 scratch.length = sizeof(sd_dat);
+ 
+                 retval = krb5_encrypt_data(context, &client_securid_key, 0,
+                         &scratch, &tmp_enc_data);
+ 
+ 		/* Memory Management */
+                 krb5_free_keyblock_contents(context, &client_securid_key);
+ 
+ 		if (retval) {
+                   com_err("krb5kdc",retval,"Cannot encrypt NEW PIN data");
+                   goto securid_cleanup;
+                 }
+ 
+ 		sam_challenge.sam_type = sr->sam_type;
+                 sam_challenge.sam_type_name.data = "SecurID";
+                 sam_challenge.sam_type_name.length = strlen("SecurID");
+                 sam_challenge.sam_flags = sr->sam_flags;
+                 sam_challenge.sam_nonce = sr->sam_nonce;
+                 sam_challenge.sam_track_id.length =
+                         tmp_enc_data.ciphertext.length;
+                 sam_challenge.sam_track_id.data = tmp_enc_data.ciphertext.data;
+                 sam_challenge.sam_challenge_label.data = "Enter New PIN again";
+ 		sam_challenge.sam_challenge_label.length =
+ 			strlen("Enter New PIN again");
+ 		sam_challenge.sam_response_prompt.data = "New PIN";
+ 		sam_challenge.sam_response_prompt.length =
+ 			strlen("New PIN");
+ 		sam_challenge.sam_challenge.length = 0;
+                 sam_challenge.sam_cksum.contents = "1";
+                 sam_challenge.sam_cksum.length = 1;
+ 		/* Do Checksum */
+                 if (retval) goto securid_cleanup;
+ 
+                 retval = 0;
+ 		goto nosetflag;
+                 break;
+ 	  default:
+ 		com_err("krb5kdc",KRB5KDC_ERR_PREAUTH_FAILED,
+ 			"Can't figure out what to do with sam_track_id! (%d)",
+ 			securid_track->state);
+ 		retval = KRB5KDC_ERR_PREAUTH_FAILED;
+ 	}
+ 	if (retval) {
+ 	  krb5_xfree(scratch1.data);
+ 	  return(KRB5KDC_ERR_PREAUTH_FAILED);
+ 	}
+ 	setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH);
+         setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH);
+ nosetflag:
+ 	krb5_xfree(scratch1.data);
+         retval = 0;
+ 	return(retval);
+     } else {
+         /* Treat this as a first attempt at SecurID checking */
+ 	if (esre->sam_passcode.length > LENPRNST) /* Avoid overrunning buffer */
+ 	  esre->sam_passcode.length = LENPRNST;
+         memcpy(&passcode, esre->sam_passcode.data, esre->sam_passcode.length);
+         passcode[esre->sam_passcode.length] = (char)0;
+ 	if (need_to_sd_init) {
+ 	  need_to_sd_init = 0;
+           if (sd_init(&sd_dat)) {
+             retval = KRB5KDC_ERR_PREAUTH_FAILED;
+             com_err("krb5kdc", retval,
+ 			"Cannot initialize SecurID communications");
+             goto securid_cleanup;
+           }
+ 	}
+         retval = sd_check(passcode, user, &sd_dat);
+         switch(retval) {
+           case ACM_OK:
+                 setflag(enc_tkt_reply->flags, TKT_FLG_HW_AUTH);
+                 setflag(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH);
+                 retval = 0;
+                 break;
+           case ACM_ACCESS_DENIED:
+ #ifdef SLAVE
+ 		(void) sleep( (unsigned int)2);
+ #endif
+                 retval = KRB5_PREAUTH_FAILED;
+ 		com_err("krb5kdc", retval,
+ 			"ACE Server returned Access Denied");
+                 break;
+           case ACM_NEXT_CODE_REQUIRED:
+                 /* Build track_id, encrypt in user/SECURID@REALM,
+                  *  set challange labels, run checksum, and send as
+                  * KRB_ERROR to user
+                  */
+                 retval = get_securid_key(context, client, &client_securid_key);
+ 		if (retval) goto securid_cleanup;
+ 
+ 		/* 
+ 		 * Our track_id now has the state built into it, so
+ 		 * let's use that.
+ 		 */
+ 
+ 		s_track.state = SECURID_STATE_NEXT_CODE;
+ 		memcpy(&s_track.sd_info, &sd_dat, sizeof(sd_dat));
+ 
+                 scratch.data = (char *)&s_track;
+                 scratch.length = sizeof(s_track);
+ 
+                 retval = krb5_encrypt_data(context, &client_securid_key, 0,
+                         &scratch, &tmp_enc_data);
+ 
+ 		/* Memory Management */
+ 		krb5_free_keyblock_contents(context, &client_securid_key);
+ 
+                 if (retval) {
+                   com_err("krb5kdc",retval,"Cannot encrypt NEXT PRN data");
+                   goto securid_cleanup;
+                 }
+                 /* Do we really want to copy these or regenerate them ?? */
+                 sam_challenge.sam_type = sr->sam_type;
+ 		sam_challenge.sam_type_name.data = "SecurID";
+ 		sam_challenge.sam_type_name.length = strlen("SecurID");
+                 sam_challenge.sam_flags = sr->sam_flags;
+                 sam_challenge.sam_nonce = sr->sam_nonce;
+                 sam_challenge.sam_track_id.length =
+                         tmp_enc_data.ciphertext.length;
+                 sam_challenge.sam_track_id.data = tmp_enc_data.ciphertext.data;
+                 sam_challenge.sam_challenge_label.data = "Enter Next Cardcode";
+                 sam_challenge.sam_challenge_label.length =
+                         strlen("Enter Next Cardcode");
+                 sam_challenge.sam_response_prompt.data = "Next Cardcode";
+                 sam_challenge.sam_response_prompt.length =
+                         strlen("Next Cardcode");
+                 sam_challenge.sam_challenge.length = 0;
+                 sam_challenge.sam_cksum.contents = "1";
+                 sam_challenge.sam_cksum.length = 1;
+                 /* sam_challenge.sam_cksum.contents = (krb5_octet *)
+                  *   malloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5_DES));
+                  * if (sam_challenge.sam_cksum.contents == NULL) return(ENOMEM);
+                  * retval = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5_DES,
+                  *      sam_challenge.sam_challenge.data,
+                  *      sam_challenge.sam_challenge.length,
+                  *      client_key->contents, client_key->length,
+                  *      &sam_challenge.sam_cksum);
+                  */
+                 if (retval) {
+                         free(sam_challenge.sam_cksum.contents);
+                         return(retval);
+                 }
+                 if (retval) goto securid_cleanup;
+ 
+                 retval = 0;
+                 break;
+           case ACM_NEW_PIN_REQUIRED:
+                 /* Build track_id, encrypt in user/SECURID@REALM,
+                  *  set challange labels, run checksum, and send as
+                  * KRB_ERROR to user
+                  */
+ 		if (sd_dat.user_selectable == CANNOT_CHOOSE_PIN)
+ 		  return(KRB5KDC_ERR_PREAUTH_FAILED);
+ 
+ 		retval = get_securid_key(context, client, &client_securid_key);
+ 		if (retval) goto securid_cleanup;
+ 
+ 		s_track.state = SECURID_STATE_NEW_PIN;
+ 		memcpy(&s_track.sd_info, &sd_dat, sizeof(sd_dat));
+ 
+                 scratch.data = (char *)&s_track;
+                 scratch.length = sizeof(s_track);
+ 
+                 retval = krb5_encrypt_data(context, &client_securid_key, 0,
+                         &scratch, &tmp_enc_data);
+ 
+ 		/* Memory Management */
+                 krb5_free_keyblock_contents(context, &client_securid_key);
+ 
+ 		if (retval) {
+                   com_err("krb5kdc",retval,"Cannot encrypt NEW PIN data");
+                   goto securid_cleanup;
+                 }
+ 
+ 		sam_challenge.sam_type = sr->sam_type;
+                 sam_challenge.sam_type_name.data = "SecurID";
+                 sam_challenge.sam_type_name.length = strlen("SecurID");
+                 sam_challenge.sam_flags = sr->sam_flags;
+                 sam_challenge.sam_nonce = sr->sam_nonce;
+                 sam_challenge.sam_track_id.length =
+                         tmp_enc_data.ciphertext.length;
+                 sam_challenge.sam_track_id.data = tmp_enc_data.ciphertext.data;
+                 sam_challenge.sam_challenge_label.data = "Select New PIN";
+ 		sam_challenge.sam_challenge_label.length =
+ 			strlen("Select New PIN");
+ 		sam_challenge.sam_response_prompt.data = "New PIN";
+ 		sam_challenge.sam_response_prompt.length =
+ 			strlen("New PIN");
+ 		sam_challenge.sam_challenge.length = 0;
+                 sam_challenge.sam_cksum.contents = "1";
+                 sam_challenge.sam_cksum.length = 1;
+ 		/* Do Checksum */
+                 if (retval) goto securid_cleanup;
+ 
+                 retval = 0;
+                 break;
+ 	  default:
+ 		/* For any errors other than above, reset these and hopefully
+ 		 *   problems will clear up
+ 		 */
+ 		com_err("krb5kdc", KRB5_PREAUTH_FAILED,
+ 			"SecurID returned (%d)", retval);
+ 		need_to_creadcfg = 1;
+ 		need_to_sd_init = 1;
+         } /* switch(retval) */
+     }
+ securid_cleanup:
+     if (esre) {
+       if (esre->sam_passcode.data)
+ 	krb5_xfree(esre->sam_passcode.data);
+       krb5_xfree(esre);
+     }
+     return(retval);
+ }
+ 
Index: krb524/Makefile.in
diff -c krb5/krb524/Makefile.in:1.1.1.1 krb5/krb524/Makefile.in:1.2
*** krb5/krb524/Makefile.in:1.1.1.1	Mon Jun  2 17:55:40 1997
--- krb5/krb524/Makefile.in	Mon Sep 14 14:36:46 1998
***************
*** 36,47 ****
  OBJS	= conv_creds.o conv_princ.o conv_tkt.o cnv_tkt_skey.o \
  	encode.o misc.o globals.o sendmsg.o krb524_err.o
  
  GENS	= krb524_err.c krb524_err.h
  
  all:: $(GENS) libkrb524.a krb524d krb524test k524init
  
! libkrb524.a: $(OBJS)
! 	$(ARADD) $@ $(OBJS)
  	$(RANLIB) $@
  
  krb524test: libkrb524.a test.o $(DEPLIBS)
--- 36,49 ----
  OBJS	= conv_creds.o conv_princ.o conv_tkt.o cnv_tkt_skey.o \
  	encode.o misc.o globals.o sendmsg.o krb524_err.o
  
+ EXTRA_OBJS=@EXTRA_OBJS@
+ 
  GENS	= krb524_err.c krb524_err.h
  
  all:: $(GENS) libkrb524.a krb524d krb524test k524init
  
! libkrb524.a: $(OBJS) $(EXTRA_OBJS)
! 	$(ARADD) $@ $(OBJS) $(EXTRA_OBJS)
  	$(RANLIB) $@
  
  krb524test: libkrb524.a test.o $(DEPLIBS)
Index: krb524/cnv_tkt_skey.c
diff -c krb5/krb524/cnv_tkt_skey.c:1.1.1.1 krb5/krb524/cnv_tkt_skey.c:1.2
*** krb5/krb524/cnv_tkt_skey.c:1.1.1.1	Mon Jun  2 17:55:40 1997
--- krb5/krb524/cnv_tkt_skey.c	Wed Aug 18 16:59:28 1999
***************
*** 67,72 ****
--- 67,73 ----
       krb5_enc_tkt_part *v5etkt;
       int ret, lifetime, deltatime;
       krb5_timestamp server_time;
+      unsigned long dummy_addr = 0;
  
       v5tkt->enc_part2 = NULL;
       if ((ret = krb5_decrypt_tkt_part(context, v5_skey, v5tkt))) {
***************
*** 136,142 ****
       /* XXX perhaps we should use the addr of the client host if */
       /* v5creds contains more than one addr.  Q: Does V4 support */
       /* non-INET addresses? */
!      if (!v5etkt->caddrs || !v5etkt->caddrs[0] ||
  	 v5etkt->caddrs[0]->addrtype != ADDRTYPE_INET) {
  	  if (krb524_debug)
  	       fprintf(stderr, "Invalid v5creds address information.\n");
--- 137,143 ----
       /* XXX perhaps we should use the addr of the client host if */
       /* v5creds contains more than one addr.  Q: Does V4 support */
       /* non-INET addresses? */
!      if (v5etkt->caddrs && v5etkt->caddrs[0] &&
  	 v5etkt->caddrs[0]->addrtype != ADDRTYPE_INET) {
  	  if (krb524_debug)
  	       fprintf(stderr, "Invalid v5creds address information.\n");
***************
*** 157,163 ****
  			     pname,
  			     pinst,
  			     prealm,
! 			     *((unsigned long *)v5etkt->caddrs[0]->contents),
  			     (char *) v5etkt->session->contents,
  			     lifetime,
  			     /* issue_data */
--- 158,166 ----
  			     pname,
  			     pinst,
  			     prealm,
! 			     v5etkt->caddrs && v5etkt->caddrs[0] ? 
! 			      *((unsigned long *)v5etkt->caddrs[0]->contents) :
! 			      dummy_addr,
  			     (char *) v5etkt->session->contents,
  			     lifetime,
  			     /* issue_data */
Index: krb524/configure.in
diff -c krb5/krb524/configure.in:1.1.1.1 krb5/krb524/configure.in:1.3
*** krb5/krb524/configure.in:1.1.1.1	Mon Jun  2 17:55:40 1997
--- krb5/krb524/configure.in	Mon Sep 14 14:36:47 1998
***************
*** 6,11 ****
--- 6,28 ----
  AC_PROG_INSTALL
  AC_PROG_AWK
  AC_TYPE_SIGNAL
+ dnl
+ dnl --with-afs-name-change enables code that supports the case where
+ dnl the name of the realm (cell) changed when going from AFS to Kerberos 5
+ dnl
+ AC_ARG_WITH([afs-name-change],
+ [  --with-afs-name-change	Support an AFS cell with a different name],
+ if test "$withval" = yes; then
+ 	AC_DEFINE(KRB524_DO_AFS_CONV)
+ fi)
+ dnl
+ AC_ARG_WITH([krb524-remapping],
+ [  --with-krb524-remapping	Support mapping foreign realm users to local realm users],
+ if test "$withval" = yes; then
+ 	AC_DEFINE(KRB524_DO_REMAPPING)
+ 	EXTRA_OBJS=remap.o
+ fi)
+ dnl
  USE_KADMSRV_LIBRARY
  USE_GSSRPC_LIBRARY
  USE_GSSAPI_LIBRARY
***************
*** 15,19 ****
--- 32,37 ----
  USE_KRB4_LIBRARY
  KRB5_LIBRARIES
  V5_USE_SHARED_LIB
+ AC_SUBST(EXTRA_OBJS)
  AC_CHECK_HEADERS(sys/select.h) dnl
  V5_AC_OUTPUT_MAKEFILE
Index: krb524/conv_creds.c
diff -c krb5/krb524/conv_creds.c:1.1.1.1 krb5/krb524/conv_creds.c:1.2
*** krb5/krb524/conv_creds.c:1.1.1.1	Mon Jun  2 17:55:40 1997
--- krb5/krb524/conv_creds.c	Wed Aug 18 16:59:29 1999
***************
*** 133,147 ****
       /* XXX perhaps we should use the addr of the client host if */
       /* v5creds contains more than one addr.  Q: Does V4 support */
       /* non-INET addresses? */
!      if (!v5creds->addresses || !v5creds->addresses[0] ||
! 	 v5creds->addresses[0]->addrtype != ADDRTYPE_INET ||
! 	 v5creds->addresses[0]->length != sizeof(addr)) {
  	  if (krb524_debug)
  	       fprintf(stderr, "Invalid v5creds address information.\n");
  	  return KRB524_BADADDR;
       } else
! 	  memcpy((char *) &addr, v5creds->addresses[0]->contents,
  		 sizeof(addr));
  
       return 0;
  }
--- 133,150 ----
       /* XXX perhaps we should use the addr of the client host if */
       /* v5creds contains more than one addr.  Q: Does V4 support */
       /* non-INET addresses? */
!      if (v5creds->addresses && v5creds->addresses[0] &&
! 	 (v5creds->addresses[0]->addrtype != ADDRTYPE_INET ||
! 	  v5creds->addresses[0]->length != sizeof(addr))) {
  	  if (krb524_debug)
  	       fprintf(stderr, "Invalid v5creds address information.\n");
  	  return KRB524_BADADDR;
       } else
! 	  if (v5creds->addresses && v5creds->addresses[0])
! 	      memcpy((char *) &addr, v5creds->addresses[0]->contents,
  		 sizeof(addr));
+ 	  else
+ 	      addr = 0;
  
       return 0;
  }
Index: krb524/conv_princ.c
diff -c krb5/krb524/conv_princ.c:1.1.1.1 krb5/krb524/conv_princ.c:1.3
*** krb5/krb524/conv_princ.c:1.1.1.1	Mon Jun  2 17:55:40 1997
--- krb5/krb524/conv_princ.c	Mon Sep 14 14:36:48 1998
***************
*** 28,33 ****
--- 28,37 ----
  #include <sys/signal.h>
  #include <netinet/in.h>
  
+ #ifdef KRB524_DO_AFS_CONV
+ #include <ctype.h>
+ #endif
+ 
  #include <krb.h>
  
  #include "krb524.h"
***************
*** 40,49 ****
  {
       char dummy[REALM_SZ];
       int ret;
       
       if ((ret = krb5_524_conv_principal(context, client, pname, pinst, 
  					prealm)))
  	  return ret;
       
!      return krb5_524_conv_principal(context, server, sname, sinst, dummy);
  }
--- 44,114 ----
  {
       char dummy[REALM_SZ];
       int ret;
+ 
+ #ifdef KRB524_DO_REMAPPING
+ #ifndef KRB524_AFS_SERVICE_NAME
+ #define KRB524_AFS_SERVICE_NAME		"afs"
+ #endif
+ 
+      krb5_principal new_client;
+ 
+      /*
+       * We ONLY do principal remapping for the AFS service.  Remap based
+       * on the V5 principal, since that's more digestable (to me, at least).
+       * And _ONLY_ remap foreign principals!
+       */
+ 
+      if (strncmp(KRB524_AFS_SERVICE_NAME,
+ 		  krb5_princ_name(context, server)[0].data,
+ 		  krb5_princ_name(context, server)[0].length) == 0 &&
+ 	 krb5_realm_compare(context, client, server) == FALSE &&
+ 	 remap_principal(context, client, &new_client) == 0) {
+ 
+ 	  if ((ret = krb5_524_conv_principal(context, new_client, pname,
+ 					     pinst, prealm))) {
+ 	       krb5_free_principal(context, new_client);
+ 	       return ret;
+ 	  }
+ 	  krb5_free_principal(context, new_client);
+      } else
+ 
+ #endif /* KRB524_DO_REMAPPING */
       
       if ((ret = krb5_524_conv_principal(context, client, pname, pinst, 
  					prealm)))
  	  return ret;
       
!      if ((ret = krb5_524_conv_principal(context, server, sname, sinst,
! 					dummy)))
! 	  return ret;
! 
! #ifdef KRB524_DO_AFS_CONV
! 
! #ifndef KRB524_AFS_SERVICE_NAME
! #define KRB524_AFS_SERVICE_NAME		"afs"
! #endif
! 
!     /*
!      * If this request is for an afs ticket (service == KRB524_AFS_CONV)
!      * and had a non-null instance (which is assumed to be
!      * the afs cell name), and the REALMs on the user and service
!      * match, then we want to change the user's realm to be the
!      * afs cell name.
!      */
! 
!     if ((strcmp(sname, KRB524_AFS_SERVICE_NAME) == 0) &&
! 	(sinst && sinst[0]) &&
! 	(strcmp(dummy, prealm) == 0)) {
! 	
! 	char *c;
! 
! 	strncpy(prealm, sinst, REALM_SZ);
! 	prealm[REALM_SZ - 1] = NULL;	/* Just to be sure... */
! 
! 	for (c = prealm; *c != NULL; c++)
! 	    *c = (char) toupper((int) *c);
!     }
! #endif /* KRB524_DO_AFS_CONV */
! 
!     return ret;
  }
Index: krb524/krb524.h
diff -c krb5/krb524/krb524.h:1.1.1.1 krb5/krb524/krb524.h:1.2
*** krb5/krb524/krb524.h:1.1.1.1	Mon Jun  2 17:55:41 1997
--- krb5/krb524/krb524.h	Mon Sep 14 14:36:48 1998
***************
*** 77,80 ****
--- 77,93 ----
  	KRB5_PROTOTYPE((const struct sockaddr * addr, const krb5_data * message,
  		   krb5_data * reply));
  
+ #ifdef KRB524_DO_REMAPPING
+ 
+ /* remap.c */
+ 
+ int init_remap
+ 	KRB5_PROTOTYPE((krb5_context context, char *file));
+ 
+ int remap_principal
+ 	KRB5_PROTOTYPE((krb5_context context, krb5_principal input,
+ 			krb5_principal *output));
+ 
+ #endif /* KRB524_DO_REMAPPING */
+ 
  #endif /* __KRB524_H__ */
Index: krb524/krb524d.c
diff -c krb5/krb524/krb524d.c:1.1.1.1 krb5/krb524/krb524d.c:1.4
*** krb5/krb524/krb524d.c:1.1.1.1	Mon Jun  2 17:55:41 1997
--- krb5/krb524/krb524d.c	Mon Sep 14 14:36:49 1998
***************
*** 40,46 ****
  #include <krb.h>
  #include "krb524.h"
  
- #define TIMEOUT 60
  #define TKT_BUFSIZ 2048
  #define MSGSIZE 8192
  
--- 40,45 ----
***************
*** 50,55 ****
--- 49,58 ----
  void *handle;
  
  int use_keytab, use_master;
+ #ifdef KRB524_DO_REMAPPING
+ int use_remap_file = 0;
+ char *remap_file = NULL;
+ #endif /* KRB524_DO_REMAPPING */
  char *keytab = NULL;
  krb5_keytab kt;
  
***************
*** 59,65 ****
--- 62,72 ----
  void usage(context)
       krb5_context context;
  {
+ #ifdef KRB524_DO_REMAPPING
+      fprintf(stderr, "Usage: %s [-m[aster]] [-k[eytab]] [-f map_config_file]\n", whoami);
+ #else /* KRB524_DO_REMAPPING */
       fprintf(stderr, "Usage: %s [-m[aster]] [-k[eytab]]\n", whoami);
+ #endif /* KRB524_DO_REMAPPING */
       cleanup_and_exit(1, context);
  }
  
***************
*** 88,97 ****
       struct servent *serv;
       struct sockaddr_in saddr;
       struct timeval timeout;
!      int ret, s;
!      fd_set rfds;
       krb5_context context;
       krb5_error_code retval;
  
       retval = krb5_init_context(&context);
       if (retval) {
--- 95,107 ----
       struct servent *serv;
       struct sockaddr_in saddr;
       struct timeval timeout;
!      int ret, s, i, numfds, maxfd;
!      fd_set rfds, select_fds;
       krb5_context context;
       krb5_error_code retval;
+      int *addr_fds = NULL;
+      krb5_address **localaddrs;
+      const int on = 1;
  
       retval = krb5_init_context(&context);
       if (retval) {
***************
*** 108,113 ****
--- 118,132 ----
  	       use_keytab = 1;
  	  else if (strncmp(*argv, "-m", 2) == 0)
  	       use_master = 1;
+ #ifdef KRB524_DO_REMAPPING
+ 	  else if (strncmp(*argv, "-f", 2) == 0) {
+ 	       use_remap_file = 1;
+ 	       if (!argc)
+ 		   usage(context);
+ 	       argv++; argc--;
+ 	       remap_file = *argv;
+ 	  }
+ #endif /* KRB524_DO_REMAPPING */
  	  else
  	       break;
  	  argv++; argc--;
***************
*** 128,133 ****
--- 147,163 ----
  	  /* someday maybe there will be some config param options */
  	  init_master(context, NULL);
  
+ #ifdef KRB524_DO_REMAPPING
+      if (use_remap_file)
+ 	  init_remap(context, remap_file);
+ #endif /* KRB524_DO_REMAPPING */
+ 
+      /*
+       * We need to bind to all of interface addresses, in addition to
+       * wildcard address, so we can reply to messages using the correct
+       * source address
+       */
+ 
       memset((char *) &saddr, 0, sizeof(struct sockaddr_in));
       saddr.sin_family = AF_INET;
       saddr.sin_addr.s_addr = INADDR_ANY;
***************
*** 142,181 ****
  	  com_err(whoami, errno, "creating main socket");
  	  cleanup_and_exit(1, context);
       }
       if ((ret = bind(s, (struct sockaddr *) &saddr,
  		     sizeof(struct sockaddr_in))) < 0) {
  	  com_err(whoami, errno, "binding main socket");
  	  cleanup_and_exit(1, context);
       }
!      
       while (1) {
! 	  FD_ZERO(&rfds);
! 	  FD_SET(s, &rfds);
! 	  timeout.tv_sec = TIMEOUT;
! 	  timeout.tv_usec = 0;
  
! 	  ret = select(s+1, &rfds, NULL, NULL, &timeout);
  	  if (signalled)
  	       cleanup_and_exit(0, context);
! 	  else if (ret == 0) {
! 	       if (use_master) {
! 		    ret = kadm5_flush(handle);
! 		    if (ret && ret != KRB5_KDB_DBNOTINITED) {
! 			 com_err(whoami, ret, "closing kerberos database");
! 			 cleanup_and_exit(1, context);
! 		    }
! 	       }
! 	  } else if (ret < 0 && errno != EINTR) {
  	       com_err(whoami, errno, "in select");
  	       cleanup_and_exit(1, context);
! 	  } else if (FD_ISSET(s, &rfds)) {
! 	       if (debug)
! 		    printf("received packet\n");
! 	       if ((ret = do_connection(s, context))) {
! 		    com_err(whoami, ret, "handling packet");
  	       }
! 	  } else
! 	       com_err(whoami, 0, "impossible situation occurred!");
       }
  
       cleanup_and_exit(0, context);
--- 172,262 ----
  	  com_err(whoami, errno, "creating main socket");
  	  cleanup_and_exit(1, context);
       }
+ 
+      /*
+       * Set SO_REUSEADDR so that we can bind to the non-wildcard addresses
+       * later
+       */
+ 
+      if ((ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
+ 			   sizeof(on))) < 0) {
+ 	  com_err(whoami, errno, "setting SO_REUSEADDR on main socket");
+      }
+ 
       if ((ret = bind(s, (struct sockaddr *) &saddr,
  		     sizeof(struct sockaddr_in))) < 0) {
  	  com_err(whoami, errno, "binding main socket");
  	  cleanup_and_exit(1, context);
       }
! 
!      numfds = 1;
!      addr_fds = (int *) malloc(sizeof(int));
!      addr_fds[0] = s;
!      maxfd = s + 1;
!      FD_ZERO(&select_fds);
!      FD_SET(s, &select_fds);
! 
!      /*
!       * Now lets go through and bind a socket to each interface
!       */
! 
!      if ((ret = krb5_os_localaddr(context, &localaddrs)) != 0) {
! 	  com_err(whoami, ret, "getting local addresses");
! 	  cleanup_and_exit(1, context);
!      }
! 
!      for (i = 0; localaddrs[i] != NULL; i++) {
! 	  if (localaddrs[i]->addrtype == ADDRTYPE_INET) {
! 	       memcpy((char *) &saddr.sin_addr, localaddrs[i]->contents,
! 		      localaddrs[i]->length);
! 	       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
! 		    com_err(whoami, errno, "creating interface socket");
! 		    cleanup_and_exit(1, context);
! 	       }
! 	       if ((ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
! 				     sizeof(on))) < 0) {
! 		    com_err(whoami, errno, "setting SO_REUSEADDR on interface socket");
! 	       }
! 	       if ((ret = bind(s, (struct sockaddr *) &saddr,
! 			       sizeof(struct sockaddr))) < 0) {
! 		    com_err(whoami, errno, "binding on interface socket");
! 		    cleanup_and_exit(1, context);
! 	       }
! 	       numfds++;
! 	       addr_fds = (int *) realloc(addr_fds, numfds * sizeof(int));
! 	       if (addr_fds == NULL) {
! 		    com_err(whoami, ENOMEM, "allocating descriptor memory");
! 		    cleanup_and_exit(1, context);
! 	       }
! 	       addr_fds[numfds - 1] = s;
! 	       FD_SET(s, &select_fds);
! 	       if (s + 1 > maxfd)
! 		    maxfd = s + 1;
! 	  }
!      }
! 
!      krb5_free_addresses(context, localaddrs);
! 
       while (1) {
! 	  rfds = select_fds;
  
! 	  ret = select(maxfd, &rfds, NULL, NULL, NULL);
  	  if (signalled)
  	       cleanup_and_exit(0, context);
! 	  else if (ret < 0 && errno != EINTR) {
  	       com_err(whoami, errno, "in select");
  	       cleanup_and_exit(1, context);
! 	  } else if (ret > 0) {
! 	       for (i = 0; i < numfds; i++) {
! 		    if (FD_ISSET(addr_fds[i], &rfds)) {
! 			 if (debug)
! 			      printf("received packet\n");
! 			 if ((ret = do_connection(addr_fds[i], context))) {
! 			      com_err(whoami, ret, "handling packet");
! 			 }
! 		    }
  	       }
! 	  }
       }
  
       cleanup_and_exit(0, context);
Index: krb524/remap.c
diff -c /dev/null krb5/krb524/remap.c:1.1
*** /dev/null	Thu Sep 23 15:41:17 1999
--- krb5/krb524/remap.c	Mon Sep 14 14:36:49 1998
***************
*** 0 ****
--- 1,98 ----
+ /*
+  * Kerberos 5-2-4 remapping code
+  *
+  * This code implements a special principal "remapping" function.
+  * This motivation for this is as follows:
+  *
+  * When doing cross-realm authentication with AFS, the PTS id for
+  * foreign realm users ends up not matching the Unix userid.  This
+  * subtly breaks a number of things.
+  *
+  * This remapping changes a V4 principal from a principal in a foreign
+  * realm to one in a local realm, based on a set of mapping criteria.
+  * Note that we only do this when getting service tickets for AFS.
+  *
+  * The security implications here are nasty; be careful.
+  */
+ 
+ #include "krb5.h"
+ 
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <stdlib.h>
+ #include <ctype.h>
+ #include <sys/types.h>
+ #include <sys/time.h>
+ #include <sys/socket.h>
+ #include <sys/signal.h>
+ #include <netinet/in.h>
+ 
+ #include <krb.h>
+ #include "krb524.h"
+ #include "k5-int.h"
+ 
+ static int remap_initialized = 0;
+ static profile_t remap_profile;
+ 
+ /*
+  * Initialize the remapping library
+  */
+ 
+ int init_remap(context, file)
+ 	krb5_context context;
+ 	char *file;
+ {
+ 	krb5_error_code code;
+ 
+ 	if (remap_initialized)
+ 		return 0;
+ 
+ 	/*
+ 	 * Because I'm lazy, I decided to use the already-existing
+ 	 * Kerberos profile routines, even though it's perhaps not the
+ 	 * best file format.
+ 	 */
+ 
+ 	code = profile_init_path(file, &remap_profile);
+ 
+ 	if (code)
+ 		return code;
+ 	
+ 	remap_initialized = 1;
+ 	return 0;
+ }
+ 
+ int remap_principal(context, input, output)
+ 	krb5_context context;
+ 	krb5_principal input;
+ 	krb5_principal *output;
+ {
+ 	krb5_error_code code;
+ 	char *inprinc;
+ 	char *newname;
+ 
+ 	if (! remap_initialized)
+ 		return 1;
+ 	
+ 	/*
+ 	 * First off, check to see if we've can remap this principal
+ 	 * via the user-specific rules
+ 	 */
+ 
+ 	if ((code = krb5_unparse_name(context, input, &inprinc)))
+ 		return code;
+ 
+ 	code = profile_get_string(remap_profile, "users", inprinc, NULL,
+ 				  NULL, &newname);
+ 
+ 	if (code == 0 && newname != NULL) {
+ 		if ((code = krb5_parse_name(context, newname, output)) == 0) {
+ 			krb5_xfree(newname);
+ 			return 0;
+ 		}
+ 		krb5_xfree(newname);
+ 	}
+ 
+ 	return 1;
+ 
+ }
Index: lib/gssapi/generic/configure.in
diff -c krb5/lib/gssapi/generic/configure.in:1.1.1.1 krb5/lib/gssapi/generic/configure.in:1.2
*** krb5/lib/gssapi/generic/configure.in:1.1.1.1	Mon Jun  2 17:55:50 1997
--- krb5/lib/gssapi/generic/configure.in	Thu Sep 18 16:37:41 1997
***************
*** 4,10 ****
  AC_PROG_AWK
  V5_SHARED_LIB_OBJS
  SubdirLibraryRule([${OBJS}])
! AC_CHECK_HEADERS(stdlib.h sys/types.h limits.h)
  AC_SIZE_T
  AC_CHECK_SIZEOF(short)
  AC_CHECK_SIZEOF(int)
--- 4,10 ----
  AC_PROG_AWK
  V5_SHARED_LIB_OBJS
  SubdirLibraryRule([${OBJS}])
! AC_CHECK_HEADERS(stdlib.h sys/types.h limits.h memory.h)
  AC_SIZE_T
  AC_CHECK_SIZEOF(short)
  AC_CHECK_SIZEOF(int)
Index: lib/gssapi/generic/util_token.c
diff -c krb5/lib/gssapi/generic/util_token.c:1.1.1.1 krb5/lib/gssapi/generic/util_token.c:1.2
*** krb5/lib/gssapi/generic/util_token.c:1.1.1.1	Mon Jun  2 17:55:52 1997
--- krb5/lib/gssapi/generic/util_token.c	Thu Sep 18 16:37:44 1997
***************
*** 21,27 ****
--- 21,29 ----
   */
  
  #include "gssapiP_generic.h"
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  
  /*
   * $Id$
Index: lib/gssapi/krb5/accept_sec_context.c
diff -c krb5/lib/gssapi/krb5/accept_sec_context.c:1.1.1.2 krb5/lib/gssapi/krb5/accept_sec_context.c:1.3
*** krb5/lib/gssapi/krb5/accept_sec_context.c:1.1.1.2	Wed Feb 25 17:19:48 1998
--- krb5/lib/gssapi/krb5/accept_sec_context.c	Thu Feb 26 11:38:36 1998
***************
*** 21,27 ****
--- 21,29 ----
   */
  
  #include "gssapiP_krb5.h"
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  
  /*
   * $Id$
Index: lib/gssapi/krb5/configure.in
diff -c krb5/lib/gssapi/krb5/configure.in:1.1.1.1 krb5/lib/gssapi/krb5/configure.in:1.2
*** krb5/lib/gssapi/krb5/configure.in:1.1.1.1	Mon Jun  2 17:55:53 1997
--- krb5/lib/gssapi/krb5/configure.in	Thu Sep 18 16:37:52 1997
***************
*** 2,8 ****
  CONFIG_RULES
  AC_PROG_AWK
  AC_PROG_INSTALL
! AC_CHECK_HEADERS(stdlib.h)
  V5_SHARED_LIB_OBJS
  SubdirLibraryRule([${OBJS}])
  CopySrcHeader(gssapi_krb5.h,[$](BUILDTOP)/include/gssapi)
--- 2,8 ----
  CONFIG_RULES
  AC_PROG_AWK
  AC_PROG_INSTALL
! AC_CHECK_HEADERS(stdlib.h memory.h)
  V5_SHARED_LIB_OBJS
  SubdirLibraryRule([${OBJS}])
  CopySrcHeader(gssapi_krb5.h,[$](BUILDTOP)/include/gssapi)
Index: lib/gssapi/krb5/gssapiP_krb5.h
diff -c krb5/lib/gssapi/krb5/gssapiP_krb5.h:1.1.1.3 krb5/lib/gssapi/krb5/gssapiP_krb5.h:1.4
*** krb5/lib/gssapi/krb5/gssapiP_krb5.h:1.1.1.3	Wed May 12 13:23:02 1999
--- krb5/lib/gssapi/krb5/gssapiP_krb5.h	Wed May 12 14:55:57 1999
***************
*** 32,38 ****
--- 32,40 ----
  #else
  #include <krb5.h>
  #endif
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  
  /* work around sunos braindamage */
  #ifdef major
Index: lib/gssapi/krb5/init_sec_context.c
diff -c krb5/lib/gssapi/krb5/init_sec_context.c:1.1.1.3 krb5/lib/gssapi/krb5/init_sec_context.c:1.3
*** krb5/lib/gssapi/krb5/init_sec_context.c:1.1.1.3	Wed May 12 13:23:04 1999
--- krb5/lib/gssapi/krb5/init_sec_context.c	Wed May 12 14:55:57 1999
***************
*** 21,27 ****
--- 21,29 ----
   */
  
  #include "gssapiP_krb5.h"
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  #include <stdlib.h>
  
  /*
Index: lib/gssapi/krb5/k5unseal.c
diff -c krb5/lib/gssapi/krb5/k5unseal.c:1.1.1.1 krb5/lib/gssapi/krb5/k5unseal.c:1.2
*** krb5/lib/gssapi/krb5/k5unseal.c:1.1.1.1	Mon Jun  2 17:55:54 1997
--- krb5/lib/gssapi/krb5/k5unseal.c	Thu Sep 18 16:37:58 1997
***************
*** 21,27 ****
--- 21,29 ----
   */
  
  #include "gssapiP_krb5.h"
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  
  /*
   * $Id$
Index: lib/gssapi/krb5/util_cksum.c
diff -c krb5/lib/gssapi/krb5/util_cksum.c:1.1.1.1 krb5/lib/gssapi/krb5/util_cksum.c:1.2
*** krb5/lib/gssapi/krb5/util_cksum.c:1.1.1.1	Mon Jun  2 17:55:56 1997
--- krb5/lib/gssapi/krb5/util_cksum.c	Thu Sep 18 16:38:01 1997
***************
*** 25,31 ****
--- 25,33 ----
   */
  
  #include "gssapiP_krb5.h"
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  
  krb5_error_code
  kg_checksum_channel_bindings(context, cb, cksum, bigend)
Index: lib/gssapi/krb5/util_crypt.c
diff -c krb5/lib/gssapi/krb5/util_crypt.c:1.1.1.1 krb5/lib/gssapi/krb5/util_crypt.c:1.2
*** krb5/lib/gssapi/krb5/util_crypt.c:1.1.1.1	Mon Jun  2 17:55:56 1997
--- krb5/lib/gssapi/krb5/util_crypt.c	Thu Sep 18 16:38:02 1997
***************
*** 21,27 ****
--- 21,29 ----
   */
  
  #include "gssapiP_krb5.h"
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  
  /*
   * $Id$
Index: lib/gssapi/krb5/util_seed.c
diff -c krb5/lib/gssapi/krb5/util_seed.c:1.1.1.1 krb5/lib/gssapi/krb5/util_seed.c:1.2
*** krb5/lib/gssapi/krb5/util_seed.c:1.1.1.1	Mon Jun  2 17:55:56 1997
--- krb5/lib/gssapi/krb5/util_seed.c	Thu Sep 18 16:38:04 1997
***************
*** 21,27 ****
--- 21,29 ----
   */
  
  #include "gssapiP_krb5.h"
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  
  /*
   * $Id$
Index: lib/kadm/logger.c
diff -c krb5/lib/kadm/logger.c:1.1.1.1 krb5/lib/kadm/logger.c:1.2
*** krb5/lib/kadm/logger.c:1.1.1.1	Mon Jun  2 17:56:03 1997
--- krb5/lib/kadm/logger.c	Tue May  4 14:37:02 1999
***************
*** 156,162 ****
   */
  #define	DEVICE_OPEN(d, m)	fopen(d, m)
  #define	CONSOLE_OPEN(m)		fopen("/dev/console", m)
! #define	DEVICE_PRINT(f, m)	((fprintf(f, m) >= 0) ? 		\
  				 (fprintf(f, "\r\n"), fflush(f), 0) :	\
  				 -1)
  #define	DEVICE_CLOSE(d)		fclose(d)
--- 156,162 ----
   */
  #define	DEVICE_OPEN(d, m)	fopen(d, m)
  #define	CONSOLE_OPEN(m)		fopen("/dev/console", m)
! #define	DEVICE_PRINT(f, m)	((fprintf(f, "%s", m) >= 0) ? 		\
  				 (fprintf(f, "\r\n"), fflush(f), 0) :	\
  				 -1)
  #define	DEVICE_CLOSE(d)		fclose(d)
***************
*** 273,279 ****
  	    /*
  	     * Files/standard error.
  	     */
! 	    if (fprintf(log_control.log_entries[lindex].lfu_filep,
  			outbuf) < 0) {
  		/* Attempt to report error */
  		fprintf(stderr, log_file_err, whoami,
--- 273,279 ----
  	    /*
  	     * Files/standard error.
  	     */
! 	    if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s",
  			outbuf) < 0) {
  		/* Attempt to report error */
  		fprintf(stderr, log_file_err, whoami,
***************
*** 312,318 ****
  		    log_control.log_entries[lindex].lsu_severity;
  					       
  	    /* Log the message with our header trimmed off */
! 	    syslog(log_pri, syslogp);
  	    break;
  #endif /* HAVE_SYSLOG */
  	default:
--- 312,318 ----
  		    log_control.log_entries[lindex].lsu_severity;
  					       
  	    /* Log the message with our header trimmed off */
! 	    syslog(log_pri, "%s", syslogp);
  	    break;
  #endif /* HAVE_SYSLOG */
  	default:
***************
*** 874,880 ****
  	    /*
  	     * Files/standard error.
  	     */
! 	    if (fprintf(log_control.log_entries[lindex].lfu_filep, 
  			outbuf) < 0) {
  		/* Attempt to report error */
  		fprintf(stderr, log_file_err,
--- 874,880 ----
  	    /*
  	     * Files/standard error.
  	     */
! 	    if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s",
  			outbuf) < 0) {
  		/* Attempt to report error */
  		fprintf(stderr, log_file_err,
***************
*** 904,910 ****
  	     */
  					       
  	    /* Log the message with our header trimmed off */
! 	    syslog(priority, syslogp);
  	    break;
  #endif /* HAVE_SYSLOG */
  	default:
--- 904,910 ----
  	     */
  					       
  	    /* Log the message with our header trimmed off */
! 	    syslog(priority, "%s", syslogp);
  	    break;
  #endif /* HAVE_SYSLOG */
  	default:
Index: lib/kadm5/admin.h
diff -c krb5/lib/kadm5/admin.h:1.1.1.2 krb5/lib/kadm5/admin.h:1.4
*** krb5/lib/kadm5/admin.h:1.1.1.2	Mon Nov  3 16:35:09 1997
--- krb5/lib/kadm5/admin.h	Thu Apr 15 14:49:04 1999
***************
*** 94,99 ****
--- 94,101 ----
  #define KADM5_CONFIG_ADMIN_SERVER	0x010000
  #define KADM5_CONFIG_DICT_FILE		0x020000
  #define KADM5_CONFIG_MKEY_FROM_KBD	0x040000
+ #define KADM5_CONFIG_KPASSWD_PORT	0x080000
+ #define KADM5_CONFIG_ADMIN_ADDRS	0x100000
     
  /*
   * permission bits
***************
*** 187,194 ****
--- 189,199 ----
       char *		realm;
       char *		profile;
       int		kadmind_port;
+      int		kpasswd_port;
  
       char *		admin_server;
+      struct sockaddr *	admin_addrs;
+      int		nadmin_addrs;
  
       char *		dbname;
       char *		admin_dbname;
Index: lib/kadm5/alt_prof.c
diff -c krb5/lib/kadm5/alt_prof.c:1.1.1.1 krb5/lib/kadm5/alt_prof.c:1.3
*** krb5/lib/kadm5/alt_prof.c:1.1.1.1	Mon Jun  2 17:56:04 1997
--- krb5/lib/kadm5/alt_prof.c	Thu Apr 15 14:49:05 1999
***************
*** 352,357 ****
--- 352,366 ----
  	      params.mask |= KADM5_CONFIG_KADMIND_PORT;
  	      *p = '\0';
  	 }
+     } else {
+ 	 krb5_data cur_realm;
+ 
+ 	 cur_realm.data = params.realm;
+ 	 cur_realm.length = strlen(params.realm);
+ 	 if (!krb5_locate_server(context, &cur_realm, "_kadmin", "_tcp",
+ 				 (void **) &params.admin_addrs,
+ 				 &params.nadmin_addrs))
+ 	      params.mask |= KADM5_CONFIG_ADMIN_ADDRS;
      }
  
      /* Get the value for the database */
***************
*** 455,460 ****
--- 464,486 ----
  	 }
      }
      
+     /* Get the value for the kpasswd port */
+     if (! (params.mask & KADM5_CONFIG_KPASSWD_PORT)) {
+ 	 hierarchy[2] = "kpasswd_port";
+ 	 if (params_in->mask & KADM5_CONFIG_KPASSWD_PORT) {
+ 	      params.mask |= KADM5_CONFIG_KPASSWD_PORT;
+ 	      params.kpasswd_port = params_in->kpasswd_port;
+ 	 } else if (aprofile &&
+ 		    !krb5_aprof_get_int32(aprofile, hierarchy, TRUE,
+ 					  &ivalue)) { 
+ 	      params.kpasswd_port = ivalue;
+ 	      params.mask |= KADM5_CONFIG_KPASSWD_PORT;
+ 	 } else {
+ 	      params.kpasswd_port = DEFAULT_KPASSWD_PORT;
+ 	      params.mask |= KADM5_CONFIG_KPASSWD_PORT;
+ 	 }
+     }
+ 
      /* Get the value for the master key name */
  	 hierarchy[2] = "master_key_name";
      if (params_in->mask & KADM5_CONFIG_MKEY_NAME) {
Index: lib/kadm5/chpass_util.c
diff -c krb5/lib/kadm5/chpass_util.c:1.1.1.2 krb5/lib/kadm5/chpass_util.c:1.3
*** krb5/lib/kadm5/chpass_util.c:1.1.1.2	Mon Nov  3 16:35:13 1997
--- krb5/lib/kadm5/chpass_util.c	Mon Nov  3 17:14:27 1997
***************
*** 8,14 ****
--- 8,16 ----
  
  
  #include <stdio.h>
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  #include <time.h>
  
  #include <kadm5/admin.h>
Index: lib/kadm5/chpass_util_strings.et
diff -c krb5/lib/kadm5/chpass_util_strings.et:1.1.1.1 krb5/lib/kadm5/chpass_util_strings.et:1.2
*** krb5/lib/kadm5/chpass_util_strings.et:1.1.1.1	Mon Jun  2 17:56:05 1997
--- krb5/lib/kadm5/chpass_util_strings.et	Tue Jun  2 09:57:47 1998
***************
*** 17,24 ****
  
  error_code CHPASS_UTIL_PASSWORD_IN_DICTIONARY,
  "New password was found in a dictionary of possible passwords and\n\
! therefore may be easily guessed. Please choose another password.\n\
! See the ovpasswd man page for help in choosing a good password."
  
  error_code CHPASS_UTIL_PASSWORD_NOT_CHANGED, "Password not changed."
  
--- 17,23 ----
  
  error_code CHPASS_UTIL_PASSWORD_IN_DICTIONARY,
  "New password was found in a dictionary of possible passwords and\n\
! therefore may be easily guessed. Please choose another password."
  
  error_code CHPASS_UTIL_PASSWORD_NOT_CHANGED, "Password not changed."
  
Index: lib/kadm5/configure.in
diff -c krb5/lib/kadm5/configure.in:1.1.1.1 krb5/lib/kadm5/configure.in:1.2
*** krb5/lib/kadm5/configure.in:1.1.1.1	Mon Jun  2 17:56:05 1997
--- krb5/lib/kadm5/configure.in	Thu Sep 18 16:38:13 1997
***************
*** 8,14 ****
  AC_PROG_INSTALL
  AC_PROG_LEX
  AC_PROG_AWK
! AC_CHECK_HEADERS(syslog.h)
  AC_CHECK_FUNCS(openlog syslog closelog strftime vsprintf)
  V5_SHARED_LIB_OBJS
  
--- 8,14 ----
  AC_PROG_INSTALL
  AC_PROG_LEX
  AC_PROG_AWK
! AC_CHECK_HEADERS(syslog.h memory.h)
  AC_CHECK_FUNCS(openlog syslog closelog strftime vsprintf)
  V5_SHARED_LIB_OBJS
  
Index: lib/kadm5/logger.c
diff -c krb5/lib/kadm5/logger.c:1.1.1.1 krb5/lib/kadm5/logger.c:1.2
*** krb5/lib/kadm5/logger.c:1.1.1.1	Mon Jun  2 17:56:05 1997
--- krb5/lib/kadm5/logger.c	Tue May  4 14:37:10 1999
***************
*** 159,165 ****
   */
  #define	DEVICE_OPEN(d, m)	fopen(d, m)
  #define	CONSOLE_OPEN(m)		fopen("/dev/console", m)
! #define	DEVICE_PRINT(f, m)	((fprintf(f, m) >= 0) ? 		\
  				 (fprintf(f, "\r\n"), fflush(f), 0) :	\
  				 -1)
  #define	DEVICE_CLOSE(d)		fclose(d)
--- 159,165 ----
   */
  #define	DEVICE_OPEN(d, m)	fopen(d, m)
  #define	CONSOLE_OPEN(m)		fopen("/dev/console", m)
! #define	DEVICE_PRINT(f, m)	((fprintf(f, "%s", m) >= 0) ? 		\
  				 (fprintf(f, "\r\n"), fflush(f), 0) :	\
  				 -1)
  #define	DEVICE_CLOSE(d)		fclose(d)
***************
*** 276,282 ****
  	    /*
  	     * Files/standard error.
  	     */
! 	    if (fprintf(log_control.log_entries[lindex].lfu_filep,
  			outbuf) < 0) {
  		/* Attempt to report error */
  		fprintf(stderr, log_file_err, whoami,
--- 276,282 ----
  	    /*
  	     * Files/standard error.
  	     */
! 	    if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s",
  			outbuf) < 0) {
  		/* Attempt to report error */
  		fprintf(stderr, log_file_err, whoami,
***************
*** 315,321 ****
  		    log_control.log_entries[lindex].lsu_severity;
  					       
  	    /* Log the message with our header trimmed off */
! 	    syslog(log_pri, syslogp);
  	    break;
  #endif /* HAVE_SYSLOG */
  	default:
--- 315,321 ----
  		    log_control.log_entries[lindex].lsu_severity;
  					       
  	    /* Log the message with our header trimmed off */
! 	    syslog(log_pri, "%s", syslogp);
  	    break;
  #endif /* HAVE_SYSLOG */
  	default:
***************
*** 878,884 ****
  	    /*
  	     * Files/standard error.
  	     */
! 	    if (fprintf(log_control.log_entries[lindex].lfu_filep, 
  			outbuf) < 0) {
  		/* Attempt to report error */
  		fprintf(stderr, log_file_err,
--- 878,884 ----
  	    /*
  	     * Files/standard error.
  	     */
! 	    if (fprintf(log_control.log_entries[lindex].lfu_filep, "%s",
  			outbuf) < 0) {
  		/* Attempt to report error */
  		fprintf(stderr, log_file_err,
***************
*** 908,914 ****
  	     */
  					       
  	    /* Log the message with our header trimmed off */
! 	    syslog(priority, syslogp);
  	    break;
  #endif /* HAVE_SYSLOG */
  	default:
--- 908,914 ----
  	     */
  					       
  	    /* Log the message with our header trimmed off */
! 	    syslog(priority, "%s", syslogp);
  	    break;
  #endif /* HAVE_SYSLOG */
  	default:
Index: lib/kadm5/server_internal.h
diff -c krb5/lib/kadm5/server_internal.h:1.1.1.2 krb5/lib/kadm5/server_internal.h:1.3
*** krb5/lib/kadm5/server_internal.h:1.1.1.2	Mon Nov  3 16:35:10 1997
--- krb5/lib/kadm5/server_internal.h	Mon Nov  3 17:14:29 1997
***************
*** 13,19 ****
--- 13,21 ----
  #ifndef __KADM5_SERVER_INTERNAL_H__
  #define __KADM5_SERVER_INTERNAL_H__
  
+ #ifdef HAVE_MEMORY_H
  #include    <memory.h>
+ #endif
  #include    <stdlib.h>
  #include    "k5-int.h"
  #include    <krb5/kdb.h>
Index: lib/kadm5/clnt/client_init.c
diff -c krb5/lib/kadm5/clnt/client_init.c:1.1.1.2 krb5/lib/kadm5/clnt/client_init.c:1.4
*** krb5/lib/kadm5/clnt/client_init.c:1.1.1.2	Mon Nov  3 16:35:23 1997
--- krb5/lib/kadm5/clnt/client_init.c	Thu Apr 15 14:49:30 1999
***************
*** 10,16 ****
--- 10,18 ----
  
  #include <stdio.h>
  #include <netdb.h>
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  #include <string.h>
  #include <com_err.h>
  #include <sys/types.h>
***************
*** 117,127 ****
  				   krb5_ui_4 api_version,
  				   void **server_handle)
  {
!      struct sockaddr_in addr;
       struct hostent *hp;
       struct servent *srv;
       int fd;
       int i;
  
       char full_service_name[BUFSIZ], host[MAXHOSTNAMELEN], *ccname_orig;
       char *realm;
--- 119,130 ----
  				   krb5_ui_4 api_version,
  				   void **server_handle)
  {
!      struct sockaddr_in addr, *addr_p;
       struct hostent *hp;
       struct servent *srv;
       int fd;
       int i;
+      int num;
  
       char full_service_name[BUFSIZ], host[MAXHOSTNAMELEN], *ccname_orig;
       char *realm;
***************
*** 231,241 ****
  	  return(code);
       }
  
! #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
! 			 KADM5_CONFIG_ADMIN_SERVER | \
! 			 KADM5_CONFIG_KADMIND_PORT) 
! 
!      if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
  	  krb5_free_context(handle->context);
  	  free(handle);
  	  return KADM5_MISSING_CONF_PARAMS;
--- 234,247 ----
  	  return(code);
       }
  
! #define REQUIRED_PARAMS1 (KADM5_CONFIG_REALM)
! #define REQUIRED_PARAMS2 (KADM5_CONFIG_ADMIN_SERVER | \
! 			  KADM5_CONFIG_KADMIND_PORT) 
! #define REQUIRED_PARAMS3 (KADM5_CONFIG_ADMIN_ADDRS)
! 
!      if (!((handle->params.mask & REQUIRED_PARAMS1) == REQUIRED_PARAMS1 &&
! 	   ((handle->params.mask & REQUIRED_PARAMS2) == REQUIRED_PARAMS2 ||
! 	    (handle->params.mask & REQUIRED_PARAMS3) == REQUIRED_PARAMS3))) {
  	  krb5_free_context(handle->context);
  	  free(handle);
  	  return KADM5_MISSING_CONF_PARAMS;
***************
*** 373,393 ****
        * We have ticket; open the RPC connection.
        */
  
!      hp = gethostbyname(handle->params.admin_server);
!      if (hp == (struct hostent *) NULL) {
  	  code = KADM5_BAD_SERVER_NAME;
  	  goto cleanup;
       }
- 
-      memset(&addr, 0, sizeof(addr));
-      addr.sin_family = hp->h_addrtype;
-      (void) memcpy((char *) &addr.sin_addr, (char *) hp->h_addr,
- 		   sizeof(addr.sin_addr));
-      addr.sin_port = htons((u_short) handle->params.kadmind_port);
-      
-      fd = RPC_ANYSOCK;
       
!      handle->clnt = clnttcp_create(&addr, KADM, KADMVERS, &fd, 0, 0);
       if (handle->clnt == NULL) {
  	  code = KADM5_RPC_ERROR;
  	  goto error;
--- 379,415 ----
        * We have ticket; open the RPC connection.
        */
  
!      if (handle->params.mask & KADM5_CONFIG_ADMIN_SERVER) {
! 	  hp = gethostbyname(handle->params.admin_server);
! 	  if (hp == (struct hostent *) NULL) {
! 	       code = KADM5_BAD_SERVER_NAME;
! 	       goto cleanup;
! 	  }
! 
! 	  memset(&addr, 0, sizeof(addr));
! 	  addr.sin_family = hp->h_addrtype;
! 	  (void) memcpy((char *) &addr.sin_addr, (char *) hp->h_addr,
! 			 sizeof(addr.sin_addr));
! 	  addr.sin_port = htons((u_short) handle->params.kadmind_port);
! 
! 	  addr_p = &addr;
! 	  num = 1;
!      } else if (handle->params.mask & KADM5_CONFIG_ADMIN_ADDRS) {
! 	  addr_p = (struct sockaddr_in *) handle->params.admin_addrs;
! 	  num = handle->params.nadmin_addrs;
!      } else {
! 	  /* Shouldn't happen, but just in case ... */
  	  code = KADM5_BAD_SERVER_NAME;
  	  goto cleanup;
       }
       
!      for (i = 0; i < num; i++) {
! 	  fd = RPC_ANYSOCK;
! 	  handle->clnt = clnttcp_create(&addr_p[i], KADM, KADMVERS, &fd, 0, 0);
! 	  if (handle->clnt != NULL)
! 	       break;
!      }
! 
       if (handle->clnt == NULL) {
  	  code = KADM5_RPC_ERROR;
  	  goto error;
***************
*** 498,503 ****
--- 520,527 ----
  	  AUTH_DESTROY(handle->clnt->cl_auth);
       if(handle->clnt)
  	  clnt_destroy(handle->clnt);
+      if(handle->params.admin_addrs)
+ 	  free(handle->params.admin_addrs);
  
  cleanup:
       krb5_free_cred_contents(handle->context, &creds);
***************
*** 531,536 ****
--- 555,562 ----
  	  AUTH_DESTROY(handle->clnt->cl_auth);
       if (handle->clnt)
  	  clnt_destroy(handle->clnt);
+      if (handle->params.admin_addrs)
+           free(handle->params.admin_addrs);
  
       handle->magic_number = 0;
       free(handle);
Index: lib/kadm5/clnt/client_principal.c
diff -c krb5/lib/kadm5/clnt/client_principal.c:1.1.1.2 krb5/lib/kadm5/clnt/client_principal.c:1.3
*** krb5/lib/kadm5/clnt/client_principal.c:1.1.1.2	Mon Nov  3 16:35:25 1997
--- krb5/lib/kadm5/clnt/client_principal.c	Mon Nov  3 17:14:33 1997
***************
*** 11,17 ****
--- 11,19 ----
  #include    <rpc/rpc.h>
  #include    <kadm5/admin.h>
  #include    <kadm5/kadm_rpc.h>
+ #ifdef HAVE_MEMORY_H
  #include    <memory.h>
+ #endif
  #include    "client_internal.h"
  
  kadm5_ret_t
Index: lib/kadm5/clnt/client_rpc.c
diff -c krb5/lib/kadm5/clnt/client_rpc.c:1.1.1.1 krb5/lib/kadm5/clnt/client_rpc.c:1.2
*** krb5/lib/kadm5/clnt/client_rpc.c:1.1.1.1	Mon Jun  2 17:56:10 1997
--- krb5/lib/kadm5/clnt/client_rpc.c	Thu Sep 18 16:38:23 1997
***************
*** 2,8 ****
--- 2,10 ----
  #include <kadm5/kadm_rpc.h>
  #include <krb5.h>
  #include <kadm5/admin.h>
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  
  /* Default timeout can be changed using clnt_control() */
  static struct timeval TIMEOUT = { 25, 0 };
Index: lib/kadm5/clnt/configure.in
diff -c krb5/lib/kadm5/clnt/configure.in:1.1.1.1 krb5/lib/kadm5/clnt/configure.in:1.2
*** krb5/lib/kadm5/clnt/configure.in:1.1.1.1	Mon Jun  2 17:56:10 1997
--- krb5/lib/kadm5/clnt/configure.in	Thu Sep 18 16:38:25 1997
***************
*** 5,10 ****
--- 5,11 ----
  AC_PROG_RANLIB
  AC_PROG_INSTALL
  V5_SHARED_LIB_OBJS
+ AC_CHECK_HEADERS(memory.h)
  V5_MAKE_SHARED_LIB(libkadm5clnt, 1.0, ../.., ./kadm5/clnt)
  
  GSSRPC_SH_VERS=$krb5_cv_shlib_version_libgssrpc
Index: lib/kadm5/srv/Makefile.in
diff -c krb5/lib/kadm5/srv/Makefile.in:1.1.1.2 krb5/lib/kadm5/srv/Makefile.in:1.3
*** krb5/lib/kadm5/srv/Makefile.in:1.1.1.2	Wed May 12 13:23:26 1999
--- krb5/lib/kadm5/srv/Makefile.in	Wed May 12 14:55:57 1999
***************
*** 64,71 ****
  all-mac:: $(OBJS)
  all-windows:: $(OBJS)
  
! LIBDONE=../DONE DONE
! LIB_SUBDIRS=.. .
  
  shared:
  	mkdir shared
--- 64,71 ----
  all-mac:: $(OBJS)
  all-windows:: $(OBJS)
  
! LIBDONE=../DONE DONE @CRACKLIB_DONE@
! LIB_SUBDIRS=.. . @CRACKLIB_SUBDIR@
  
  shared:
  	mkdir shared
Index: lib/kadm5/srv/adb_free.c
diff -c krb5/lib/kadm5/srv/adb_free.c:1.1.1.2 krb5/lib/kadm5/srv/adb_free.c:1.3
*** krb5/lib/kadm5/srv/adb_free.c:1.1.1.2	Mon Nov  3 16:35:31 1997
--- krb5/lib/kadm5/srv/adb_free.c	Mon Nov  3 17:14:38 1997
***************
*** 4,9 ****
--- 4,18 ----
   * $Header$
   * 
   * $Log$
+  * Revision 1.3  1997/11/03 22:14:38  kenh
+  * Fix up conflicts from Release 1.0.2 import.
+  *
+  * Revision 1.2  1997/09/18 20:38:30  vwelch
+  * ConvexOS Port.
+  *
+  * Revision 1.1.1.1  1997/06/02 21:56:07  kenh
+  * Initial import of R1.0 from MIT.
+  *
   * Revision 1.1.1.2  1997/11/03 21:35:31  kenh
   * Import of Kerberos 5, Release 1.0.2
   *
***************
*** 55,61 ****
--- 64,72 ----
  #endif
  
  #include	"adb.h"
+ #ifdef HAVE_MEMORY_H
  #include	<memory.h>
+ #endif
  #include	<stdlib.h>
  
  void
Index: lib/kadm5/srv/adb_xdr.c
diff -c krb5/lib/kadm5/srv/adb_xdr.c:1.1.1.2 krb5/lib/kadm5/srv/adb_xdr.c:1.3
*** krb5/lib/kadm5/srv/adb_xdr.c:1.1.1.2	Mon Nov  3 16:35:33 1997
--- krb5/lib/kadm5/srv/adb_xdr.c	Mon Nov  3 17:14:40 1997
***************
*** 13,19 ****
--- 13,21 ----
  #include <rpc/rpc.h>
  #include "adb.h"
  #include "admin_xdr.h"
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  
  bool_t
  xdr_krb5_key_data(XDR *xdrs, krb5_key_data *objp)
Index: lib/kadm5/srv/configure.in
diff -c krb5/lib/kadm5/srv/configure.in:1.1.1.1 krb5/lib/kadm5/srv/configure.in:1.4
*** krb5/lib/kadm5/srv/configure.in:1.1.1.1	Mon Jun  2 17:56:07 1997
--- krb5/lib/kadm5/srv/configure.in	Thu Nov 20 17:52:32 1997
***************
*** 7,12 ****
--- 7,32 ----
  AC_PROG_LEX
  AC_PROG_AWK
  
+ dnl Use cracklib?
+ AC_ARG_WITH([cracklib],
+ 	[  --with-cracklib               Use cracklib for password checking],
+ 	use_cracklib=$withval,
+ 	use_cracklib="false")
+ 
+ if test "$use_cracklib" != false ; then
+ 	cracklib_dir="cracklib"
+ 	AC_DEFINE(KADM5_USE_CRACKLIB)
+ 	CRACKLIB_SUBDIR=$cracklib_dir
+ 	CRACKLIB_DONE=$cracklib_dir/DONE
+ 	CONFIG_DIRS($cracklib_dir)
+ 	DO_SUBDIRS
+ else
+ 	CRACKLIB_SUBDIR=""
+ 	CRACKLIB_DONE=""
+ fi
+ AC_SUBST(CRACKLIB_SUBDIR)
+ AC_SUBST(CRACKLIB_DONE)
+ 
  save_LIBS="$LIBS"
  LIBS=-lgen
  AC_CHECK_FUNCS(compile step)
***************
*** 26,31 ****
--- 46,52 ----
  	;;
  esac
  
+ AC_CHECK_HEADERS(memory.h)
  V5_SHARED_LIB_OBJS
  V5_MAKE_SHARED_LIB(libkadm5srv, 1.0, ../.., ./kadm5/srv)
  
***************
*** 43,48 ****
--- 64,71 ----
  AC_SUBST(COMERR_SH_VERS)
  DYN_SH_VERS=$krb5_cv_shlib_version_libdyn
  AC_SUBST(DYN_SH_VERS)
+ 
+ 
  
  SubdirLibraryRule([$(OBJS)])
  
Index: lib/kadm5/srv/server_dict.c
diff -c krb5/lib/kadm5/srv/server_dict.c:1.1.1.2 krb5/lib/kadm5/srv/server_dict.c:1.5
*** krb5/lib/kadm5/srv/server_dict.c:1.1.1.2	Mon Nov  3 16:35:35 1997
--- krb5/lib/kadm5/srv/server_dict.c	Thu Dec  4 12:23:30 1997
***************
*** 17,29 ****
--- 17,39 ----
  #include    <stdlib.h>
  #include    <stdio.h>
  #include    <string.h>
+ #ifdef HAVE_MEMORY_H
  #include    <memory.h>
+ #endif
  #include    <syslog.h>
  #include    "server_internal.h"
  
+ #ifndef KADM5_USE_CRACKLIB
  static char	    **word_list = NULL;	    /* list of word pointers */
  static char	    *word_block = NULL;	    /* actual word data */
  static int	    word_count = 0;	    /* number of words */
+ 
+ #else /* KADM5_USE_CRACKLIB */
+ static char		*dict_path = NULL;
+ extern char 		*FascistCheck();
+ 
+ #endif /* KADM5_USE_CRACKLIB */
+ 
  extern int	    errno;
  
  /*
***************
*** 47,52 ****
--- 57,63 ----
      return (strcasecmp(*(char **)s1, *(char **)s2));
  }
  
+ #ifndef KADM5_USE_CRACKLIB
  /*
   * Function: init-dict
   * 
***************
*** 196,198 ****
--- 207,287 ----
  	word_count = 0;
      return;
  }
+ 
+ #else /* KADM5_USE_CRACKLIB */
+ 
+ /*
+  * Get dictionary file path from params, check it and store for later
+  * use by find_word().
+  */
+ int init_dict(kadm5_config_params *params)
+ {
+     struct stat st;
+     char *dict_file;
+ 
+ 
+     if (dict_path)	/* Already been initialized */
+ 	return KADM5_OK;
+ 
+     if (! (params->mask & KADM5_CONFIG_DICT_FILE)) {
+ 	syslog(LOG_INFO, "No dictionary file specified, continuing "
+ 	       "without one.");
+ 	return KADM5_OK;
+     }
+ 
+     /*
+      * Check for one of the cracklib dictionary files. We'll
+      * assume that if it's there, then the other two are.
+      *
+      * Note that for cracklib the path specified is just the
+      * prefix filename. The actual files will be the path
+      * plus an appened ".hwm", ".pwd", and ".pwi".
+      */
+      
+     dict_file = malloc(strlen(params->dict_file) + 5);
+     
+     if (dict_file == NULL) {
+ 	syslog(LOG_ERR, "malloc() failed.");
+ 	return errno;
+     }
+ 
+     strcpy(dict_file, params->dict_file);
+     strcat(dict_file, ".hwm");
+ 
+     if (stat(dict_file, &st) == 0) {
+ 	dict_path = params->dict_file;
+ 	syslog(LOG_INFO, "Using cracklib dictionary with prefix %s", dict_path);
+     } else {
+ 	syslog(LOG_ERR, "WARNING!  Cannot find cracklib dictionary file %s, "
+ 	       "continuing without one.", dict_file);
+     }
+ 
+     free(dict_file);
+     return KADM5_OK;
+ }
+   
+ int
+ find_word(const char *word)
+ {
+     char *msg;
+ 
+ 
+     if (dict_path == NULL)
+ 	return WORD_NOT_FOUND;
+ 
+     if (msg = FascistCheck(word, dict_path)) {
+ 	syslog(LOG_INFO, "cracklib rejected new change: %s", msg);
+ 	return KADM5_OK;
+     } else {
+ 	return WORD_NOT_FOUND;
+     }
+ }
+ 
+ void
+ destroy_dict(void)
+ {
+     dict_path = NULL;
+     return;
+ }
+ 
+ #endif /* KADM5_USE_CRACKLIB */
Index: lib/kadm5/srv/svr_principal.c
diff -c krb5/lib/kadm5/srv/svr_principal.c:1.1.1.3 krb5/lib/kadm5/srv/svr_principal.c:1.5
*** krb5/lib/kadm5/srv/svr_principal.c:1.1.1.3	Mon Nov  3 16:35:41 1997
--- krb5/lib/kadm5/srv/svr_principal.c	Mon Nov  3 17:14:44 1997
***************
*** 212,224 ****
  	return(ret);
      }
  
-     if (ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)) {
- 	krb5_dbe_free_contents(handle->context, &kdb);
- 	if (mask & KADM5_POLICY)
- 	     (void) kadm5_free_policy_ent(handle->lhandle, &polent);
- 	return(ret);
-     }
- 
      /* initialize the keys */
  
      if (ret = krb5_dbe_cpw(handle->context, &master_encblock,
--- 212,217 ----
***************
*** 365,371 ****
  
      CHECK_HANDLE(server_handle);
  
!     if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) ||
         (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
         (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
         (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
--- 358,364 ----
  
      CHECK_HANDLE(server_handle);
  
!     if((mask & KADM5_PRINCIPAL) ||
         (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) ||
         (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) ||
         (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) ||
***************
*** 534,539 ****
--- 527,545 ----
  	      kdb.tl_data = tl;
  	      tl2 = tl2->tl_data_next;
  	 }
+     }
+ 
+     /*
+      * I'm not sure if client programs should be forced to modify the
+      * TL_DATA directly, or use the obvious mechanism of modifying
+      * KADM5_LAST_PW_CHANGE.  To me, the latter seems to make more
+      * sense.
+      */
+ 
+     if (mask & KADM5_LAST_PWD_CHANGE) {
+ 	if ((ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb,
+ 						  entry->last_pwd_change)))
+ 	    goto done;
      }
  
      ret = kdb_put_entry(handle, &kdb, &adb);
Index: lib/kdb/configure.in
diff -c krb5/lib/kdb/configure.in:1.1.1.1 krb5/lib/kdb/configure.in:1.2
*** krb5/lib/kdb/configure.in:1.1.1.1	Mon Jun  2 17:55:45 1997
--- krb5/lib/kdb/configure.in	Tue Aug 12 12:42:14 1997
***************
*** 16,21 ****
--- 16,31 ----
  	LIBS="$LIBS -ldb"
  	;;
  esac
+ dnl
+ dnl --with-afs-name-change enables code that supports the case where
+ dnl the name of the realm (cell) changed when going from AFS to Kerberos 5
+ dnl
+ AC_ARG_WITH([afs-name-change],
+ [  -with-afs-name-change	Support an AFS cell with a different name],
+ if test "$withval" = yes; then
+ 	AC_DEFINE(CPW_PRESERVE_AFS_SALT)
+ fi)
+ dnl
  KRB5_RUN_FLAGS
  V5_USE_SHARED_LIB
  KRB5_LIBRARIES
Index: lib/kdb/kdb_cpw.c
diff -c krb5/lib/kdb/kdb_cpw.c:1.1.1.1 krb5/lib/kdb/kdb_cpw.c:1.4
*** krb5/lib/kdb/kdb_cpw.c:1.1.1.1	Mon Jun  2 17:55:45 1997
--- krb5/lib/kdb/kdb_cpw.c	Tue Jun 23 15:32:01 1998
***************
*** 27,32 ****
--- 27,37 ----
  #include <stdio.h>
  #include <errno.h>
  
+ #ifdef CPW_PRESERVE_AFS_SALT
+ static char *default_afs_key_salt = NULL;
+ static char *afs_key_salt;
+ #endif
+ 
  static int
  get_key_data_kvno(context, count, data)
      krb5_context	  context;
***************
*** 391,403 ****
              key_salt.data.length = 0;
              key_salt.data.data = 0;
              break;
!     	case KRB5_KDB_SALTTYPE_AFS3: {
              krb5_data * saltdata;
              if (retval = krb5_copy_data(context, krb5_princ_realm(context,
  					db_entry->princ), &saltdata))
  	 	return(retval);
  
  	    key_salt.data = *saltdata;
  	    key_salt.data.length = -1; /*length actually used below...*/
  	    krb5_xfree(saltdata);
  	}
--- 396,440 ----
              key_salt.data.length = 0;
              key_salt.data.data = 0;
              break;
!     	case KRB5_KDB_SALTTYPE_AFS3:
! #ifdef CPW_PRESERVE_AFS_SALT
! 	    /*
! 	     * If a salt string for AFS was specified then use it instead
! 	     * of calling krb5_princ_realm()
! 	     */
! 	if (afs_key_salt) {
! 	    key_salt.data.data = strdup(afs_key_salt);
! 	    if (!key_salt.data.data)
! 		return ENOMEM; 
! 
! 	    key_salt.data.length = -1;
! 		
! 	} else
! #endif /* CPW_PRESERVE_AFS_SALT */
! 	{
              krb5_data * saltdata;
+ 	    char *terminated_string;
              if (retval = krb5_copy_data(context, krb5_princ_realm(context,
  					db_entry->princ), &saltdata))
  	 	return(retval);
  
  	    key_salt.data = *saltdata;
+ 	    /*
+ 	     * The krb5_string_to_key function expects a null-terminated realm
+ 	     * name.  Re-allocate storage with room for a terminator and
+ 	     * terminate the string.
+ 	     */
+ 	    if ((terminated_string = malloc(key_salt.data.length + 1)) == NULL)
+ 	    {
+ 		if (key_salt.data.data)
+ 		    free(key_salt.data.data);
+ 		krb5_xfree(saltdata);
+ 		return(ENOMEM);
+ 	    }
+ 	    memcpy(terminated_string, key_salt.data.data, key_salt.data.length);
+ 	    terminated_string[key_salt.data.length] = '\0';
+ 	    free(key_salt.data.data);
+ 	    key_salt.data.data = terminated_string;
  	    key_salt.data.length = -1; /*length actually used below...*/
  	    krb5_xfree(saltdata);
  	}
***************
*** 416,423 ****
  	}
  
  	if (key_salt.data.length == -1)
! 	    key_salt.data.length = 
! 	      krb5_princ_realm(context, db_entry->princ)->length;
  
  	if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, &key,
  		     (const krb5_keysalt *)&key_salt,
--- 453,469 ----
  	}
  
  	if (key_salt.data.length == -1)
! #ifdef CPW_PRESERVE_AFS_SALT
! 	    /*
! 	     * Again, use specified salt string, if specified, instead
! 	     * of krb5_princ_realm().
! 	     */
! 	    if (afs_key_salt)
! 		key_salt.data.length = strlen(afs_key_salt);
! 	    else	
! #endif /* CPW_PRESERVE_AFS_SALT */
! 		key_salt.data.length = 
! 		    krb5_princ_realm(context, db_entry->princ)->length;
  
  	if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, &key,
  		     (const krb5_keysalt *)&key_salt,
***************
*** 464,469 ****
--- 510,577 ----
      db_entry->key_data = NULL;
      db_entry->n_key_data = 0;
  
+ #ifdef CPW_PRESERVE_AFS_SALT
+     /*
+      * See if the user has an old AFS key and if so then we'll use it's
+      * salt to salt their new AFS key.
+      *
+      * If the user doesn't have an old AFS key then check the krb5.conf
+      * file for a default string to use. If it's there then use it.
+      *
+      * Otherwise then just leave afs_key_salt NULL and the default will
+      * be used.
+      *
+      */
+     {
+ 	int i;
+ 
+ 	afs_key_salt = NULL;
+ 
+ 	/* Check for an old AFS key */
+ 	for (i = 0; i < key_data_count; i++) {
+ 	    if ((key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_AFS3) &&
+ 		key_data[i].key_data_length[1]) {
+ 
+ 		int len = key_data[i].key_data_length[1];
+ 		
+ 		/*
+ 		 * We need to copy out the contents and terminate it with
+ 		 * a null, since it's not guarenteed to be null
+ 		 * terminated as it is.
+ 		 */
+ 		afs_key_salt = malloc(len + 1);
+ 
+ 		if (!afs_key_salt)
+ 		    return ENOMEM;	
+ 
+ 		memcpy(afs_key_salt, key_data[i].key_data_contents[1], len);
+ 		afs_key_salt[len] = '\0';
+ 	    }
+ 	}
+ 
+ 	if (!afs_key_salt) {
+ 	    /* Check for default in krb5.conf */
+ 	    const char *names[3];
+ 	    char **values = NULL;
+ 
+ 	    names[0] = "kdc";
+ 	    names[1] = "afs_salt";
+ 	    names[2] = NULL;
+ 
+ 	    retval = profile_get_values(context->profile, names, &values);
+ 	    if (retval == 0 && values && values[0])
+ 		afs_key_salt = strdup(values[0]);
+ 
+ 	    if (values) {
+ 		char **cpp;
+ 		for (cpp = values; *cpp; cpp++)
+ 			free(*cpp);
+ 		free(values);
+ 	    }
+ 	}
+     }
+ #endif /* CPW_PRESERVE_AFS_SALT */
+ 
      /* increment the kvno.  if the requested kvno is too small, 
         increment the old kvno */
      if (new_kvno < old_kvno+1)
***************
*** 477,482 ****
--- 585,596 ----
      } else {
  	cleanup_key_data(context, key_data_count, key_data);
      }
+ #ifdef CPW_PRESERVE_AFS_SALT
+     if (afs_key_salt) {
+ 	free(afs_key_salt);
+ 	afs_key_salt = NULL;
+     }
+ #endif
      return(retval);
  }
  
Index: lib/krb4/decomp_tkt.c
diff -c krb5/lib/krb4/decomp_tkt.c:1.1.1.1 krb5/lib/krb4/decomp_tkt.c:1.2
*** krb5/lib/krb4/decomp_tkt.c:1.1.1.1	Mon Jun  2 17:56:22 1997
--- krb5/lib/krb4/decomp_tkt.c	Wed Aug 27 18:20:25 1997
***************
*** 80,86 ****
  	setbuf(fp, keybuf);
  	fwrite(tkt->dat, 1, tkt->length, fp);
  	fclose(fp);
! 	memset(keybuf, sizeof(keybuf), 0);	/* Clear the buffer */
      }
  #endif
      pcbc_encrypt((C_Block *)tkt->dat,(C_Block *)tkt->dat,
--- 80,86 ----
  	setbuf(fp, keybuf);
  	fwrite(tkt->dat, 1, tkt->length, fp);
  	fclose(fp);
! 	memset(keybuf, 0, sizeof(keybuf));	/* Clear the buffer */
      }
  #endif
      pcbc_encrypt((C_Block *)tkt->dat,(C_Block *)tkt->dat,
***************
*** 95,101 ****
  	setbuf(fp, keybuf);
  	fwrite(tkt->dat, 1, tkt->length, fp);
  	fclose(fp);
! 	memset(keybuf, sizeof(keybuf), 0);	/* Clear the buffer */
      }
  #endif
  
--- 95,101 ----
  	setbuf(fp, keybuf);
  	fwrite(tkt->dat, 1, tkt->length, fp);
  	fclose(fp);
! 	memset(keybuf, 0, sizeof(keybuf));	/* Clear the buffer */
      }
  #endif
  
Index: lib/krb4/g_krbrlm.c
diff -c krb5/lib/krb4/g_krbrlm.c:1.1.1.2 krb5/lib/krb4/g_krbrlm.c:1.3
*** krb5/lib/krb4/g_krbrlm.c:1.1.1.2	Mon Jun  2 23:33:32 1997
--- krb5/lib/krb4/g_krbrlm.c	Tue Jun  3 00:07:20 1997
***************
*** 12,17 ****
--- 12,18 ----
  #include <stdio.h>
  #include "krb.h"
  #include <string.h>
+ #include "k5-int.h"
  
  /*
   * krb_get_lrealm takes a pointer to a string, and a number, n.  It fills
***************
*** 44,50 ****
      cnffile = krb__get_cnffile();
      if (!cnffile) {
  	if (n == 1) {
! 	    (void) strcpy(r, KRB_REALM);
  	    return(KSUCCESS);
  	}
  	else
--- 45,67 ----
      cnffile = krb__get_cnffile();
      if (!cnffile) {
  	if (n == 1) {
! 	    krb5_context context;
! 	    krb5_error_code retcode;
! 	    char *realm = NULL;
! 
! 	    retcode = krb5_init_context(&context);
! 
! 	    if (retcode || krb5_get_default_realm(context, &realm)) {
! 	        (void) strcpy(r, KRB_REALM);
! 	    } else {
! 		(void) strcpy(r, realm);
! 	    }
! 
! 	    if (realm)
! 		free(realm);
! 
! 	    if (! retcode)
! 	        krb5_free_context(context);
  	    return(KSUCCESS);
  	}
  	else
Index: lib/krb5/Makefile.in
diff -c krb5/lib/krb5/Makefile.in:1.1.1.1 krb5/lib/krb5/Makefile.in:1.2
*** krb5/lib/krb5/Makefile.in:1.1.1.1	Mon Jun  2 17:56:50 1997
--- krb5/lib/krb5/Makefile.in	Tue Apr 13 14:08:56 1999
***************
*** 2,7 ****
--- 2,8 ----
  
  ANAME_DBDEP=@ANAME_DBDEP@
  ANAME_DBLIB=@ANAME_DBLIB@
+ RESOLV_LIB=@RESOLV_LIB@
  
  TST=if test -n "`cat DONE`" ; then
  
***************
*** 22,28 ****
  DEPLIBS=$(TOPLIBD)/libcrypto.$(SHEXT).$(CRYPTO_VER) \
  	$(TOPLIBD)/libcom_err.$(SHEXT).$(COMERR_VER) \
  	$(ANAME_DBDEP)
! SHLIB_LIBS=-lcrypto -lcom_err $(ANAME_DBLIB) @SHLIB_GEN@
  SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@	
  #	$(LD_UNRESOLVED_PREFIX)_et_list $(LD_UNRESOLVED_PREFIX)error_message
  SHLIB_LIBDIRS= @SHLIB_LIBDIRS@
--- 23,29 ----
  DEPLIBS=$(TOPLIBD)/libcrypto.$(SHEXT).$(CRYPTO_VER) \
  	$(TOPLIBD)/libcom_err.$(SHEXT).$(COMERR_VER) \
  	$(ANAME_DBDEP)
! SHLIB_LIBS=-lcrypto -lcom_err $(ANAME_DBLIB) $(RESOLV_LIB) @SHLIB_GEN@
  SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@	
  #	$(LD_UNRESOLVED_PREFIX)_et_list $(LD_UNRESOLVED_PREFIX)error_message
  SHLIB_LIBDIRS= @SHLIB_LIBDIRS@
Index: lib/krb5/configure.in
diff -c krb5/lib/krb5/configure.in:1.1.1.1 krb5/lib/krb5/configure.in:1.2
*** krb5/lib/krb5/configure.in:1.1.1.1	Mon Jun  2 17:56:50 1997
--- krb5/lib/krb5/configure.in	Tue Apr 13 14:08:56 1999
***************
*** 13,18 ****
--- 13,33 ----
  AC_SUBST(ANAME_DBDEP)
  AC_SUBST(ANAME_DBLIB)
  dnl
+ dnl If we are compiling with --enable-dns-resolv, we need to create a
+ dnl dependency for -lresolv in libkrb5 on Solaris
+ dnl
+ RESOLV_LIB=
+ AC_ARG_ENABLE([dns-lookup],
+ [  --enable-dns-lookup     Support for looking up KDC/host info in DNS],[
+ echo "Enabling support for looking up KDC/host information via DNS"
+ case $krb5_cv_host in
+ 	*-sun-solaris*|i386-unknown-solaris*)
+ 		RESOLV_LIB=-lresolv
+ 		;;
+ esac],[
+ echo "No support for KDC/host info lookup via DNS"])
+ AC_SUBST(RESOLV_LIB)
+ dnl
  AC_CHECK_LIB(gen,compile,SHLIB_GEN=-lgen,SHLIB_GEN='')
  AC_SUBST(SHLIB_GEN)
  dnl
Index: lib/krb5/asn.1/krb5_decode.c
diff -c krb5/lib/krb5/asn.1/krb5_decode.c:1.1.1.1 krb5/lib/krb5/asn.1/krb5_decode.c:1.2
*** krb5/lib/krb5/asn.1/krb5_decode.c:1.1.1.1	Mon Jun  2 17:57:06 1997
--- krb5/lib/krb5/asn.1/krb5_decode.c	Thu Jul 23 13:05:32 1998
***************
*** 837,839 ****
--- 837,851 ----
    cleanup(free);
  }
  
+ krb5_error_code decode_krb5_principal(code, rep)
+      const krb5_data * code;
+      krb5_principal * rep;
+ {
+   setup();
+   alloc_field(*rep, krb5_principal_data);
+   { begin_structure();
+     get_field(*rep, 0, asn1_decode_realm);
+     get_field(*rep, 1, asn1_decode_principal_name);
+     end_structure(); }
+   cleanup(free);
+ }
Index: lib/krb5/asn.1/krb5_encode.c
diff -c krb5/lib/krb5/asn.1/krb5_encode.c:1.1.1.1 krb5/lib/krb5/asn.1/krb5_encode.c:1.2
*** krb5/lib/krb5/asn.1/krb5_encode.c:1.1.1.1	Mon Jun  2 17:57:07 1997
--- krb5/lib/krb5/asn.1/krb5_encode.c	Thu Jul 23 13:05:33 1998
***************
*** 847,849 ****
--- 847,863 ----
    sum += length;
    krb5_cleanup();
  }
+ 
+ krb5_error_code encode_krb5_principal(rep, code)
+      const krb5_principal rep;
+      krb5_data ** code;
+ {
+   krb5_setup();
+ 
+   krb5_addfield(rep, 1, asn1_encode_principal_name);
+   krb5_addfield(rep, 0, asn1_encode_realm);
+ 
+   krb5_makeseq();
+ 
+   krb5_cleanup();
+ }
Index: lib/krb5/krb/Makefile.in
diff -c krb5/lib/krb5/krb/Makefile.in:1.1.1.2 krb5/lib/krb5/krb/Makefile.in:1.3
*** krb5/lib/krb5/krb/Makefile.in:1.1.1.2	Wed May 12 13:24:04 1999
--- krb5/lib/krb5/krb/Makefile.in	Wed May 12 14:55:58 1999
***************
*** 8,13 ****
--- 8,15 ----
  	$(CC) $(CFLAGS) -c $(srcdir)/$*.c
  @SHARED_RULE@
  
+ init_ctx.$(OBJEXT): $(srcdir)/brand.c
+ 
  OBJS=	addr_comp.$(OBJEXT)	\
  	addr_order.$(OBJEXT)	\
  	addr_srch.$(OBJEXT)	\
***************
*** 87,92 ****
--- 89,95 ----
  	$(srcdir)/auth_con.c	\
  	$(srcdir)/bld_pr_ext.c	\
  	$(srcdir)/bld_princ.c	\
+ 	$(srcdir)/brand.c	\
  	$(srcdir)/chk_trans.c	\
  	$(srcdir)/conv_princ.c	\
  	$(srcdir)/copy_addrs.c	\
Index: lib/krb5/krb/brand.c
diff -c krb5/lib/krb5/krb/brand.c:1.1.1.5 krb5/lib/krb5/krb/brand.c:1.6
*** krb5/lib/krb5/krb/brand.c:1.1.1.5	Wed May 12 13:24:06 1999
--- krb5/lib/krb5/krb/brand.c	Thu Sep 23 15:12:53 1999
***************
*** 12,15 ****
  
  /* Format: "KRB5_BRAND: <cvs tag> <date>" */
  
! static char krb5_brand[] = "KRB5_BRAND: V1_0_6_FINAL 1.0.6 19990510";
--- 12,15 ----
  
  /* Format: "KRB5_BRAND: <cvs tag> <date>" */
  
! static char krb5_brand[] = "@(#) $NRL: AFS_K5_MIGRATION_KIT_1_3 19990923 $";
Index: lib/krb5/krb/configure.in
diff -c krb5/lib/krb5/krb/configure.in:1.1.1.1 krb5/lib/krb5/krb/configure.in:1.3
*** krb5/lib/krb5/krb/configure.in:1.1.1.1	Mon Jun  2 17:56:54 1997
--- krb5/lib/krb5/krb/configure.in	Tue Nov 11 19:33:32 1997
***************
*** 5,11 ****
  AC_PROG_RANLIB
  AC_HEADER_STDARG
  V5_SHARED_LIB_OBJS
! AC_HAVE_FUNCS(strftime strptime geteuid)
  KRB5_RUN_FLAGS
  SubdirLibraryRule([$(OBJS)])
  USE_ANAME
--- 5,19 ----
  AC_PROG_RANLIB
  AC_HEADER_STDARG
  V5_SHARED_LIB_OBJS
! AC_ARG_WITH([strptime],
! [  --with-strptime         Use native strptime(), if present (default)
!   --without-strptime      Always use included strptime()], ,with_strptime=yes)
! if test $with_strptime != no; then
! 	AC_HAVE_FUNCS(strftime strptime geteuid)
! else
! 	AC_HAVE_FUNCS(strftime geteuid)
! fi
! AC_CHECK_HEADERS(memory.h)
  KRB5_RUN_FLAGS
  SubdirLibraryRule([$(OBJS)])
  USE_ANAME
Index: lib/krb5/krb/conv_princ.c
diff -c krb5/lib/krb5/krb/conv_princ.c:1.1.1.2 krb5/lib/krb5/krb/conv_princ.c:1.3
*** krb5/lib/krb5/krb/conv_princ.c:1.1.1.2	Wed May 12 13:24:07 1999
--- krb5/lib/krb5/krb/conv_princ.c	Wed May 12 14:55:58 1999
***************
*** 67,72 ****
--- 67,73 ----
      {"imap",	"imap",		DO_REALM_CONVERSION},
      {"ftp",	"ftp",		DO_REALM_CONVERSION},
      {"ecat",	"ecat",		DO_REALM_CONVERSION},
+     {"sunhpc",	"sunhpc",	DO_REALM_CONVERSION},
      {"daemon",        "daemon",       DO_REALM_CONVERSION},
      {"gnats", "gnats",        DO_REALM_CONVERSION},
      {"moira", "moira",        DO_REALM_CONVERSION},
Index: lib/krb5/krb/cp_key_cnt.c
diff -c krb5/lib/krb5/krb/cp_key_cnt.c:1.1.1.1 krb5/lib/krb5/krb/cp_key_cnt.c:1.2
*** krb5/lib/krb5/krb/cp_key_cnt.c:1.1.1.1	Mon Jun  2 17:56:55 1997
--- krb5/lib/krb5/krb/cp_key_cnt.c	Mon Sep 14 14:37:16 1998
***************
*** 36,44 ****
      krb5_keyblock *to;
  {
      *to = *from;
!     to->contents = (krb5_octet *)malloc(to->length);
!     if (!to->contents)
! 	return ENOMEM;
!     memcpy((char *)to->contents, (char *)from->contents, to->length);
      return 0;
  }
--- 36,46 ----
      krb5_keyblock *to;
  {
      *to = *from;
!     if (from->length > 0) {
! 	to->contents = (krb5_octet *)malloc(to->length);
! 	if (!to->contents)
! 	    return ENOMEM;
!         memcpy((char *)to->contents, (char *)from->contents, to->length);
!     }
      return 0;
  }
Index: lib/krb5/krb/fwd_tgt.c
diff -c krb5/lib/krb5/krb/fwd_tgt.c:1.1.1.2 krb5/lib/krb5/krb/fwd_tgt.c:1.4
*** krb5/lib/krb5/krb/fwd_tgt.c:1.1.1.2	Mon Jun  2 23:36:29 1997
--- krb5/lib/krb5/krb/fwd_tgt.c	Thu Sep 18 16:38:47 1997
***************
*** 23,29 ****
--- 23,31 ----
  
  #define NEED_SOCKETS
  #include "k5-int.h"
+ #ifdef HAVE_MEMORY_H
  #include <memory.h>
+ #endif
  
  /* helper function: convert flags to necessary KDC options */
  #define flags2options(flags) (flags & KDC_TKT_COMMON_MASK)
Index: lib/krb5/krb/get_in_tkt.c
diff -c krb5/lib/krb5/krb/get_in_tkt.c:1.1.1.1 krb5/lib/krb5/krb/get_in_tkt.c:1.2
*** krb5/lib/krb5/krb/get_in_tkt.c:1.1.1.1	Mon Jun  2 17:56:57 1997
--- krb5/lib/krb5/krb/get_in_tkt.c	Thu Apr  1 23:45:18 1999
***************
*** 401,412 ****
      request.msg_type = KRB5_AS_REQ;
      request.addresses = 0;
      request.ktype = 0;
      if (addrs)
  	request.addresses = (krb5_address **) addrs;
      else
  	if ((retval = krb5_os_localaddr(context, &request.addresses)))
  	    goto cleanup;
-     request.padata = 0;
      request.kdc_options = options;
      request.client = creds->client;
      request.server = creds->server;
--- 401,412 ----
      request.msg_type = KRB5_AS_REQ;
      request.addresses = 0;
      request.ktype = 0;
+     request.padata = 0;
      if (addrs)
  	request.addresses = (krb5_address **) addrs;
      else
  	if ((retval = krb5_os_localaddr(context, &request.addresses)))
  	    goto cleanup;
      request.kdc_options = options;
      request.client = creds->client;
      request.server = creds->server;
Index: lib/krb5/krb/init_ctx.c
diff -c krb5/lib/krb5/krb/init_ctx.c:1.1.1.1 krb5/lib/krb5/krb/init_ctx.c:1.2
*** krb5/lib/krb5/krb/init_ctx.c:1.1.1.1	Mon Jun  2 17:56:57 1997
--- krb5/lib/krb5/krb/init_ctx.c	Tue May  4 15:45:35 1999
***************
*** 25,30 ****
--- 25,31 ----
  
  #include "k5-int.h"
  #include <ctype.h>
+ #include "brand.c"
  
  #if (defined(_MSDOS) || defined(_WIN32))
  extern void krb5_win_do_init();
Index: lib/krb5/krb/rd_cred.c
diff -c krb5/lib/krb5/krb/rd_cred.c:1.1.1.1 krb5/lib/krb5/krb/rd_cred.c:1.2
*** krb5/lib/krb5/krb/rd_cred.c:1.1.1.1	Mon Jun  2 17:56:58 1997
--- krb5/lib/krb5/krb/rd_cred.c	Wed Aug 27 18:21:52 1997
***************
*** 95,101 ****
      if ((retval = decode_krb5_cred(pcreddata, &pcred)))
      	return retval;
  
!     memset(&encpart, sizeof(encpart), 0);
  
      if ((retval = decrypt_credencdata(context, pcred, pkeyblock, &encpart)))
  	goto cleanup_cred;
--- 95,101 ----
      if ((retval = decode_krb5_cred(pcreddata, &pcred)))
      	return retval;
  
!     memset(&encpart, 0, sizeof(encpart));
  
      if ((retval = decrypt_credencdata(context, pcred, pkeyblock, &encpart)))
  	goto cleanup_cred;
Index: lib/krb5/krb/recvauth.c
diff -c krb5/lib/krb5/krb/recvauth.c:1.1.1.2 krb5/lib/krb5/krb/recvauth.c:1.3
*** krb5/lib/krb5/krb/recvauth.c:1.1.1.2	Wed May 12 13:24:15 1999
--- krb5/lib/krb5/krb/recvauth.c	Wed May 12 14:55:58 1999
***************
*** 88,94 ****
  	 */
  	if ((retval = krb5_read_message(context, fd, &inbuf)))
  		return(retval);
! 	if (strcmp(inbuf.data, appl_version)) {
  		krb5_xfree(inbuf.data);
  		if (!problem)
  			problem = KRB5_SENDAUTH_BADAPPLVERS;
--- 88,94 ----
  	 */
  	if ((retval = krb5_read_message(context, fd, &inbuf)))
  		return(retval);
! 	if (appl_version && strcmp(inbuf.data, appl_version)) {
  		krb5_xfree(inbuf.data);
  		if (!problem)
  			problem = KRB5_SENDAUTH_BADAPPLVERS;
Index: lib/krb5/krb/str_conv.c
diff -c krb5/lib/krb5/krb/str_conv.c:1.1.1.2 krb5/lib/krb5/krb/str_conv.c:1.4
*** krb5/lib/krb5/krb/str_conv.c:1.1.1.2	Wed May 12 13:24:18 1999
--- krb5/lib/krb5/krb/str_conv.c	Tue Jul  6 13:44:37 1999
***************
*** 277,283 ****
   * Rudimentary version of strptime for systems which don't have it.
   */
  static char *
! strptime(buf, format, tm)
      char *buf;
      const char *format;
      struct tm *tm;
--- 277,283 ----
   * Rudimentary version of strptime for systems which don't have it.
   */
  static char *
! lstrptime(buf, format, tm)
      char *buf;
      const char *format;
      struct tm *tm;
***************
*** 401,406 ****
--- 401,407 ----
  	    return NULL;
      return bp;
  }
+ #define strptime lstrptime
  #endif	/* HAVE_STRPTIME */
  
  /*
***************
*** 675,681 ****
  	if (buflen >= sftime_default_len) {
  	    sprintf(buffer, sftime_default_fmt,
  		    tmp->tm_mday, tmp->tm_mon+1, 1900+tmp->tm_year,
! 		    tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
  	    ndone = strlen(buffer);
  	}
      }
--- 676,682 ----
  	if (buflen >= sftime_default_len) {
  	    sprintf(buffer, sftime_default_fmt,
  		    tmp->tm_mday, tmp->tm_mon+1, 1900+tmp->tm_year,
! 		    tmp->tm_hour, tmp->tm_min);
  	    ndone = strlen(buffer);
  	}
      }
Index: lib/krb5/os/Makefile.in
diff -c krb5/lib/krb5/os/Makefile.in:1.1.1.1 krb5/lib/krb5/os/Makefile.in:1.2
*** krb5/lib/krb5/os/Makefile.in:1.1.1.1	Mon Jun  2 17:57:28 1997
--- krb5/lib/krb5/os/Makefile.in	Mon Jun  2 18:34:48 1997
***************
*** 10,15 ****
--- 10,16 ----
  @SHARED_RULE@
  
  OBJS= \
+ 	appdefault.$(OBJEXT)	\
  	an_to_ln.$(OBJEXT)	\
  	def_realm.$(OBJEXT)	\
  	DNR.$(OBJEXT)	\
Index: lib/krb5/os/appdefault.c
diff -c /dev/null krb5/lib/krb5/os/appdefault.c:1.1
*** /dev/null	Thu Sep 23 15:41:58 1999
--- krb5/lib/krb5/os/appdefault.c	Mon Jun  2 18:38:26 1997
***************
*** 0 ****
--- 1,181 ----
+ /*
+  * appdefault - routines designed to be called from applications to
+  *		 handle the [appdefaults] profile section
+  */
+ 
+ #include <stdio.h>
+ #include <string.h>
+ #include <k5-int.h>
+ 
+ 
+ 
+  /*xxx Duplicating this is annoying; try to work on a better way.*/
+ static char *conf_yes[] = {
+ 	"y", "yes", "true", "t", "1", "on",
+ 	0,
+ };
+ 
+ static char *conf_no[] = {
+ 	"n", "no", "false", "nil", "0", "off",
+ 	0,
+ };
+ 
+ static int conf_boolean(s)
+ 	char *s;
+ {
+ 	char **p;
+ 	for(p=conf_yes; *p; p++) {
+ 		if (!strcasecmp(*p,s))
+ 			return 1;
+ 	}
+ 	for(p=conf_no; *p; p++) {
+ 		if (!strcasecmp(*p,s))
+ 		return 0;
+ 	}
+ 	/* Default to "no" */
+ 	return 0;
+ }
+ 
+ static krb5_error_code appdefault_get(context, appname, realm, option,
+ 				ret_value)
+ krb5_context context;
+ 	const char *appname, *option;
+ const krb5_data *realm;
+ 	char **ret_value;
+ {
+ profile_t profile;
+ const char *names[5];
+ 	char **nameval = NULL;
+ 	krb5_error_code retval;
+ 	const char * realmstr =  realm?realm->data:NULL;
+ 
+ 	    if (!context || (context->magic != KV5M_CONTEXT)) 
+ 	    return KV5M_CONTEXT;
+ 
+ 	    profile = context->profile;
+ 	    
+ 	/*
+ 	 * Try number one:
+ 	 *
+ 	 * [appdefaults]
+ 	 *	app = {
+ 	 *		SOME.REALM = {
+ 	 *			option = <boolean>
+ 	 *		}
+ 	 *	}
+ 	 */
+ 
+ 	names[0] = "appdefaults";
+ 	names[1] = appname;
+ 
+ 	if (realmstr) {
+ 		names[2] = realmstr;
+ 		names[3] = option;
+ 		names[4] = 0;
+ 		retval = profile_get_values(profile, names, &nameval);
+ 		if (retval == 0 && nameval && nameval[0]) {
+ 			*ret_value = strdup(nameval[0]);
+ 			goto goodbye;
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * Try number two:
+ 	 *
+ 	 * [appdefaults]
+ 	 *	app = {
+ 	 *		option = <boolean>
+ 	 *      }
+ 	 */
+ 
+ 	names[2] = option;
+ 	names[3] = 0;
+ 	retval = profile_get_values(profile, names, &nameval);
+ 	if (retval == 0 && nameval && nameval[0]) {
+ 		*ret_value = strdup(nameval[0]);
+ 		goto goodbye;
+ 	}
+ 
+ 	/*
+ 	 * Try number three:
+ 	 *
+ 	 * [appdefaults]
+ 	 *	realm = {
+ 	 *		option = <boolean>
+ 	 */
+ 	
+ 	if (realmstr) {
+ 		names[1] = realmstr;
+ 		names[2] = option;
+ 		names[3] = 0;
+ 		retval = profile_get_values(profile, names, &nameval);
+ 		if (retval == 0 && nameval && nameval[0]) {
+ 			*ret_value = strdup(nameval[0]);
+ 			goto goodbye;
+ 		}
+ 	}
+ 
+ 	/*
+ 	 * Try number four:
+ 	 *
+ 	 * [appdefaults]
+ 	 *	option = <boolean>
+ 	 */
+ 
+ 	names[1] = option;
+ 	names[2] = 0;
+ 	retval = profile_get_values(profile, names, &nameval);
+ 	if (retval == 0 && nameval && nameval[0]) {
+ 		*ret_value = strdup(nameval[0]);
+ 	} else {
+ 		return retval;
+ 	}
+ 
+ goodbye:
+ 	if (nameval) {
+ 		char **cpp;
+ 		for (cpp = nameval; *cpp; cpp++)
+ 			free(*cpp);
+ 		free(nameval);
+ 	}
+ 	return 0;
+ }
+ 
+ 	 void krb5_appdefault_boolean(context, appname, realm, option,
+ 				     default_value, ret_value)
+ 	   krb5_context context;
+ 	const char *appname,  *option;
+ 	   const krb5_data *realm;
+ 	int default_value;
+ 	int *ret_value;
+ {
+ 	char *string = NULL;
+ 	krb5_error_code retval;
+ 
+ 	retval = appdefault_get(context, appname, realm, option, &string);
+ 
+ 	if (! retval && string) {
+ 		*ret_value = conf_boolean(string);
+ 		free(string);
+ 	} else
+ 		*ret_value = default_value;
+ }
+ 
+ void krb5_appdefault_string(context, appname, realm, option, default_value,
+ 				ret_value)
+      krb5_context context;
+ 	const char *appname, *option, *default_value;
+ 	char **ret_value;
+      const krb5_data *realm;
+ 	{
+ 	krb5_error_code retval;
+ 	char *string;
+ 
+ 	retval = appdefault_get(context, appname, realm, option, &string);
+ 
+ 	if (! retval && string) {
+ 		*ret_value = string;
+ 	} else {
+ 		*ret_value = strdup(default_value);
+ 	}
+ }
Index: lib/krb5/os/configure.in
diff -c krb5/lib/krb5/os/configure.in:1.1.1.1 krb5/lib/krb5/os/configure.in:1.4
*** krb5/lib/krb5/os/configure.in:1.1.1.1	Mon Jun  2 17:57:29 1997
--- krb5/lib/krb5/os/configure.in	Thu Apr 15 14:49:58 1999
***************
*** 26,31 ****
--- 26,45 ----
  AC_HAVE_FUNCS(re_comp)
  AC_HEADER_EGREP(time_t, sys/types.h, AC_DEFINE(POSIX_TYPES))
  HAS_ANSI_VOLATILE
+ dnl
+ dnl --enable-app-proxy turns on support for application proxy gateways
+ dnl
+ AC_ARG_ENABLE([app-proxy],
+ [  --enable-app-proxy      Support application proxy gateways],[
+ echo "Enabling support for application proxy gateways"
+ AC_DEFINE(PROXY_ALTERNATE_ADDRS)],[
+ echo "No support for application proxy gateways"])
+ AC_ARG_ENABLE([dns-lookup],
+ [  --enable-dns-lookup     Support for looking up KDC/host info in DNS],[
+ echo "Enabling support for looking up KDC/host information via DNS"
+ AC_DEFINE(KRB5_DNS_LOOKUP)],[
+ echo "No support for KDC/host info lookup via DNS"])
+ AC_HAVE_FUNCS(snprintf)
  AC_DEFINE(AN_TO_LN_RULES)
  USE_ANAME
  V5_SHARED_LIB_OBJS
Index: lib/krb5/os/hst_realm.c
diff -c krb5/lib/krb5/os/hst_realm.c:1.1.1.1 krb5/lib/krb5/os/hst_realm.c:1.3
*** krb5/lib/krb5/os/hst_realm.c:1.1.1.1	Mon Jun  2 17:57:29 1997
--- krb5/lib/krb5/os/hst_realm.c	Wed May  5 17:42:50 1999
***************
*** 71,82 ****
--- 71,194 ----
  #else
  #include <strings.h>
  #endif
+ #ifdef KRB5_DNS_LOOKUP
+ #include <arpa/nameser.h>
+ #include <arpa/inet.h>
+ #include <resolv.h>
+ #endif /* KRB5_DNS_LOOKUP */
  
  /* for old Unixes and friends ... */
  #ifndef MAXHOSTNAMELEN
  #define MAXHOSTNAMELEN 64
  #endif
  
+ #ifdef KRB5_DNS_LOOKUP
+ /*
+  * Try to look up a TXT record pointing to a Kerberos realm
+  */
+ 
+ static krb5_error_code
+ krb5_try_realm_txt_rr(prefix, name, realm)
+     const char *prefix, *name;
+     char **realm;
+ {
+     unsigned char answer[2048], *p;
+     char host[256];
+     int size;
+     HEADER *hdr;
+     int type, class, numanswers, numqueries, rdlen, len;
+ 
+     /*
+      * Form our query, and send it via DNS
+      */
+ 
+ #ifdef HAVE_SNPRINTF
+     snprintf(host, sizeof(host), "%s.%s", prefix, name);
+ #else /* HAVE_SNPRINTF */
+     sprintf(host, "%s.%s", prefix, name);
+ #endif /* HAVE_SNPRINTF */
+ 
+     size = res_search(host, C_IN, T_TXT, answer, sizeof(answer));
+ 
+     if (size < 0)
+ 	return KRB5_ERR_HOST_REALM_UNKNOWN;
+ 
+     p = answer;
+     hdr = (HEADER *) answer;
+ 
+     numqueries = ntohs(hdr->qdcount);
+     numanswers = ntohs(hdr->ancount);
+ 
+     p += sizeof(HEADER);
+ 
+     /*
+      * We need to skip over the questions before we can get to the answers,
+      * which means we have to iterate over every query record.  We use
+      * dn_expand to tell us how long each compressed name is.
+      */
+ 
+ #define INCR_CHECK(x, y) x += y; if (x > size + answer) \
+ 					return KRB5_ERR_HOST_REALM_UNKNOWN
+ #define NTOHSP(x) x[0] << 8 | x[1]
+ 
+     while (numqueries--) {
+ 	len = dn_expand(answer, answer + size, p, host, sizeof(host));
+ 	if (len < 0)
+ 	    return KRB5_ERR_HOST_REALM_UNKNOWN;
+ 	INCR_CHECK(p, len + 4);		/* Name plus type plus class */
+     }
+ 
+     /*
+      * We're now pointing at the answer records.  Process the first
+      * TXT record we find.
+      */
+ 
+     while (numanswers--) {
+ 	
+ 	/* First the name; use dn_expand to get the compressed size */
+ 	len = dn_expand(answer, answer + size, p, host, sizeof(host));
+ 	if (len < 0)
+ 	    return KRB5_ERR_HOST_REALM_UNKNOWN;
+ 	INCR_CHECK(p, len);
+ 
+ 	/* Next is the query type */
+ 	type = NTOHSP(p);
+ 	INCR_CHECK(p, 2);
+ 
+ 	/* Next is the query class; also skip over 4 byte TTL */
+ 	class = NTOHSP(p);
+ 	INCR_CHECK(p, 6);
+ 
+ 	/* Record data length - make sure we aren't truncated */
+ 
+ 	rdlen = NTOHSP(p);
+ 	INCR_CHECK(p, 2);
+ 
+ 	if (p + rdlen > answer + size)
+ 	    return KRB5_ERR_HOST_REALM_UNKNOWN;
+ 
+ 	/*
+ 	 * If this is a TXT record, return the string.  Note that the
+ 	 * string has a 1-byte length in the front
+ 	 */
+ 
+ 	if (class == C_IN && type == T_TXT) {
+ 	    len = *p++;
+ 	    if (p + len > answer + size)
+ 		return KRB5_ERR_HOST_REALM_UNKNOWN;
+ 	    *realm = malloc(len + 1);
+ 	    if (*realm == NULL)
+ 		return ENOMEM;
+ 	    strncpy(*realm, (char *) p, len);
+ 	    (*realm)[len] = '\0';
+ 	    return 0;
+ 	}
+     }
+ 
+     return KRB5_ERR_HOST_REALM_UNKNOWN;
+ }
+ #endif /* KRB5_DNS_LOOKUP */
+ 
  krb5_error_code
  krb5_get_host_realm(context, host, realmsp)
      krb5_context context;
***************
*** 140,145 ****
--- 252,274 ----
      }
  
      if (realm == (char *)NULL) {
+ #ifdef KRB5_DNS_LOOKUP
+ 	/*
+ 	 * Since this didn't appear in our config file, try looking
+ 	 * it up via DNS.  Look for a TXT records of the form:
+ 	 *
+ 	 * _kerberos.<hostname>
+ 	 * _kerberos.<domainname>
+ 	 *
+ 	 * Note: We only do one domain iteration here.  Is that enough?
+ 	 */
+ 
+ 	retval = krb5_try_realm_txt_rr("_kerberos", host, &realm);
+ 	if (retval && default_realm)
+ 	    retval = krb5_try_realm_txt_rr("_kerberos", default_realm, &realm);
+ 
+ 	if (retval)
+ #endif /* KRB5_DNS_LOOKUP */
  	    if (default_realm != (char *)NULL) {
  		    /* We are defaulting to the realm of the host */
  		    if (!(cp = (char *)malloc(strlen(default_realm)+1)))
Index: lib/krb5/os/localaddr.c
diff -c krb5/lib/krb5/os/localaddr.c:1.1.1.1 krb5/lib/krb5/os/localaddr.c:1.2
*** krb5/lib/krb5/os/localaddr.c:1.1.1.1	Mon Jun  2 17:57:30 1997
--- krb5/lib/krb5/os/localaddr.c	Wed Oct  8 13:17:39 1997
***************
*** 31,35 ****
--- 31,169 ----
      krb5_context context;
      krb5_address ***addr;
  {
+ #ifndef PROXY_ALTERNATE_ADDRS
      return krb5_crypto_os_localaddr(addr);
+ #else /* PROXY_ALTERNATE_ADDRS */
+     int naddrs = 0, nproxies = 0, i, j, n;
+     krb5_address **local_addrs, ***proxy_addrs;
+     const char *proxy_names[3];
+     char **proxylist;
+     krb5_error_code code;
+ 
+     /*
+      * We need to add the IP addresses of any proxies given in the
+      * Kerberos configuration file to the "local" IP address.  First,
+      * let's see if we have any in the configuration file.
+      */
+ 
+     proxy_names[0] = "libdefaults";
+     proxy_names[1] = "proxy_gateway";
+     proxy_names[2] = NULL;
+ 
+     if (profile_get_values(context->profile, proxy_names, &proxylist)) {
+ 	return krb5_crypto_os_localaddr(addr);
+     }
+ 
+     /*
+      * We've got some proxy hosts in the config file.  First, let's figure
+      * out how many we're talking about and total them all up.
+      */
+ 
+     if ((code = krb5_crypto_os_localaddr(&local_addrs))) {
+ 	for (i = 0; proxylist[i]; i++) {
+ 	    free(proxylist[i]);
+ 	}
+ 	free(proxylist);
+ 	return code;
+     }
+ 
+     /*
+      * Total number of addreses for the local host
+      */
+ 
+     while (local_addrs[naddrs]) naddrs++;
+ 
+     /*
+      * Total number of _hosts_ that we're using as possible proxies
+      */
+ 
+     while (proxylist[nproxies]) nproxies++;
+ 
+     proxy_addrs = (krb5_address ***) malloc(sizeof(proxy_addrs) * nproxies);
+ 
+     if (! proxy_addrs) {
+ 	krb5_free_addresses(context, local_addrs);
+ 	for (i = 0; proxylist[i]; i++) {
+ 	    free(proxylist[i]);
+ 	}
+ 	free((char *) proxylist);
+ 	return ENOMEM;
+     }
+ 
+     /*
+      * Get all of the addresses for all of the proxy hosts.  Just total
+      * them all up for now; we need the total number to construct the
+      * address array.
+      */
+ 
+     for (i = 0; i < nproxies; i++) {
+ 
+ 	if (krb5_os_hostaddr(context, proxylist[i], &proxy_addrs[i])) {
+ 		proxy_addrs[i] = NULL;
+ 		continue;
+ 	}
+ 
+ 	for (j = 0; proxy_addrs[i][j]; j++)
+ 		naddrs++;
+ 
+ 	free(proxylist[i]);
+ 
+     }
+ 
+     free((char *) proxylist);
+ 
+     /*
+      * Build the final addresses array, using all of the addresses that
+      * we have.
+      */
+ 
+     *addr = (krb5_address **) malloc(sizeof(krb5_address *) * (naddrs + 1));
+ 
+     if (! *addr) {
+ 	krb5_free_addresses(context, local_addrs);
+ 
+ 	for (i = 0; i < nproxies; i++) {
+ 		if (proxy_addrs[i])
+ 			krb5_free_addresses(context, proxy_addrs[i]);
+ 	}
+ 	free((char *) proxy_addrs);
+ 
+ 	return ENOMEM;
+     }
+ 
+     n = 0;
+ 
+     /*
+      * First, the "real" local addresses.  Note that we only free the
+      * array memory, not the element memory (since we're just assinging
+      * pointers.
+      */
+ 
+     for (i = 0; local_addrs[i]; i++)
+ 	(*addr)[n++] = local_addrs[i];
+ 
+     free((char *) local_addrs);
+ 
+     /*
+      * Next, proxy addresses
+      */
+ 
+     for (i = 0; i < nproxies; i++) {
+ 	if (proxy_addrs[i]) {
+ 	    for (j = 0; proxy_addrs[i][j]; j++)
+ 		(*addr)[n++] = proxy_addrs[i][j];
+ 	    free((char *) proxy_addrs[i]);
+ 	}
+     }
+ 
+     free((char *) proxy_addrs);
+ 
+     /*
+      * Don't forget to NULL-terminate the array
+      */
+ 
+     (*addr)[n] = NULL;
+ 
+     return 0;
+ #endif /* PROXY_ALTERNATE_ADDRS */
  }
Index: lib/krb5/os/locate_kdc.c
diff -c krb5/lib/krb5/os/locate_kdc.c:1.1.1.2 krb5/lib/krb5/os/locate_kdc.c:1.4
*** krb5/lib/krb5/os/locate_kdc.c:1.1.1.2	Wed Feb 25 17:22:14 1998
--- krb5/lib/krb5/os/locate_kdc.c	Fri May 21 10:42:42 1999
***************
*** 27,45 ****
  #define NEED_SOCKETS
  #include "k5-int.h"
  #include <stdio.h>
  
  /*
   * returns count of number of addresses found
   */
  
! krb5_error_code
! krb5_locate_kdc(context, realm, addr_pp, naddrs)
      krb5_context context;
      const krb5_data *realm;
      struct sockaddr **addr_pp;
      int *naddrs;
  {
!     const char	*realm_kdc_names[4];
      char **hostlist, *host, *port, *cp;
      krb5_error_code code;
      int i, j, out, count;
--- 27,54 ----
  #define NEED_SOCKETS
  #include "k5-int.h"
  #include <stdio.h>
+ #ifdef KRB5_DNS_LOOKUP
+ #include <arpa/nameser.h>
+ #include <arpa/inet.h>
+ #include <resolv.h>
+ #ifndef T_SRV
+ #define T_SRV 33
+ #endif /* T_SRV */
+ #endif /* KRB5_DNS_LOOKUP */
  
  /*
   * returns count of number of addresses found
   */
  
! static krb5_error_code
! krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs)
      krb5_context context;
      const krb5_data *realm;
+     const char *name;
      struct sockaddr **addr_pp;
      int *naddrs;
  {
!     const char	*realm_srv_names[4];
      char **hostlist, *host, *port, *cp;
      krb5_error_code code;
      int i, j, out, count;
***************
*** 59,70 ****
      host[realm->length] = '\0';
      hostlist = 0;
      
!     realm_kdc_names[0] = "realms";
!     realm_kdc_names[1] = host;
!     realm_kdc_names[2] = "kdc";
!     realm_kdc_names[3] = 0;
  
!     code = profile_get_values(context->profile, realm_kdc_names, &hostlist);
  
      if (code == PROF_NO_SECTION)
  	return KRB5_REALM_UNKNOWN;
--- 68,81 ----
      host[realm->length] = '\0';
      hostlist = 0;
      
!     realm_srv_names[0] = "realms";
!     realm_srv_names[1] = host;
!     realm_srv_names[2] = name;
!     realm_srv_names[3] = 0;
! 
!     code = profile_get_values(context->profile, realm_srv_names, &hostlist);
  
!     free(host);
  
      if (code == PROF_NO_SECTION)
  	return KRB5_REALM_UNKNOWN;
***************
*** 160,163 ****
--- 171,471 ----
      *addr_pp = addr_p;
      *naddrs = out;
      return 0;
+ }
+ 
+ #ifdef KRB5_DNS_LOOKUP
+ 
+ /*
+  * Lookup a KDC via DNS SRV records
+  */
+ 
+ static krb5_error_code
+ krb5_locate_srv_dns(context, realm, service, protocol, addr_pp, naddrs)
+     krb5_context context;
+     const krb5_data *realm;
+     const char *service;
+     const char *protocol;
+     struct sockaddr **addr_pp;
+     int *naddrs;
+ {
+     krb5_error_code code;
+     int out, j, count;
+     unsigned char answer[2048], *p;
+     char host[256];
+     struct sockaddr *addr = NULL;
+     struct sockaddr_in *sin;
+     struct hostent *hp;
+     int type, class;
+     int status, priority, weight, size, len, numanswers, numqueries, rdlen;
+     unsigned short port;
+     HEADER *hdr;
+     struct srv_dns_entry {
+ 	struct srv_dns_entry *next;
+ 	int priority;
+ 	int weight;
+ 	unsigned short port;
+ 	char *host;
+     };
+ 
+     struct srv_dns_entry *head = NULL;
+     struct srv_dns_entry *srv, *entry;
+ 
+     out = 0;
+     addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
+     if (addr == NULL)
+ 	return ENOMEM;
+ 
+     count = 1;
+ 
+     /*
+      * First off, build a query of the form:
+      *
+      * service.protocol.realm
+      *
+      * which will most likely be something like:
+      *
+      * _kerberos._udp.REALM
+      *
+      */
+ 
+ #ifdef HAVE_SNPRINTF
+     snprintf(host, sizeof(host), "%s.%s.%.*s.", service, protocol,
+ 	     realm->length, realm->data);
+ #else /* HAVE_SNPRINTF */
+     sprintf(host, "%s.%s.%.*s", service, protocol, realm->length,
+ 	    realm->data);
+ #endif /* HAVE_SNPRINTF */
+ 
+     size = res_search(host, C_IN, T_SRV, answer, sizeof(answer));
+ 
+     if (size < sizeof(HEADER))
+ 	goto out;
+ 
+     /*
+      * We got an answer!  First off, parse the header and figure out how
+      * many answers we got back.
+      */
+ 
+     p = answer;
+     hdr = (HEADER *) answer;
+ 
+     numqueries = ntohs(hdr->qdcount);
+     numanswers = ntohs(hdr->ancount);
+ 
+     p += sizeof(HEADER);
+ 
+     /*
+      * We need to skip over all of the questions, so we have to iterate
+      * over every query record.  dn_expand() is able to tell us the size
+      * of compress DNS names, so we use it.
+      */
+ 
+ #define INCR_CHECK(x,y) x += y; if (x > size + answer) goto out
+ #define NTOHSP(x) x[0] << 8 | x[1]
+ 
+     while (numqueries--) {
+ 	len = dn_expand(answer, answer + size, p, host, sizeof(host));
+ 	if (len < 0)
+ 	    goto out;
+ 	INCR_CHECK(p, len + 4);
+     }
+ 
+     /*
+      * We're now pointing at the answer records.  Only process them if
+      * they're actually T_SRV records (they might be CNAME records,
+      * for instance).
+      */
+ 
+     while (numanswers--) {
+ 
+ 	/* First is the name; use dn_expand to get the compressed size */
+ 	len = dn_expand(answer, answer + size, p, host, sizeof(host));
+ 	if (len < 0)
+ 	    goto out;
+ 	INCR_CHECK(p, len);
+ 
+ 	/* Next is the query type */
+ 	type = NTOHSP(p);
+ 	INCR_CHECK(p, 2);
+ 
+ 	/* Next is the query class; also skip over 4 byte TTL */
+ 	class = NTOHSP(p);
+ 	INCR_CHECK(p, 6);
+ 
+ 	/* Record data length */
+ 
+ 	rdlen = NTOHSP(p);
+ 	INCR_CHECK(p, 2);
+ 
+ 	/*
+ 	 * If this is an SRV record, process it.  Record format is:
+ 	 *
+ 	 * Priority
+ 	 * Weight
+ 	 * Port
+ 	 * Server name
+ 	 */
+ 
+ 	if (class == C_IN && type == T_SRV) {
+ 	    priority = NTOHSP(p);
+ 	    INCR_CHECK(p, 2);
+ 	    weight = NTOHSP(p);
+ 	    INCR_CHECK(p, 2);
+ 	    port = NTOHSP(p);
+ 	    INCR_CHECK(p, 2);
+ 	    len = dn_expand(answer, answer + size, p, host, sizeof(host));
+ 	    if (len < 0)
+ 		goto out;
+ 	    INCR_CHECK(p, len);
+ 
+ 	    /*
+ 	     * We got everything!  Insert it into our list, but make sure
+ 	     * it's in the right order.  Right now we don't do anything
+ 	     * with the weight field
+ 	     */
+ 
+ 	    srv = (struct srv_dns_entry *) malloc(sizeof(struct srv_dns_entry));
+ 
+ 	    if (srv == NULL)
+ 		goto out;
+ 	
+ 	    srv->priority = priority;
+ 	    srv->weight = weight;
+ 	    srv->port = port;
+ 	    srv->host = strdup(host);
+ 
+ 	    if (head == NULL || head->priority > srv->priority) {
+ 		srv->next = head;
+ 		head = srv;
+ 	    } else
+ 		/*
+ 		 * This is confusing.  Only insert an entry into this
+ 		 * spot if:
+ 		 * The next person has a higher priority (lower priorities
+ 		 * are preferred).
+ 		 * Or
+ 		 * There is no next entry (we're at the end)
+ 		 */
+ 		for (entry = head; entry != NULL; entry = entry->next)
+ 		    if ((entry->next &&
+ 			 entry->next->priority > srv->priority) ||
+ 			entry->next == NULL) {
+ 			srv->next = entry->next;
+ 			entry->next = srv;
+ 			break;
+ 		    }
+ 	} else
+ 	    INCR_CHECK(p, rdlen);
+     }
+ 	
+     /*
+      * Okay!  Now we've got a linked list of entries sorted by
+      * priority.  Start looking up A records and returning
+      * addresses.
+      */
+ 
+     if (head == NULL)
+ 	goto out;
+ 
+     for (entry = head; entry != NULL; entry = entry->next) {
+ 	
+ 	hp = gethostbyname(entry->host);
+ 	if (hp != 0) {
+ 	    switch (hp->h_addrtype) {
+ #ifdef KRB5_USE_INET
+ 	    case AF_INET:
+ 		for (j=0; hp->h_addr_list[j]; j++) {
+ 		    sin = (struct sockaddr_in *) &addr[out++];
+ 		    memset ((char *) sin, 0, sizeof (struct sockaddr));
+ 		    sin->sin_family = hp->h_addrtype;
+ 		    sin->sin_port = htons(entry->port);
+ 		    memcpy((char *) &sin->sin_addr,
+ 			   (char *) hp->h_addr_list[j],
+ 			   sizeof(struct in_addr));
+ 		    if (out + 1 >= count) {
+ 			count += 5;
+ 			addr = (struct sockaddr *)
+ 				realloc((char *) addr,
+ 					sizeof(struct sockaddr) * count);
+ 			if (!addr)
+ 			    goto out;
+ 		    }
+ 		}
+ 		break;
+ #endif /* KRB5_USE_INET */
+ 	    default:
+ 		break;
+ 	    }
+ 	}
+     }
+ 
+ out:
+     for (entry = head; entry != NULL; ) {
+ 	free(entry->host);
+ 	srv = entry;
+ 	entry = entry->next;
+ 	free(srv);
+     }
+     if (out == 0) {	/* No good servers */
+ 	free(addr);
+ 	return KRB5_REALM_CANT_RESOLVE;
+     }
+ 
+     *addr_pp = addr;
+     *naddrs = out;
+     return 0;
+ }
+ #endif /* KRB5_DNS_LOOKUP */
+ 
+ /*
+  * Wrapper function for the two backends
+  */
+ 
+ krb5_error_code
+ krb5_locate_kdc(context, realm, addr_pp, naddrs)
+     krb5_context context;
+     const krb5_data *realm;
+     struct sockaddr **addr_pp;
+     int *naddrs;
+ {
+     krb5_error_code code;
+ 
+     /*
+      * We always try the local file first
+      */
+ 
+     code = krb5_locate_srv_conf(context, realm, "kdc", addr_pp, naddrs);
+ 
+ #ifdef KRB5_DNS_LOOKUP
+     if (code) {
+ 	code = krb5_locate_srv_dns(context, realm, "_kerberos", "_udp",
+ 				   addr_pp, naddrs);
+     }
+ #endif /* KRB5_DNS_LOOKUP */
+ 
+     return (code);
+ }
+ 
+ /*
+  * It turns out that it is really useful to be able to use these functions
+  * for other things (like admin servers), so create an abstract function
+  * for this
+  */
+ 
+ krb5_error_code
+ krb5_locate_server(context, realm, name, proto, addrs, naddrs)
+     krb5_context context;
+     const krb5_data *realm;
+     const char *name, *proto;
+     void **addrs;
+     int *naddrs;
+ {
+     krb5_error_code code = KRB5_REALM_UNKNOWN;
+ 
+ #ifdef KRB5_DNS_LOOKUP
+     code = krb5_locate_srv_dns(context, realm, name, proto,
+ 			       (struct sockaddr **) addrs, naddrs);
+ #endif /* KRB5_DNS_LOOKUP */
+ 
+     return (code);
  }
Index: lib/krb5/posix/configure.in
diff -c krb5/lib/krb5/posix/configure.in:1.1.1.1 krb5/lib/krb5/posix/configure.in:1.2
*** krb5/lib/krb5/posix/configure.in:1.1.1.1	Mon Jun  2 17:57:32 1997
--- krb5/lib/krb5/posix/configure.in	Tue Jul  8 19:19:24 1997
***************
*** 5,10 ****
  AC_CONST
  AC_HEADER_CHECK(paths.h,AC_DEFINE(HAS_PATHS_H))
  AC_HAVE_FUNCS(setenv unsetenv getenv)
! AC_REPLACE_FUNCS(vfprintf vsprintf strdup strcasecmp strerror memmove daemon getuid sscanf syslog)
  AC_FUNC_CHECK(setsid,AC_DEFINE(HAS_SETSID))
  V5_AC_OUTPUT_MAKEFILE
--- 5,10 ----
  AC_CONST
  AC_HEADER_CHECK(paths.h,AC_DEFINE(HAS_PATHS_H))
  AC_HAVE_FUNCS(setenv unsetenv getenv)
! AC_REPLACE_FUNCS(vfprintf vsprintf strdup strcasecmp strerror memmove daemon getuid sscanf syslog writev)
  AC_FUNC_CHECK(setsid,AC_DEFINE(HAS_SETSID))
  V5_AC_OUTPUT_MAKEFILE
Index: lib/krb5/posix/writev.c
diff -c /dev/null krb5/lib/krb5/posix/writev.c:1.2
*** /dev/null	Thu Sep 23 15:42:00 1999
--- krb5/lib/krb5/posix/writev.c	Tue Oct 28 15:33:54 1997
***************
*** 0 ****
--- 1,24 ----
+ /*
+  * I can't believe there are systems that _don't_ have writev, but I
+  * guess they do exist ...
+  */
+ 
+ #include <stdio.h>
+ 
+ int
+ writev(fd, iov, iovcnt)
+ 	int fd;
+ 	struct iovec *iov;
+ 	int iovcnt;
+ {
+ 	int i, count = 0, ret;
+ 
+ 	for (i = 0; i < iovcnt; i++) {
+ 		ret = write(fd, iov[i].iov_base, iov[i].iov_len);
+ 		if (ret == -1)
+ 			return -1;
+ 		count += ret;
+ 	}
+ 
+ 	return count;
+ }
Index: lib/krb5/rcache/rc_dfl.c
diff -c krb5/lib/krb5/rcache/rc_dfl.c:1.1.1.1 krb5/lib/krb5/rcache/rc_dfl.c:1.2
*** krb5/lib/krb5/rcache/rc_dfl.c:1.1.1.1	Mon Jun  2 17:57:35 1997
--- krb5/lib/krb5/rcache/rc_dfl.c	Thu Mar 19 11:12:31 1998
***************
*** 115,120 ****
--- 115,121 ----
    krb5_rc_iostuff d;
  #endif
    char recovering;
+   char expunging;
   }
  ;
  
***************
*** 287,292 ****
--- 288,294 ----
      t->d.fd = -1;
  #endif
      t->recovering = 0;
+     t->expunging = 0;
      return 0;
      
  cleanup:
***************
*** 459,465 ****
      krb5_rc_free_entry(context, &rep);
      if (retval)
  	krb5_rc_io_close(context, &t->d);
!     else if (expired_entries > EXCESSREPS)
  	retval = krb5_rc_dfl_expunge(context, id);
      t->recovering = 0;
      return retval;
--- 461,467 ----
      krb5_rc_free_entry(context, &rep);
      if (retval)
  	krb5_rc_io_close(context, &t->d);
!     else if (! t->expunging && expired_entries > EXCESSREPS)
  	retval = krb5_rc_dfl_expunge(context, id);
      t->recovering = 0;
      return retval;
***************
*** 578,587 ****
--- 580,591 ----
  	free(name);
  	if (retval)
  	    return retval;
+ 	((struct dfl_data *)id->data)->expunging = 1;
  	retval = krb5_rc_dfl_recover(context, id);
  	if (retval)
  	    return retval;
  	t = (struct dfl_data *)id->data; /* point to recovered cache */
+ 	t->expunging = 0;
      }
  
      tmp = (krb5_rcache) malloc(sizeof(*tmp));
Index: lib/rpc/configure.in
diff -c krb5/lib/rpc/configure.in:1.1.1.1 krb5/lib/rpc/configure.in:1.2
*** krb5/lib/rpc/configure.in:1.1.1.1	Mon Jun  2 17:56:39 1997
--- krb5/lib/rpc/configure.in	Tue Jul  8 19:19:32 1997
***************
*** 48,53 ****
--- 48,56 ----
  AC_CHECK_SIZEOF(long)
  SIZEOF_LONG=$ac_cv_sizeof_long
  AC_SUBST(SIZEOF_LONG)
+ AC_CHECK_SIZEOF(short)
+ SIZEOF_SHORT=$ac_cv_sizeof_short
+ AC_SUBST(SIZEOF_SHORT)
  
  AC_MSG_CHECKING([return type of setrpcent])
  AC_CACHE_VAL(k5_cv_type_setrpcent,
Index: lib/rpc/getrpcent.c
diff -c krb5/lib/rpc/getrpcent.c:1.1.1.1 krb5/lib/rpc/getrpcent.c:1.2
*** krb5/lib/rpc/getrpcent.c:1.1.1.1	Mon Jun  2 17:56:39 1997
--- krb5/lib/rpc/getrpcent.c	Thu Sep 18 16:39:35 1997
***************
*** 116,122 ****
--- 116,127 ----
  
  struct rpcent *
  getrpcbyname(name)
+ #ifdef __convex__
+ 	char *name;
+ #else
  	const char *name;
+ 
+ #endif
  {
  	struct rpcent *rpc;
  	char **rp;
Index: lib/rpc/netdb.h
diff -c krb5/lib/rpc/netdb.h:1.1.1.1 krb5/lib/rpc/netdb.h:1.2
*** krb5/lib/rpc/netdb.h:1.1.1.1	Mon Jun  2 17:56:40 1997
--- krb5/lib/rpc/netdb.h	Thu Sep 18 16:39:37 1997
***************
*** 46,51 ****
--- 46,54 ----
  };
  #endif /*STRUCT_RPCENT_IN_RPC_NETDB_H*/
  
+ #ifndef __convex__
+ /* Convex defines these slightly differently and makes gcc barf	*/
  struct rpcent *getrpcbyname(), *getrpcbynumber(), *getrpcent();
+ #endif
  
  #endif
Index: lib/rpc/svc_auth_gssapi.c
diff -c krb5/lib/rpc/svc_auth_gssapi.c:1.1.1.2 krb5/lib/rpc/svc_auth_gssapi.c:1.3
*** krb5/lib/rpc/svc_auth_gssapi.c:1.1.1.2	Mon Nov  3 16:40:28 1997
--- krb5/lib/rpc/svc_auth_gssapi.c	Mon Nov  3 17:14:53 1997
***************
*** 5,10 ****
--- 5,13 ----
   * $Source$
   * 
   * $Log$
+  * Revision 1.3  1997/11/03 22:14:53  kenh
+  * Fix up conflicts from Release 1.0.2 import.
+  *
   * Revision 1.1.1.2  1997/11/03 21:40:28  kenh
   * Import of Kerberos 5, Release 1.0.2
   *
Index: util/makeshlib.sh
diff -c krb5/util/makeshlib.sh:1.1.1.1 krb5/util/makeshlib.sh:1.2
*** krb5/util/makeshlib.sh:1.1.1.1	Mon Jun  2 17:58:07 1997
--- krb5/util/makeshlib.sh	Thu Jun 12 00:03:32 1997
***************
*** 156,162 ****
--- 156,171 ----
  	ld -shared -expect_unresolved \* $ldflags -o $library -all $FILES $libdirfl $liblist -none -lc -update_registry ../../so_locations
  	stat=$?
  	;;
+ mips-*-irix*)
+ 	FILES=`for i 
+ 	do
+ 		sed -e "s;^;$i/;" -e "s; ; $i/;g" $i/DONE
+ 	done`
  
+ 	echo ld -shared -rdata_shared $ldflags -o $library $optflags $FILES $libdirfl $liblist
+ 	ld -shared -rdata_shared $ldflags -o $library $optflags $FILES $libdirfl $liblist
+ 	stat=$?
+ 	;;
  *)
  	echo "Host type $host not supported!"
  	exit 1
Index: util/db2/acconfig.h
diff -c krb5/util/db2/acconfig.h:1.1.1.1 krb5/util/db2/acconfig.h:1.2
*** krb5/util/db2/acconfig.h:1.1.1.1	Mon Jun  2 17:58:08 1997
--- krb5/util/db2/acconfig.h	Wed Aug 13 16:57:31 1997
***************
*** 15,17 ****
--- 15,20 ----
  #undef u_int16_t
  #undef int32_t
  #undef u_int32_t
+ 
+ /* Define if we're using a btree database for the KDC */
+ #undef USE_BTREE
Index: util/db2/configure.in
diff -c krb5/util/db2/configure.in:1.1.1.1 krb5/util/db2/configure.in:1.3
*** krb5/util/db2/configure.in:1.1.1.1	Mon Jun  2 17:58:08 1997
--- krb5/util/db2/configure.in	Wed Aug 13 16:57:33 1997
***************
*** 1,6 ****
--- 1,7 ----
  dnl Process this file with autoconf to produce a configure script.
  AC_INIT(db/db.c)
  AC_CONFIG_HEADER(obj/db-config.h)
+ CONFIG_RULES
  dnl checks for programs
  AC_PROG_CC
  AC_PROG_RANLIB
***************
*** 9,14 ****
--- 10,20 ----
  AC_PATH_PROG(SH,sh,$FALSE)
  AC_PATH_PROG(SH5,sh5,$FALSE)
  AC_PATH_PROG(BASH,bash,$FALSE)
+ 
+ AC_ARG_ENABLE([btree-db],
+ [  --enable-btree-db       Use btree-format database for KDC],[
+ echo "Using btree-style database for KDC"
+ AC_DEFINE(USE_BTREE)])
  
  AC_CACHE_CHECK([checking for shell with functions],local_cv_program_fctsh,
  [if $SH -c 'foo() { true; }; foo' > /dev/null 2>&1; then
Index: util/db2/hash/dbm.c
diff -c krb5/util/db2/hash/dbm.c:1.1.1.2 krb5/util/db2/hash/dbm.c:1.3
*** krb5/util/db2/hash/dbm.c:1.1.1.2	Wed Feb 25 17:26:10 1998
--- krb5/util/db2/hash/dbm.c	Thu Feb 26 11:38:38 1998
***************
*** 47,53 ****
--- 47,57 ----
  #include <string.h>
  
  #include "db-ndbm.h"
+ #ifdef USE_BTREE
+ #include "btree.h"
+ #else
  #include "hash.h"
+ #endif /* USE_BTREE */
  
  /* If the two size fields of datum and DBMT are not equal, then
   * casting between structures will result in stack garbage being
***************
*** 159,176 ****
  	const char *file;
  	int flags, mode;
  {
  	HASHINFO info;
  	char path[MAXPATHLEN];
  
! 	info.bsize = 4096;
  	info.ffactor = 40;
  	info.nelem = 1;
  	info.cachesize = 0;
  	info.hash = NULL;
  	info.lorder = 0;
  	(void)strcpy(path, file);
  	(void)strcat(path, DBM_SUFFIX);
  	return ((DBM *)__hash_open(path, flags, mode, &info, 0));
  }
  
  /*
--- 163,191 ----
  	const char *file;
  	int flags, mode;
  {
+ #ifdef USE_BTREE
+ 	BTREEINFO info;
+ #else
  	HASHINFO info;
+ #endif /* USE_BTREE */
  	char path[MAXPATHLEN];
  
! #ifndef USE_BTREE
! 	/* initial values for hash */
! 	info.bsize = 8192;
  	info.ffactor = 40;
  	info.nelem = 1;
  	info.cachesize = 0;
  	info.hash = NULL;
  	info.lorder = 0;
+ #endif
  	(void)strcpy(path, file);
  	(void)strcat(path, DBM_SUFFIX);
+ #ifdef USE_BTREE
+ 	return ((DBM *)__bt_open(path, flags, mode, 0/*&info*/, 0));
+ #else
  	return ((DBM *)__hash_open(path, flags, mode, &info, 0));
+ #endif
  }
  
  /*
***************
*** 269,274 ****
--- 284,390 ----
  
  /*
   * Returns:
+  *	DATUM on success
+  *	NULL on failure
+  * 
+  * This is only sensical for an ordered DB2 access method (like Btree).
+  */
+ datum
+ dbm_lastkey(db)
+ 	DBM *db;
+ {
+ 	int status;
+ 	datum retdata, retkey;
+ 
+ #ifdef USE_BTREE
+ #ifdef NEED_COPY
+ 	DBT k, r;
+ 
+ 	status = (db->seq)(db, &k, &r, R_LAST);
+ 	retkey.dptr = k.data;
+ 	retkey.dsize = k.size;
+ #else
+ 	status = (db->seq)(db, (DBT *)&retkey, (DBT *)&retdata, R_:AST);
+ #endif /* NEED_COPY */
+ 	if (status)
+ 		retkey.dptr = NULL;
+ #else /* USE_BTREE */
+ 	retkey.dptr = NULL;
+ #endif /* USE_BTREE */
+ 	return (retkey);
+ }
+ 
+ /*
+  * Returns:
+  *	DATUM on success
+  *	NULL on failure
+  *
+  * This is only sensical for an ordered DB2 access method (like Btree).
+  */
+ datum
+ dbm_prevkey(db)
+ 	DBM *db;
+ {
+ 	int status;
+ 	datum retdata, retkey;
+ 
+ #ifdef USE_BTREE
+ #ifdef NEED_COPY
+ 	DBT k, r;
+ 
+ 	status = (db->seq)(db, &k, &r, R_PREV);
+ 	retkey.dptr = k.data;
+ 	retkey.dsize = k.size;
+ #else
+ 	status = (db->seq)(db, (DBT *)&retkey, (DBT *)&retdata, R_PREV);
+ #endif /* NEED_COPY */
+ 	if (status)
+ 		retkey.dptr = NULL;
+ #else
+ 	retkey.dptr = NULL;
+ #endif /* USE_BTREE */
+ 	return (retkey);
+ }
+ 
+ /*
+  * Returns:
+  *	DATUM on success
+  *	NULL on failure
+  *
+  * This is only sensical for an ordered DB2 access method (like Btree).
+  */
+ datum
+ dbm_startkey(db, key)
+ 	DBM *db;
+ 	datum key;
+ {
+ 	datum retval;
+ 	int status;
+ 
+ #ifdef USE_BTREE
+ #ifdef NEED_COPY
+ 	DBT k, r;
+ 
+ 	k.data = key.dptr;
+ 	k.size = key.dsize;
+ 	status = (db->seq)(db, &k, &r, R_CURSOR);
+ 	retval.dptr = r.data;
+ 	retval.dsize = r.size;
+ #else
+ 	status = (db->seq)(db, (DBT *)&key, (DBT *)&retval, R_CURSOR);
+ #endif
+ 	if (status) {
+ 		retval.dptr = NULL;
+ 		retval.dsize = 0;
+ 	}
+ #else
+ 	retval.dptr = NULL;
+ #endif /* USE_BTREE */
+ 	return (retval);
+ }
+ 
+ /*
+  * Returns:
   *	 0 on success
   *	<0 failure
   */
***************
*** 325,344 ****
--- 441,468 ----
  dbm_error(db)
  	DBM *db;
  {
+ #ifndef USE_BTREE
  	HTAB *hp;
  
  	hp = (HTAB *)db->internal;
  	return (hp->local_errno);
+ #else
+ 	return errno;
+ #endif
  }
  
  int
  dbm_clearerr(db)
  	DBM *db;
  {
+ #ifndef USE_BTREE
  	HTAB *hp;
  
  	hp = (HTAB *)db->internal;
  	hp->local_errno = 0;
+ #else
+ 	errno = 0;
+ #endif
  	return (0);
  }
  
***************
*** 346,350 ****
--- 470,478 ----
  dbm_dirfno(db)
  	DBM *db;
  {
+ #ifndef USE_BTREE
  	return(((HTAB *)db->internal)->fp);
+ #else
+ 	return(((BTREE *)db->internal)->bt_fd);
+ #endif
  }
Index: util/db2/hash/hash.c
diff -c krb5/util/db2/hash/hash.c:1.1.1.2 krb5/util/db2/hash/hash.c:1.3
*** krb5/util/db2/hash/hash.c:1.1.1.2	Wed Feb 25 17:26:11 1998
--- krb5/util/db2/hash/hash.c	Thu Feb 26 11:38:38 1998
***************
*** 96,102 ****
  extern DB *
  __hash_open(file, flags, mode, info, dflags)
  	const char *file;
! 	int32_t flags, mode, dflags;
  	const HASHINFO *info;	/* Special directives for create */
  {
  	struct stat statbuf;
--- 96,102 ----
  extern DB *
  __hash_open(file, flags, mode, info, dflags)
  	const char *file;
! 	int flags, mode, dflags;
  	const HASHINFO *info;	/* Special directives for create */
  {
  	struct stat statbuf;
Index: util/db2/hash/hash_bigkey.c
diff -c krb5/util/db2/hash/hash_bigkey.c:1.1.1.1 krb5/util/db2/hash/hash_bigkey.c:1.2
*** krb5/util/db2/hash/hash_bigkey.c:1.1.1.1	Mon Jun  2 17:58:17 1997
--- krb5/util/db2/hash/hash_bigkey.c	Wed Aug 13 16:57:46 1997
***************
*** 386,392 ****
  		totlen = len + BIGKEYLEN(pagep);
  		if (hashp->bigkey_buf)
  			free(hashp->bigkey_buf);
! 		hashp->bigkey_buf = (char *)malloc(totlen);
  		if (!hashp->bigkey_buf)
  			return (-1);
  		memcpy(hashp->bigkey_buf + len,
--- 386,392 ----
  		totlen = len + BIGKEYLEN(pagep);
  		if (hashp->bigkey_buf)
  			free(hashp->bigkey_buf);
! 		hashp->bigkey_buf = (u_int8_t *)malloc(totlen);
  		if (!hashp->bigkey_buf)
  			return (-1);
  		memcpy(hashp->bigkey_buf + len,
***************
*** 400,406 ****
  	if (BIGKEYLEN(pagep) == 0) {
  		if (hashp->bigkey_buf)
  			free(hashp->bigkey_buf);
! 		hashp->bigkey_buf = (char *)malloc(len);
  		return (hashp->bigkey_buf ? len : -1);
  	}
  	totlen = len + BIGKEYLEN(pagep);
--- 400,406 ----
  	if (BIGKEYLEN(pagep) == 0) {
  		if (hashp->bigkey_buf)
  			free(hashp->bigkey_buf);
! 		hashp->bigkey_buf = (u_int8_t *)malloc(len);
  		return (hashp->bigkey_buf ? len : -1);
  	}
  	totlen = len + BIGKEYLEN(pagep);
***************
*** 453,459 ****
  		if (hashp->bigdata_buf)
  			free(hashp->bigdata_buf);
  		totlen = len + BIGDATALEN(pagep);
! 		hashp->bigdata_buf = (char *)malloc(totlen);
  		if (!hashp->bigdata_buf)
  			return (-1);
  		memcpy(hashp->bigdata_buf + totlen - BIGDATALEN(pagep),
--- 453,459 ----
  		if (hashp->bigdata_buf)
  			free(hashp->bigdata_buf);
  		totlen = len + BIGDATALEN(pagep);
! 		hashp->bigdata_buf = (u_int8_t *)malloc(totlen);
  		if (!hashp->bigdata_buf)
  			return (-1);
  		memcpy(hashp->bigdata_buf + totlen - BIGDATALEN(pagep),
Index: util/db2/include/db-ndbm.h
diff -c krb5/util/db2/include/db-ndbm.h:1.1.1.1 krb5/util/db2/include/db-ndbm.h:1.2
*** krb5/util/db2/include/db-ndbm.h:1.1.1.1	Mon Jun  2 17:58:19 1997
--- krb5/util/db2/include/db-ndbm.h	Wed Aug 13 16:57:51 1997
***************
*** 74,79 ****
--- 74,84 ----
  int	 dbm_dirfno __P((DBM *));
  int	 dbm_error __P((DBM *db));
  int	 dbm_clearerr __P((DBM *db));
+ /* The following functions are only valid for Btree-accessed DB2
+    impementations. */
+ datum	 dbm_startkey __P((DBM *, datum));
+ datum	 dbm_lastkey __P((DBM *));
+ datum	 dbm_prevkey __P((DBM *));
  __END_DECLS
  
  #endif /* !_NDBM_H_ */
Index: util/db2/obj/Makefile.in
diff -c krb5/util/db2/obj/Makefile.in:1.1.1.1 krb5/util/db2/obj/Makefile.in:1.2
*** krb5/util/db2/obj/Makefile.in:1.1.1.1	Mon Jun  2 17:58:21 1997
--- krb5/util/db2/obj/Makefile.in	Wed Jun  3 12:13:28 1998
***************
*** 47,52 ****
--- 47,53 ----
  	$(RANLIB) $@
  
  db.h: $(top_srcdir)/include/db.h
+ 	rm -f db.h
  	ln -s $(top_srcdir)/include/db.h .
  
  dbtest: dbtest.o $(STRERROR_OBJ) $(LIBDB)
Index: util/dyn/Makefile.in
diff -c krb5/util/dyn/Makefile.in:1.1.1.1 krb5/util/dyn/Makefile.in:1.2
*** krb5/util/dyn/Makefile.in:1.1.1.1	Mon Jun  2 17:58:47 1997
--- krb5/util/dyn/Makefile.in	Fri May 21 10:43:19 1999
***************
*** 32,37 ****
--- 32,39 ----
  LIB_SUBDIRS= .
  LIBDONE= DONE
  
+ SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@
+ 
  all-unix:: shared includes $(OBJS)
  all-mac:: $(OBJS)
  all-windows:: $(OBJS)
Index: util/pty/configure.in
diff -c krb5/util/pty/configure.in:1.1.1.1 krb5/util/pty/configure.in:1.2
*** krb5/util/pty/configure.in:1.1.1.1	Mon Jun  2 17:58:57 1997
--- krb5/util/pty/configure.in	Fri May  1 12:16:41 1998
***************
*** 45,50 ****
--- 45,56 ----
  *-*-hpux*)
       krb5_cv_has_streams=no
       ;;
+ *-*-linux-gnu)
+ 	# setutent() and ttyslot() don't do the right thing under linux
+ 	# (or Redhat at least)
+ 	ac_cv_func_setutent=no
+      AC_DEFINE(TTYSLOT_BROKEN)
+      ;;
  esac
  dnl
  AC_SUBST(LOGINLIBS)
Index: util/pty/update_utmp.c
diff -c krb5/util/pty/update_utmp.c:1.1.1.2 krb5/util/pty/update_utmp.c:1.8
*** krb5/util/pty/update_utmp.c:1.1.1.2	Wed May 12 13:26:57 1999
--- krb5/util/pty/update_utmp.c	Thu Jun  3 15:15:19 1999
***************
*** 84,95 ****
  
  #ifndef NO_UT_PID
      if (!strcmp (line, "/dev/console"))
        strncpy (ent.ut_id, "cons", 4);
      else {
        tmpx = line + strlen(line)-1;
        if (*(tmpx-1) != '/') tmpx--; /* last two characters, unless it's a / */
! #ifdef __hpux
        strcpy(utmp_id, tmpx);
  #else
        sprintf(utmp_id, "kl%s", tmpx);
  #endif
--- 84,102 ----
  
  #ifndef NO_UT_PID
      if (!strcmp (line, "/dev/console"))
+ #if defined(__sun) && defined(__SVR4)
+       strncpy (ent.ut_id, "co", 2);
+ #else
        strncpy (ent.ut_id, "cons", 4);
+ #endif
      else {
        tmpx = line + strlen(line)-1;
        if (*(tmpx-1) != '/') tmpx--; /* last two characters, unless it's a / */
! #if defined(__hpux) || defined(__linux__)
        strcpy(utmp_id, tmpx);
+ #elif defined(sgi)
+       /* Everything after '/dev/tty/' */
+       strcpy(utmp_id, line + 8);   /* 8 == strlen("/dev/tty"); */
  #else
        sprintf(utmp_id, "kl%s", tmpx);
  #endif
***************
*** 131,136 ****
--- 138,146 ----
      setutxent();
  #ifdef HAVE_GETUTMPX
      getutmpx(&ent, &utx);
+ #if defined(sgi)
+     utx.ut_pid = pid;
+ #endif /* sgi */
  #else
      /* For platforms like HPUX and Dec Unix which don't have getutmpx */
      strncpy(utx.ut_user, ent.ut_user, sizeof(ent.ut_user));
***************
*** 138,143 ****
--- 148,154 ----
      strncpy(utx.ut_line, ent.ut_line, sizeof(ent.ut_line));
      utx.ut_pid = pid;		/* kludge for Irix, etc. to avoid trunc. */
      utx.ut_type = ent.ut_type;
+ #ifndef NO_UTX_EXIT
  #ifdef UT_EXIT_STRUCTURE_DIFFER
      utx.ut_exit.ut_exit = ent.ut_exit.e_exit;
  #else
***************
*** 149,154 ****
--- 160,166 ----
      /*xxx do nothing for now; we don't even know the structure member exists*/
  #endif
  #endif
+ #endif /* !NO_UTX_EXIT */
      utx.ut_tv.tv_sec = ent.ut_time;
      utx.ut_tv.tv_usec = 0;
  #endif
***************
*** 161,169 ****
  #endif /* HAVE_SETUTXENT */
  
  #else /* HAVE_SETUTENT */
!     if (flags&PTY_TTYSLOT_USABLE) 
  	tty = ttyslot();
!     else {
        int lc;
        tty = -1;
        if ((fd = open(UTMP_FILE, O_RDWR)) < 0)
--- 173,185 ----
  #endif /* HAVE_SETUTXENT */
  
  #else /* HAVE_SETUTENT */
! 
! #ifndef TTYSLOT_BROKEN
!     if (flags&PTY_TTYSLOT_USABLE)
  	tty = ttyslot();
!      else
! #endif
!       {
        int lc;
        tty = -1;
        if ((fd = open(UTMP_FILE, O_RDWR)) < 0)
***************
*** 183,190 ****
--- 199,215 ----
  	}
        }
        close(fd);
+ 
+ #ifdef TTYSLOT_BROKEN
+       /*
+        * If we're find a usable slot and didn't come across one, then append.
+        */
+       if ((flags & PTY_TTYSLOT_USABLE) && (tty == -1))
+ 	tty = lc;
+ #endif
      }
      
+     /* I think this should be 'tty != -1'? */
      if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) {
        (void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
        (void)write(fd, (char *)&ent, sizeof(struct utmp));
