Subject: Collected Debian patches for OpenAFS
Author: Russ Allbery <rra@debian.org>

The packaging for OpenAFS is maintained in Git with no Debian-specific
patches, just cherry-picks from upstream (possibly from upstream Gerrit).
This makes it complex to separate the changes into individual patches.
They are therefore all included in a single Debian patch.

For full commit history and separated commits, see the packaging Git
repository.
--- openafs-1.6.1.orig/acinclude.m4
+++ openafs-1.6.1/acinclude.m4
@@ -793,6 +793,7 @@ case $AFS_SYSNAME in *_linux* | *_umlinu
 		 AC_CHECK_LINUX_STRUCT([backing_dev_info], [name],
 				       [backing-dev.h])
 		 AC_CHECK_LINUX_STRUCT([ctl_table], [ctl_name], [sysctl.h])
+		 AC_CHECK_LINUX_STRUCT([dentry], [d_u.d_alias], [dcache.h])
 		 AC_CHECK_LINUX_STRUCT([inode], [i_alloc_sem], [fs.h])
 		 AC_CHECK_LINUX_STRUCT([inode], [i_blkbits], [fs.h])
 		 AC_CHECK_LINUX_STRUCT([inode], [i_blksize], [fs.h])
--- openafs-1.6.1.orig/configure.ac
+++ openafs-1.6.1/configure.ac
@@ -50,14 +50,20 @@ MAKE_KRB5="#"
 AS_IF([test x"$KRB5_LIBS" != x],
     [BUILD_KRB5=yes
      MAKE_KRB5=
+     AC_DEFINE([USE_RXKAD_KEYTAB], 1,
+	       [Define to 1 if krb5 libraries are available and rxkad can use keytabs])
      RRA_LIB_KRB5_SWITCH
      AC_CHECK_FUNCS([add_error_table \
         add_to_error_table \
         encode_krb5_enc_tkt_part \
         encode_krb5_ticket \
         krb5_allow_weak_crypto \
+        krb5_c_decrypt \
         krb5_c_encrypt \
+        krb5_crypto_init \
         krb5_decode_ticket \
+        krb5_decrypt_tkt_part \
+        krb5_encrypt_tkt_part \
         krb5_enctype_enable \
         krb5_get_init_creds_opt_alloc \
         krb5_get_prompt_types \
@@ -72,8 +78,13 @@ AS_IF([test x"$KRB5_LIBS" != x],
                      [Define to 1 if you have the `krb524_convert_creds_kdc' function.])])])])
      AC_CHECK_HEADERS([kerberosIV/krb.h])
      AC_CHECK_HEADERS([kerberosV/heim_err.h])
-     AC_CHECK_MEMBERS([krb5_creds.keyblock, krb5_creds.keyblock.enctype, krb5_creds.session,
-                       krb5_prompt.type], , , [#include <krb5.h>])
+     AC_CHECK_MEMBERS([krb5_creds.keyblock, krb5_creds.keyblock.enctype,
+		       krb5_creds.session, krb5_keytab_entry.key,
+		       krb5_keytab_entry.keyblock, krb5_keyblock.enctype,
+		       krb5_keyblock.keytype, krb5_prompt.type], , ,
+		       [#include <krb5.h>])
+     AC_CHECK_DECLS([krb5_free_keytab_entry_contents, krb5_kt_free_entry,
+		    KRB5_KU_TICKET], [], [], [#include <krb5.h>])
      RRA_LIB_KRB5_RESTORE])
 AC_SUBST([BUILD_KRB5])
 AC_SUBST([MAKE_KRB5])
--- openafs-1.6.1.orig/src/afs/LINUX/osi_compat.h
+++ openafs-1.6.1/src/afs/LINUX/osi_compat.h
@@ -27,6 +27,10 @@
 # endif
 #endif
 
+#if defined(STRUCT_DENTRY_HAS_D_U_D_ALIAS)
+# define d_alias d_u.d_alias
+#endif
+
 #ifndef HAVE_LINUX_DO_SYNC_READ
 static inline int
 do_sync_read(struct file *fp, char *buf, size_t count, loff_t *offp) {
--- openafs-1.6.1.orig/src/afs/LINUX/osi_prototypes.h
+++ openafs-1.6.1/src/afs/LINUX/osi_prototypes.h
@@ -79,6 +79,9 @@ extern void osi_VM_FlushPages(struct vca
 extern void osi_VM_Truncate(struct vcache *avc, int alen,
 			    afs_ucred_t *acred);
 
+/* osi_vcache.c */
+extern void osi_ResetRootVCache(afs_uint32 volid);
+
 /* osi_vfsops.c */
 extern void vattr2inode(struct inode *ip, struct vattr *vp);
 extern int afs_init_inodecache(void);
--- openafs-1.6.1.orig/src/afs/LINUX/osi_vcache.c
+++ openafs-1.6.1/src/afs/LINUX/osi_vcache.c
@@ -13,6 +13,8 @@
 #include "afs/sysincludes.h"    /*Standard vendor system headers */
 #include "afsincludes.h"        /*AFS-based standard headers */
 
+#include "osi_compat.h"
+
 int
 osi_TryEvictVCache(struct vcache *avc, int *slept, int defersleep) {
     int code;
@@ -139,3 +141,64 @@ osi_PostPopulateVCache(struct vcache *av
     vSetType(avc, VREG);
 }
 
+/**
+ * osi_ResetRootVCache - Reset the root vcache
+ * Reset the dentry associated with the afs root.
+ * Called from afs_CheckRootVolume when we notice that
+ * the root volume ID has changed.
+ *
+ * @volid: volume ID for the afs root
+ */
+void
+osi_ResetRootVCache(afs_uint32 volid)
+{
+    struct vrequest *treq = NULL;
+    struct vattr vattr;
+    cred_t *credp;
+    struct dentry *dp;
+    struct vcache *vcp;
+    struct inode *root = AFSTOV(afs_globalVp);
+
+    afs_rootFid.Fid.Volume = volid;
+    afs_rootFid.Fid.Vnode = 1;
+    afs_rootFid.Fid.Unique = 1;
+
+    credp = crref();
+    if (afs_CreateReq(&treq, credp))
+	goto out;
+    vcp = afs_GetVCache(&afs_rootFid, treq, NULL, NULL);
+    if (!vcp)
+	goto out;
+    afs_getattr(vcp, &vattr, credp);
+    afs_fill_inode(AFSTOV(vcp), &vattr);
+
+    dp = d_find_alias(root);
+
+#if defined(HAVE_DCACHE_LOCK)
+    spin_lock(&dcache_lock);
+#else
+    spin_lock(&AFSTOV(vcp)->i_lock);
+#endif
+    spin_lock(&dp->d_lock);
+#if defined(D_ALIAS_IS_HLIST)
+    hlist_del_init(&dp->d_alias);
+    hlist_add_head(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
+#else
+    list_del_init(&dp->d_alias);
+    list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
+#endif
+    dp->d_inode = AFSTOV(vcp);
+    spin_unlock(&dp->d_lock);
+#if defined(HAVE_DCACHE_LOCK)
+    spin_unlock(&dcache_lock);
+#else
+    spin_unlock(&AFSTOV(vcp)->i_lock);
+#endif
+    dput(dp);
+
+    AFS_RELE(root);
+    afs_globalVp = vcp;
+out:
+    crfree(credp);
+    afs_DestroyReq(treq);
+}
--- openafs-1.6.1.orig/src/afs/LINUX24/osi_prototypes.h
+++ openafs-1.6.1/src/afs/LINUX24/osi_prototypes.h
@@ -69,6 +69,9 @@ extern void osi_syscall_clean(void);
 extern int osi_sysctl_init(void);
 extern void osi_sysctl_clean(void);
 
+/* osi_vcache.c */
+extern void osi_ResetRootVCache(afs_uint32 volid);
+
 /* osi_vm.c */
 extern int osi_VM_FlushVCache(struct vcache *avc, int *slept);
 extern void osi_VM_TryToSmush(struct vcache *avc, afs_ucred_t *acred,
--- openafs-1.6.1.orig/src/afs/LINUX24/osi_vcache.c
+++ openafs-1.6.1/src/afs/LINUX24/osi_vcache.c
@@ -118,3 +118,39 @@ osi_PostPopulateVCache(struct vcache *av
     vSetType(avc, VREG);
 }
 
+void
+osi_ResetRootVCache(afs_uint32 volid)
+{
+    struct vrequest *treq = NULL;
+    struct vattr vattr;
+    cred_t *credp;
+    struct dentry *dp;
+    struct vcache *vcp;
+
+    afs_rootFid.Fid.Volume = volid;
+    afs_rootFid.Fid.Vnode = 1;
+    afs_rootFid.Fid.Unique = 1;
+
+    credp = crref();
+    if (afs_CreateReq(&treq, credp))
+	goto out;
+    vcp = afs_GetVCache(&afs_rootFid, treq, NULL, NULL);
+    if (!vcp)
+	goto out;
+    afs_getattr(vcp, &vattr, credp);
+    afs_fill_inode(AFSTOV(vcp), &vattr);
+
+    dp = d_find_alias(AFSTOV(afs_globalVp));
+    spin_lock(&dcache_lock);
+    list_del_init(&dp->d_alias);
+    list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
+    dp->d_inode = AFSTOV(vcp);
+    spin_unlock(&dcache_lock);
+    dput(dp);
+
+    AFS_FAST_RELE(afs_globalVp);
+    afs_globalVp = vcp;
+out:
+    crfree(credp);
+    afs_DestroyReq(treq);
+}
--- openafs-1.6.1.orig/src/afs/afs_daemons.c
+++ openafs-1.6.1/src/afs/afs_daemons.c
@@ -363,65 +363,14 @@ afs_CheckRootVolume(void)
 		 * count to zero and fs checkv is executed when the current
 		 * directory is /afs.
 		 */
-#ifdef AFS_LINUX20_ENV
-		{
-		    struct vrequest treq;
-		    struct vattr vattr;
-		    cred_t *credp;
-		    struct dentry *dp;
-		    struct vcache *vcp;
-
-		    afs_rootFid.Fid.Volume = volid;
-		    afs_rootFid.Fid.Vnode = 1;
-		    afs_rootFid.Fid.Unique = 1;
-
-		    credp = crref();
-		    if (afs_InitReq(&treq, credp))
-			goto out;
-		    vcp = afs_GetVCache(&afs_rootFid, &treq, NULL, NULL);
-		    if (!vcp)
-			goto out;
-		    afs_getattr(vcp, &vattr, credp);
-		    afs_fill_inode(AFSTOV(vcp), &vattr);
-
-		    dp = d_find_alias(AFSTOV(afs_globalVp));
-
-#if defined(AFS_LINUX24_ENV)
-#if defined(HAVE_DCACHE_LOCK)
-		    spin_lock(&dcache_lock);
+#ifdef AFS_LINUX22_ENV
+		osi_ResetRootVCache(volid);
 #else
-		    spin_lock(&AFSTOV(vcp)->i_lock);
-#endif
-#if defined(AFS_LINUX26_ENV)
-		    spin_lock(&dp->d_lock);
-#endif
-#endif
-		    list_del_init(&dp->d_alias);
-		    list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
-		    dp->d_inode = AFSTOV(vcp);
-#if defined(AFS_LINUX24_ENV)
-#if defined(AFS_LINUX26_ENV)
-		    spin_unlock(&dp->d_lock);
-#endif
-#if defined(HAVE_DCACHE_LOCK)
-		    spin_unlock(&dcache_lock);
-#else
-		    spin_unlock(&AFSTOV(vcp)->i_lock);
-#endif
-#endif
-		    dput(dp);
-
-		    AFS_FAST_RELE(afs_globalVp);
-		    afs_globalVp = vcp;
-		out:
-		    crfree(credp);
-		}
-#else
-#ifdef AFS_DARWIN80_ENV
+# ifdef AFS_DARWIN80_ENV
 		afs_PutVCache(afs_globalVp);
-#else
+# else
 		AFS_FAST_RELE(afs_globalVp);
-#endif
+# endif
 		afs_globalVp = 0;
 #endif
 	    }
--- openafs-1.6.1.orig/src/afs/afs_osi_pag.c
+++ openafs-1.6.1/src/afs/afs_osi_pag.c
@@ -487,6 +487,64 @@ afs_InitReq(struct vrequest *av, afs_ucr
     return 0;
 }
 
+/*!
+ * Allocate and setup a vrequest.
+ *
+ * \note The caller must free the allocated vrequest with
+ *       afs_DestroyReq() if this function returns successfully (zero).
+ *
+ * \note The GLOCK must be held on platforms which require the GLOCK
+ *       for osi_AllocSmallSpace() and osi_FreeSmallSpace().
+ *
+ * \param[out] avpp   address of the vrequest pointer
+ * \param[in]  acred  user credentials to setup the vrequest; may be NULL
+ * \return     0 on success
+ */
+int
+afs_CreateReq(struct vrequest **avpp, afs_ucred_t *acred)
+{
+    int code;
+    struct vrequest *treq = NULL;
+
+    if (afs_shuttingdown) {
+	return EIO;
+    }
+    if (!avpp) {
+	return EINVAL;
+    }
+    treq = osi_AllocSmallSpace(sizeof(struct vrequest));
+    if (!treq) {
+	return ENOMEM;
+    }
+    if (!acred) {
+	memset(treq, 0, sizeof(struct vrequest));
+    } else {
+	code = afs_InitReq(treq, acred);
+	if (code != 0) {
+	    osi_FreeSmallSpace(treq);
+	    return code;
+	}
+    }
+    *avpp = treq;
+    return 0;
+}
+
+/*!
+ * Deallocate a vrequest.
+ *
+ * \note The GLOCK must be held on platforms which require the GLOCK
+ *       for osi_FreeSmallSpace().
+ *
+ * \param[in]  av  pointer to the vrequest to free; may be NULL
+ */
+void
+afs_DestroyReq(struct vrequest *av)
+{
+    if (av) {
+	osi_FreeSmallSpace(av);
+    }
+}
+
 #ifndef AFS_LINUX26_ONEGROUP_ENV
 afs_uint32
 afs_get_pag_from_groups(gid_t g0a, gid_t g1a)
--- openafs-1.6.1.orig/src/afs/afs_pioctl.c
+++ openafs-1.6.1/src/afs/afs_pioctl.c
@@ -53,8 +53,9 @@ struct afs_pdata {
 static_inline int
 afs_pd_alloc(struct afs_pdata *apd, size_t size)
 {
-
-    if (size > AFS_LRALLOCSIZ)
+    /* Ensure that we give caller at least one trailing guard byte
+     * for the NUL terminator. */
+    if (size >= AFS_LRALLOCSIZ)
 	apd->ptr = osi_Alloc(size + 1);
     else
 	apd->ptr = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
@@ -62,6 +63,13 @@ afs_pd_alloc(struct afs_pdata *apd, size
     if (apd->ptr == NULL)
 	return ENOMEM;
 
+    /* Clear it all now, including the guard byte. */
+    if (size >= AFS_LRALLOCSIZ)
+	memset(apd->ptr, 0, size + 1);
+    else
+	memset(apd->ptr, 0, AFS_LRALLOCSIZ);
+
+    /* Don't tell the caller about the guard byte. */
     apd->remaining = size;
 
     return 0;
@@ -73,7 +81,7 @@ afs_pd_free(struct afs_pdata *apd)
     if (apd->ptr == NULL)
 	return;
 
-    if (apd->remaining > AFS_LRALLOCSIZ)
+    if (apd->remaining >= AFS_LRALLOCSIZ)
 	osi_Free(apd->ptr, apd->remaining + 1);
     else
 	osi_FreeLargeSpace(apd->ptr);
@@ -2016,6 +2024,7 @@ DECL_PIOCTL(PSetVolumeStatus)
     AFS_STATCNT(PSetVolumeStatus);
     if (!avc)
 	return EINVAL;
+    memset(&storeStat, 0, sizeof(storeStat));
 
     tvp = afs_GetVolume(&avc->f.fid, areq, READ_LOCK);
     if (tvp) {
@@ -4956,8 +4965,7 @@ DECL_PIOCTL(PFsCmd)
 	    if (tc) {
 		RX_AFS_GUNLOCK();
 		code =
-		    RXAFS_FsCmd(rxconn, Fid, Inputs,
-					(struct FsCmdOutputs *)aout);
+		    RXAFS_FsCmd(rxconn, Fid, Inputs, Outputs);
 		RX_AFS_GLOCK();
 	    } else
 		code = -1;
--- openafs-1.6.1.orig/src/afs/afs_prototypes.h
+++ openafs-1.6.1/src/afs/afs_prototypes.h
@@ -601,6 +601,8 @@ extern int AddPag(afs_proc_t *p, afs_int
 extern int AddPag(afs_int32 aval, afs_ucred_t **credpp);
 #endif
 extern int afs_InitReq(struct vrequest *av, afs_ucred_t *acred);
+extern int afs_CreateReq(struct vrequest **avpp, afs_ucred_t *acred);
+extern void afs_DestroyReq(struct vrequest *av);
 extern afs_uint32 afs_get_pag_from_groups(gid_t g0a, gid_t g1a);
 extern void afs_get_groups_from_pag(afs_uint32 pag, gid_t * g0p, gid_t * g1p);
 extern afs_int32 PagInCred(afs_ucred_t *cred);
--- openafs-1.6.1.orig/src/afs/afs_segments.c
+++ openafs-1.6.1/src/afs/afs_segments.c
@@ -55,6 +55,7 @@ afs_StoreMini(struct vcache *avc, struct
 	tlen = avc->f.truncPos;
     avc->f.truncPos = AFS_NOTRUNC;
     avc->f.states &= ~CExtendedFile;
+    memset(&InStatus, 0, sizeof(InStatus));
 
     do {
 	tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK, &rxconn);
@@ -175,8 +176,6 @@ afs_StoreAllSegments(struct vcache *avc,
 
     AFS_STATCNT(afs_StoreAllSegments);
 
-    hset(oldDV, avc->f.m.DataVersion);
-    hset(newDV, avc->f.m.DataVersion);
     hash = DVHash(&avc->f.fid);
     foreign = (avc->f.states & CForeign);
     dcList = (struct dcache **)osi_AllocLargeSpace(AFS_LRALLOCSIZ);
@@ -214,6 +213,14 @@ afs_StoreAllSegments(struct vcache *avc,
 	/*printf("Net down in afs_StoreSegments\n");*/
 	return ENETDOWN;
     }
+
+    /*
+     * Can't do this earlier because osi_VM_StoreAllSegments drops locks
+     * and can indirectly do some stores that increase the DV.
+     */
+    hset(oldDV, avc->f.m.DataVersion);
+    hset(newDV, avc->f.m.DataVersion);
+
     ConvertWToSLock(&avc->lock);
 
     /*
--- openafs-1.6.1.orig/src/aklog/aklog.c
+++ openafs-1.6.1/src/aklog/aklog.c
@@ -91,6 +91,7 @@
 #include <afs/pterror.h>
 #include <afs/dirpath.h>
 #include <afs/afsutil.h>
+#include <afs/akimpersonate.h>
 
 #include "aklog.h"
 #include "linked_list.h"
@@ -188,62 +189,9 @@ static int get_user_realm(krb5_context,
 #error "Must have either krb5_princ_size or krb5_principal_get_comp_string"
 #endif
 
-#if !defined(HAVE_KRB5_ENCRYPT_TKT_PART) && defined(HAVE_ENCODE_KRB5_ENC_TKT_PART) && defined(HAVE_KRB5_C_ENCRYPT)
-extern krb5_error_code encode_krb5_enc_tkt_part (const krb5_enc_tkt_part *rep,
-						 krb5_data **code);
-
-krb5_error_code
-krb5_encrypt_tkt_part(krb5_context context,
-		      const krb5_keyblock *key,
-		      krb5_ticket *ticket)
-{
-    krb5_data *data = 0;
-    int code;
-    size_t enclen;
-
-    if ((code = encode_krb5_enc_tkt_part(ticket->enc_part2, &data)))
-	goto Done;
-    if ((code = krb5_c_encrypt_length(context, key->enctype,
-				      data->length, &enclen)))
-	goto Done;
-    ticket->enc_part.ciphertext.length = enclen;
-    if (!(ticket->enc_part.ciphertext.data = malloc(enclen))) {
-	code = ENOMEM;
-	goto Done;
-    }
-    if ((code = krb5_c_encrypt(context, key, KRB5_KEYUSAGE_KDC_REP_TICKET,
-			       0, data, &ticket->enc_part))) {
-	free(ticket->enc_part.ciphertext.data);
-	ticket->enc_part.ciphertext.data = 0;
-    }
-Done:
-    if (data) {
-	if (data->data)
-	    free(data->data);
-	free(data);
-    }
-    return code;
-}
-#endif
-
-#if defined(HAVE_KRB5_CREDS_KEYBLOCK)
-
-#define get_cred_keydata(c) c->keyblock.contents
-#define get_cred_keylen(c) c->keyblock.length
-#define get_creds_enctype(c) c->keyblock.enctype
-
-#elif defined(HAVE_KRB5_CREDS_SESSION)
-
-#define get_cred_keydata(c) c->session.keyvalue.data
-#define get_cred_keylen(c) c->session.keyvalue.length
-#define get_creds_enctype(c) c->session.keytype
-
-#else
-#error "Must have either keyblock or session member of krb5_creds"
-#endif
-
-#ifdef AFS_DARWIN110_ENV
-#define HAVE_NO_KRB5_524 /* MITKerberosShim logs but returns success */
+/* MITKerberosShim logs but returns success */
+#if !defined(HAVE_KRB5_524_CONV_PRINCIPAL) || defined(AFS_DARWIN110_ENV) || (!defined(HAVE_KRB5_524_CONVERT_CREDS) && !defined(HAVE_KRB524_CONVERT_CREDS_KDC))
+#define HAVE_NO_KRB5_524
 #elif !defined(HAVE_KRB5_524_CONVERT_CREDS) && defined(HAVE_KRB524_CONVERT_CREDS_KDC)
 #define krb5_524_convert_creds krb524_convert_creds_kdc
 #elif !defined(HAVE_KRB5_524_CONVERT_CREDS) && !defined(HAVE_KRB524_CONVERT_CREDS_KDC)
@@ -692,6 +640,8 @@ rxkad_build_native_token(krb5_context co
     char k4inst[INST_SZ];
     char k4realm[REALM_SZ];
 #endif
+    void *inkey = get_cred_keydata(v5cred);
+    size_t inkey_sz = get_cred_keylen(v5cred);
 
     afs_dprintf("Using Kerberos V5 ticket natively\n");
 
@@ -739,8 +689,11 @@ rxkad_build_native_token(krb5_context co
     token->kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
     token->startTime = v5cred->times.starttime;;
     token->endTime = v5cred->times.endtime;
-    memcpy(&token->sessionKey, get_cred_keydata(v5cred),
-	   get_cred_keylen(v5cred));
+    if (tkt_DeriveDesKey(get_creds_enctype(v5cred), inkey, inkey_sz,
+			 &token->sessionKey) != 0) {
+	free(token);
+	return RXKADBADKEY;
+    }
     token->ticketLen = v5cred->ticket.length;
     memcpy(token->ticket, v5cred->ticket.data, token->ticketLen);
 
@@ -1808,327 +1761,6 @@ isdir(char *path, unsigned char *val)
 }
 
 static krb5_error_code
-get_credv5_akimpersonate(krb5_context context,
-			 char* keytab,
-			 krb5_principal service_principal,
-			 krb5_principal client_principal,
-			 time_t starttime,
-			 time_t endtime,
-			 int *allowed_enctypes,
-			 int *paddress,
-			 krb5_creds** out_creds /* out */ )
-{
-#if defined(USING_HEIMDAL) || (defined(HAVE_ENCODE_KRB5_ENC_TKT) && defined(HAVE_ENCODE_KRB5_TICKET) && defined(HAVE_KRB5_C_ENCRYPT))
-    krb5_error_code code;
-    krb5_keytab kt = 0;
-    krb5_kt_cursor cursor[1];
-    krb5_keytab_entry entry[1];
-    krb5_ccache cc = 0;
-    krb5_creds *creds = 0;
-    krb5_enctype enctype;
-    krb5_kvno kvno;
-    krb5_keyblock session_key[1];
-#if USING_HEIMDAL
-    Ticket ticket_reply[1];
-    EncTicketPart enc_tkt_reply[1];
-    krb5_address address[30];
-    krb5_addresses faddr[1];
-    int temp_vno[1];
-    time_t temp_time[2];
-#else
-    krb5_ticket ticket_reply[1];
-    krb5_enc_tkt_part enc_tkt_reply[1];
-    krb5_address address[30], *faddr[30];
-    krb5_data * temp;
-#endif
-    int i;
-    static int any_enctype[] = {0};
-    *out_creds = 0;
-    if (!(creds = malloc(sizeof *creds))) {
-        code = ENOMEM;
-        goto cleanup;
-    }
-    if (!allowed_enctypes)
-        allowed_enctypes = any_enctype;
-
-    cc = 0;
-    enctype = 0; /* AKIMPERSONATE_IGNORE_ENCTYPE */
-    kvno = 0; /* AKIMPERSONATE_IGNORE_VNO */
-    memset((char*)creds, 0, sizeof *creds);
-    memset((char*)entry, 0, sizeof *entry);
-    memset((char*)session_key, 0, sizeof *session_key);
-    memset((char*)ticket_reply, 0, sizeof *ticket_reply);
-    memset((char*)enc_tkt_reply, 0, sizeof *enc_tkt_reply);
-    code = krb5_kt_resolve(context, keytab, &kt);
-    if (code) {
-        if (keytab)
-            afs_com_err(progname, code, "while resolving keytab %s", keytab);
-        else
-            afs_com_err(progname, code, "while resolving default keytab");
-        goto cleanup;
-    }
-
-    if (service_principal) {
-        for (i = 0; (enctype = allowed_enctypes[i]) || !i; ++i) {
-	    code = krb5_kt_get_entry(context,
-				     kt,
-				     service_principal,
-				     kvno,
-				     enctype,
-				     entry);
-	    if (!code) {
-		if (allowed_enctypes[i])
-		    deref_keyblock_enctype(session_key) = allowed_enctypes[i];
-		break;
-	    }
-        }
-        if (code) {
-	    afs_com_err(progname, code,"while scanning keytab entries");
-	    goto cleanup;
-        }
-    } else {
-        krb5_keytab_entry new[1];
-        int best = -1;
-        memset(new, 0, sizeof *new);
-        if ((code == krb5_kt_start_seq_get(context, kt, cursor))) {
-            afs_com_err(progname, code, "while starting keytab scan");
-            goto cleanup;
-        }
-        while (!(code = krb5_kt_next_entry(context, kt, new, cursor))) {
-            for (i = 0;
-                    allowed_enctypes[i] && allowed_enctypes[i]
-		     != deref_entry_enctype(new); ++i)
-                ;
-            if ((!i || allowed_enctypes[i]) &&
-		(best < 0 || best > i)) {
-                krb5_free_keytab_entry_contents(context, entry);
-                *entry = *new;
-                memset(new, 0, sizeof *new);
-            } else krb5_free_keytab_entry_contents(context, new);
-        }
-        if ((i = krb5_kt_end_seq_get(context, kt, cursor))) {
-            afs_com_err(progname, i, "while ending keytab scan");
-            code = i;
-            goto cleanup;
-        }
-        if (best < 0) {
-            afs_com_err(progname, code, "while scanning keytab");
-            goto cleanup;
-        }
-        deref_keyblock_enctype(session_key) = deref_entry_enctype(entry);
-    }
-
-    /* Make Ticket */
-
-#if USING_HEIMDAL
-    if ((code = krb5_generate_random_keyblock(context,
-					      deref_keyblock_enctype(session_key), session_key))) {
-        afs_com_err(progname, code, "while making session key");
-        goto cleanup;
-    }
-    enc_tkt_reply->flags.initial = 1;
-    enc_tkt_reply->transited.tr_type = DOMAIN_X500_COMPRESS;
-    enc_tkt_reply->cname = client_principal->name;
-    enc_tkt_reply->crealm = client_principal->realm;
-    enc_tkt_reply->key = *session_key;
-    {
-        static krb5_data empty_string;
-        enc_tkt_reply->transited.contents = empty_string;
-    }
-    enc_tkt_reply->authtime = starttime;
-    enc_tkt_reply->starttime = temp_time;
-    *enc_tkt_reply->starttime = starttime;
-#if 0
-    enc_tkt_reply->renew_till = temp_time + 1;
-    *enc_tkt_reply->renew_till = endtime;
-#endif
-    enc_tkt_reply->endtime = endtime;
-#else
-    if ((code = krb5_c_make_random_key(context,
-				       deref_keyblock_enctype(session_key), session_key))) {
-        afs_com_err(progname, code, "while making session key");
-        goto cleanup;
-    }
-    enc_tkt_reply->magic = KV5M_ENC_TKT_PART;
-#define DATACAST        (unsigned char *)
-    enc_tkt_reply->flags |= TKT_FLG_INITIAL;
-    enc_tkt_reply->transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
-    enc_tkt_reply->session = session_key;
-    enc_tkt_reply->client = client_principal;
-    {
-        static krb5_data empty_string;
-        enc_tkt_reply->transited.tr_contents = empty_string;
-    }
-    enc_tkt_reply->times.authtime = starttime;
-    enc_tkt_reply->times.starttime = starttime; /* krb524init needs this */
-    enc_tkt_reply->times.endtime = endtime;
-#endif  /* USING_HEIMDAL */
-    /* NB:  We will discard address for now--ignoring caddr field
-       in any case.  MIT branch does what it always did. */
-
-    if (paddress && *paddress) {
-        deref_enc_tkt_addrs(enc_tkt_reply) = faddr;
-#if USING_HEIMDAL
-        faddr->len = 0;
-        faddr->val = address;
-#endif
-        for (i = 0; paddress[i]; ++i) {
-#if USING_HEIMDAL
-            address[i].addr_type = KRB5_ADDRESS_INET;
-            address[i].address.data = (void*)(paddress+i);
-            address[i].address.length = sizeof(paddress[i]);
-#else
-#if !USING_SSL
-            address[i].magic = KV5M_ADDRESS;
-            address[i].addrtype = ADDRTYPE_INET;
-#else
-            address[i].addrtype = AF_INET;
-#endif
-            address[i].contents = (void*)(paddress+i);
-            address[i].length = sizeof(int);
-            faddr[i] = address+i;
-#endif
-        }
-#if USING_HEIMDAL
-        faddr->len = i;
-#else
-        faddr[i] = 0;
-#endif
-    }
-
-#if USING_HEIMDAL
-    ticket_reply->sname = service_principal->name;
-    ticket_reply->realm = service_principal->realm;
-
-    { /* crypto block */
-        krb5_crypto crypto = 0;
-        unsigned char *buf = 0;
-        size_t buf_size, buf_len;
-        char *what;
-
-        ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size,
-			   enc_tkt_reply, &buf_len, code);
-        if(code) {
-            afs_com_err(progname, code, "while encoding ticket");
-            goto cleanup;
-        }
-
-        if(buf_len != buf_size) {
-            afs_com_err(progname, code,
-		    "%u != %u while encoding ticket (internal ASN.1 encoder error",
-		    (unsigned int)buf_len, (unsigned int)buf_size);
-            goto cleanup;
-        }
-        what = "krb5_crypto_init";
-        code = krb5_crypto_init(context,
-				&deref_entry_keyblock(entry),
-				deref_entry_enctype(entry),
-				&crypto);
-        if(!code) {
-            what = "krb5_encrypt";
-            code = krb5_encrypt_EncryptedData(context, crypto, KRB5_KU_TICKET,
-					      buf, buf_len, entry->vno, &(ticket_reply->enc_part));
-        }
-        if (buf) free(buf);
-        if (crypto) krb5_crypto_destroy(context, crypto);
-        if(code) {
-            afs_com_err(progname, code, "while %s", what);
-            goto cleanup;
-        }
-    } /* crypto block */
-    ticket_reply->enc_part.etype = deref_entry_enctype(entry);
-    ticket_reply->enc_part.kvno = temp_vno;
-    *ticket_reply->enc_part.kvno = entry->vno;
-    ticket_reply->tkt_vno = 5;
-#else
-    ticket_reply->server = service_principal;
-    ticket_reply->enc_part2 = enc_tkt_reply;
-    if ((code = krb5_encrypt_tkt_part(context, &deref_entry_keyblock(entry), ticket_reply))) {
-        afs_com_err(progname, code, "while making ticket");
-        goto cleanup;
-    }
-    ticket_reply->enc_part.kvno = entry->vno;
-#endif
-
-    /* Construct Creds */
-
-    if ((code = krb5_copy_principal(context, service_principal,
-				    &creds->server))) {
-        afs_com_err(progname, code, "while copying service principal");
-        goto cleanup;
-    }
-    if ((code = krb5_copy_principal(context, client_principal,
-				    &creds->client))) {
-        afs_com_err(progname, code, "while copying client principal");
-        goto cleanup;
-    }
-    if ((code = krb5_copy_keyblock_contents(context, session_key,
-					    &deref_session_key(creds)))) {
-        afs_com_err(progname, code, "while copying session key");
-        goto cleanup;
-    }
-
-#if USING_HEIMDAL
-    creds->times.authtime = enc_tkt_reply->authtime;
-    creds->times.starttime = *(enc_tkt_reply->starttime);
-    creds->times.endtime = enc_tkt_reply->endtime;
-    creds->times.renew_till = 0; /* *(enc_tkt_reply->renew_till) */
-    creds->flags.b = enc_tkt_reply->flags;
-#else
-    creds->times = enc_tkt_reply->times;
-    creds->ticket_flags = enc_tkt_reply->flags;
-#endif
-    if (!deref_enc_tkt_addrs(enc_tkt_reply))
-        ;
-    else if ((code = krb5_copy_addresses(context,
-					 deref_enc_tkt_addrs(enc_tkt_reply), &creds->addresses))) {
-        afs_com_err(progname, code, "while copying addresses");
-        goto cleanup;
-    }
-
-#if USING_HEIMDAL
-    {
-	size_t creds_tkt_len;
-	ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
-			   ticket_reply, &creds_tkt_len, code);
-	if(code) {
-	    afs_com_err(progname, code, "while encoding ticket");
-	    goto cleanup;
-	}
-    }
-#else
-    if ((code = encode_krb5_ticket(ticket_reply, &temp))) {
-	afs_com_err(progname, code, "while encoding ticket");
-	goto cleanup;
-    }
-    creds->ticket = *temp;
-    free(temp);
-#endif
-    /* return creds */
-    *out_creds = creds;
-    creds = 0;
-cleanup:
-    if (deref_enc_data(&ticket_reply->enc_part))
-        free(deref_enc_data(&ticket_reply->enc_part));
-    krb5_free_keytab_entry_contents(context, entry);
-    if (client_principal)
-        krb5_free_principal(context, client_principal);
-    if (service_principal)
-        krb5_free_principal(context, service_principal);
-    if (cc)
-        krb5_cc_close(context, cc);
-    if (kt)
-        krb5_kt_close(context, kt);
-    if (creds) krb5_free_creds(context, creds);
-    krb5_free_keyblock_contents(context, session_key);
-    return code;
-#else
-    return -1;
-#endif
-}
-
-
-static krb5_error_code
 get_credv5(krb5_context context, char *name, char *inst, char *realm,
 	   krb5_creds **creds)
 {
@@ -2167,21 +1799,17 @@ get_credv5(krb5_context context, char *n
 
     increds.client = client_principal;
     increds.times.endtime = 0;
-    /* Ask for DES since that is what V4 understands */
-    get_creds_enctype((&increds)) = ENCTYPE_DES_CBC_CRC;
+    if (do524)
+	/* Ask for DES since that is what V4 understands */
+	get_creds_enctype((&increds)) = ENCTYPE_DES_CBC_CRC;
 
     if (keytab) {
-	int allowed_enctypes[] = {
-	    ENCTYPE_DES_CBC_CRC, 0
-	};
-
 	r = get_credv5_akimpersonate(context,
 				     keytab,
 				     increds.server,
 				     increds.client,
-				     300, ((~0U)>>1),
-				     allowed_enctypes,
-				     0 /* paddress */,
+				     0, 0x7fffffff,
+				     NULL,
 				     creds /* out */);
     } else {
 	r = krb5_get_credentials(context, 0, _krb425_ccache, &increds, creds);
--- openafs-1.6.1.orig/src/aklog/klog.c
+++ openafs-1.6.1/src/aklog/klog.c
@@ -667,9 +667,6 @@ CommandProc(struct cmd_syndesc *as, void
     for (service = service_temp;;service = "afs") {
         memset(mcred, 0, sizeof *mcred);
         mcred->client = princ;
-        /* Ask for DES since that is what rxkad understands */
-        if (service && !strncmp(service, "afs", 3))
-            get_creds_enctype(mcred) = ENCTYPE_DES_CBC_CRC;
         code = krb5_parse_name(k5context, service, &mcred->server);
         if (code) {
             afs_com_err(rn, code, "Unable to parse service <%s>\n", service);
@@ -713,13 +710,6 @@ CommandProc(struct cmd_syndesc *as, void
 	struct ktc_principal aserver[1], aclient[1];
 	struct ktc_token atoken[1];
 
-        if (get_cred_keylen(afscred) != sizeof(atoken->sessionKey)) {
-            afs_com_err(rn, 0, "Invalid rxkad key length (%u != 8) key type (%u)",
-                        get_cred_keylen(afscred),
-                        get_creds_enctype(afscred));
-            KLOGEXIT(1);
-        }
-
 	memset(atoken, 0, sizeof *atoken);
 	if (evil) {
 	    size_t elen = enc_part->length;
@@ -737,8 +727,15 @@ CommandProc(struct cmd_syndesc *as, void
 	}
 	atoken->startTime = afscred->times.starttime;
 	atoken->endTime = afscred->times.endtime;
-	memcpy(&atoken->sessionKey, get_cred_keydata(afscred),
-	    get_cred_keylen(afscred));
+	if (tkt_DeriveDesKey(get_creds_enctype(afscred),
+			     get_cred_keydata(afscred),
+			     get_cred_keylen(afscred), &atoken->sessionKey)) {
+	    afs_com_err(rn, 0,
+			"Cannot derive DES key from enctype %i of length %u",
+			get_creds_enctype(afscred),
+			(unsigned)get_cred_keylen(afscred));
+	    KLOGEXIT(1);
+	}
 	memcpy(atoken->ticket, enc_part->data,
 	    atoken->ticketLen = enc_part->length);
 	memset(aserver, 0, sizeof *aserver);
--- openafs-1.6.1.orig/src/auth/Makefile.in
+++ openafs-1.6.1/src/auth/Makefile.in
@@ -14,15 +14,15 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
 
 OBJS= cellconfig.o ktc.o userok.o writeconfig.o authcon.o \
-    acfg_errors.o ktc_errors.o
+    acfg_errors.o ktc_errors.o @MAKE_KRB5@ akimpersonate.o akimpersonate_v5gen.o
 KOBJS= cellconfig.o ktc.krb.o userok.o writeconfig.o authcon.o \
-    acfg_errors.o ktc_errors.o
+    acfg_errors.o ktc_errors.o @MAKE_KRB5@ akimpersonate.o akimpersonate_v5gen.o
 
 LIBS=libauth.a \
       ${TOP_LIBDIR}/librxkad.a ${TOP_LIBDIR}/libdes.a \
       ${TOP_LIBDIR}/librx.a ${TOP_LIBDIR}/libsys.a \
       ${TOP_LIBDIR}/liblwp.a ${TOP_LIBDIR}/util.a
-INCLS=cellconfig.h auth.h keys.h
+INCLS=cellconfig.h auth.h keys.h akimpersonate.h akimpersonate_v5gen.h
 KSRCS=auth.h
 UKSRCS=${KSRCS} cellconfig.h acfg_errors.c keys.h cellconfig.c \
        ktc.c authcon.c ktc_errors.c
@@ -31,6 +31,7 @@ all: ${TOP_LIBDIR}/libauth.a ${TOP_LIBDI
 
 depinstall: ${TOP_INCDIR}/afs/keys.h \
 	${TOP_INCDIR}/afs/cellconfig.h \
+	${TOP_INCDIR}/afs/akimpersonate.h \
 	${TOP_INCDIR}/afs/auth.h \
 	${TOP_INCDIR}/afs/ktc.h
 
@@ -42,6 +43,9 @@ ${TOP_INCDIR}/afs/keys.h: keys.h
 ${TOP_INCDIR}/afs/cellconfig.h: cellconfig.h
 	${INSTALL_DATA} cellconfig.h $@
 
+${TOP_INCDIR}/afs/akimpersonate.h: akimpersonate.h
+	${INSTALL_DATA} $? $@
+
 ${TOP_INCDIR}/afs/auth.h: auth.h
 	${INSTALL_DATA} $? $@
 
@@ -57,7 +61,16 @@ ${TOP_LIBDIR}/libauth.krb.a: libauth.krb
 cellconfig.o: cellconfig.c ${INCLS}
 ktc.o: ktc.c ${INCLS} ${TOP_INCDIR}/afs/vice.h
 writeconfig.o: writeconfig.c ${INCLS}
+
 authcon.o: authcon.c ${INCLS}
+	${CCOBJ} ${CFLAGS} -c ${srcdir}/authcon.c @KRB5_CPPFLAGS@
+
+akimpersonate.o: akimpersonate.c ${INCLS}
+	${CCOBJ} ${CFLAGS} -c ${srcdir}/akimpersonate.c @KRB5_CPPFLAGS@
+
+akimpersonate_v5gen.o: akimpersonate_v5gen.c ${INCLS}
+	${CCOBJ} ${CFLAGS} -c ${srcdir}/akimpersonate_v5gen.c @KRB5_CPPFLAGS@ -I${srcdir}/../rxkad
+
 userok.o: userok.c ${INCLS}
 cellconfig.o: cellconfig.c ${INCLS}
 copyauth.o: copyauth.c ${INCLS} AFS_component_version_number.o
--- /dev/null
+++ openafs-1.6.1/src/auth/akimpersonate.c
@@ -0,0 +1,775 @@
+/*
+ * Copyright (c) 2005, 2006
+ * The Linux Box Corporation
+ * ALL RIGHTS RESERVED
+ *
+ * Permission is granted to use, copy, create derivative works
+ * and redistribute this software and such derivative works
+ * for any purpose, so long as the name of the Linux Box
+ * Corporation is not used in any advertising or publicity
+ * pertaining to the use or distribution of this software
+ * without specific, written prior authorization.  If the
+ * above copyright notice or any other identification of the
+ * Linux Box Corporation is included in any copy of any
+ * portion of this software, then the disclaimer below must
+ * also be included.
+ *
+ * This software is provided as is, without representation
+ * from the Linux Box Corporation as to its fitness for any
+ * purpose, and without warranty by the Linux Box Corporation
+ * of any kind, either express or implied, including
+ * without limitation the implied warranties of
+ * merchantability and fitness for a particular purpose.  The
+ * regents of the Linux Box Corporation shall not be liable
+ * for any damages, including special, indirect, incidental, or
+ * consequential damages, with respect to any claim arising
+ * out of or in connection with the use of the software, even
+ * if it has been or is hereafter advised of the possibility of
+ * such damages.
+ */
+/*
+ * Copyright (C) 2013 by Alexander Chernyakhovsky and the
+ * Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+#include <afs/stds.h>
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <krb5.h>
+
+#include "akimpersonate.h"
+#include "akimpersonate_v5gen.h"
+
+#ifdef HAVE_KRB5_CREDS_KEYBLOCK
+#define USING_MIT 1
+#endif
+#ifdef HAVE_KRB5_CREDS_SESSION
+#define USING_HEIMDAL 1
+#endif
+
+#if USING_HEIMDAL
+#define deref_keyblock_enctype(kb)	((kb)->keytype)
+#define deref_entry_keyblock(entry)	((entry)->keyblock)
+#define deref_session_key(creds)	((creds)->session)
+#define deref_enc_tkt_addrs(tkt)	((tkt)->caddr)
+#define deref_enc_data(enc)		((enc)->cipher.data)
+#else
+#define deref_keyblock_enctype(kb)	((kb)->enctype)
+#define deref_entry_keyblock(entry)	((entry)->key)
+#define deref_session_key(creds)	((creds)->keyblock)
+#define deref_enc_tkt_addrs(tkt)	((tkt)->caddrs)
+#define deref_enc_data(enc)		((enc)->ciphertext.data)
+#endif
+#if HAVE_DECL_KRB5_FREE_KEYTAB_ENTRY_CONTENTS
+/* nothing */
+#elif HAVE_DECL_KRB5_KT_FREE_ENTRY
+#define krb5_free_keytab_entry_contents krb5_kt_free_entry
+#else
+static inline int
+krb5_free_keytab_entry_contents(krb5_context ctx, krb5_keytab_entry * ent)
+{
+    krb5_free_principal(ctx, ent->principal);
+    krb5_free_keyblock_contents(ctx, kte_keyblock(ent));
+    return 0;
+}
+#endif
+
+#define deref_entry_enctype(entry)			\
+    deref_keyblock_enctype(&deref_entry_keyblock(entry))
+
+#ifdef USING_MIT
+# if !defined(HAVE_ENCODE_KRB5_TICKET)
+/*
+ * Solaris doesn't have encode_krb5_ticket and encode_krb5_enc_tkt_part, so we
+ * need to implement our own. The akv5gen_* functions below are implemented
+ * using v5gen code; so, they need to have no krb5 structures in their
+ * arguments, since using system krb5 headers at the same time as v5gen
+ * headers is problematic. That's why the ticket contents are exploded.
+ */
+static krb5_error_code
+encode_krb5_ticket(krb5_ticket *rep, krb5_data **a_out)
+{
+    krb5_error_code code = 0;
+    int i;
+    char **names = NULL;
+    krb5_data *out = NULL;
+    size_t out_len = 0;
+    char *out_data = NULL;
+
+    *a_out = NULL;
+
+    out = calloc(1, sizeof(*out));
+    if (!out) {
+	code = ENOMEM;
+	goto cleanup;
+    }
+
+    names = calloc(rep->server->length, sizeof(names[0]));
+    if (names == NULL) {
+	code = ENOMEM;
+	goto cleanup;
+    }
+
+    for (i = 0; i < rep->server->length; i++) {
+	names[i] = rep->server->data[i].data;
+    }
+
+    code = akv5gen_encode_krb5_ticket(rep->enc_part.kvno,
+                                      rep->server->realm.data,
+                                      rep->server->type,
+                                      rep->server->length,
+                                      names,
+                                      rep->enc_part.enctype,
+                                      rep->enc_part.ciphertext.length,
+                                      rep->enc_part.ciphertext.data,
+                                      &out_len,
+                                      &out_data);
+    if (code != 0) {
+	goto cleanup;
+    }
+
+    out->length = out_len;
+    out->data = out_data;
+    *a_out = out;
+    out = NULL;
+
+ cleanup:
+    free(names);
+    free(out);
+    return code;
+}
+# else
+extern krb5_error_code encode_krb5_ticket(krb5_ticket *rep,
+					  krb5_data **a_out);
+# endif /* !HAVE_ENCODE_KRB5_TICKET */
+
+# if !defined(HAVE_ENCODE_KRB5_ENC_TKT_PART)
+static krb5_error_code
+encode_krb5_enc_tkt_part(krb5_enc_tkt_part *encpart, krb5_data **a_out)
+{
+    krb5_error_code code = 0;
+    int i;
+    char **names = NULL;
+    krb5_data *out = NULL;
+    size_t out_len = 0;
+    char *out_data = NULL;
+
+    *a_out = NULL;
+
+    out = calloc(1, sizeof(*out));
+    if (out == NULL) {
+	code = ENOMEM;
+	goto cleanup;
+    }
+
+    names = calloc(encpart->client->length, sizeof(names[0]));
+    if (names == NULL) {
+	code = ENOMEM;
+	goto cleanup;
+    }
+
+    for (i = 0; i < encpart->client->length; i++)
+	names[i] = encpart->client->data[i].data;
+
+    if (encpart->flags != TKT_FLG_INITIAL) {
+	/* We assume the ticket has the flag _INITIAL set, and only that flag.
+	 * passing each individual flag to akv5gen would be really ugly, and
+	 * should be unnecessary. */
+	goto invalid;
+    }
+    if (encpart->caddrs != NULL && encpart->caddrs[0] != NULL)
+	goto invalid;
+    if (encpart->authorization_data && encpart->authorization_data[0])
+	goto invalid;
+
+    code = akv5gen_encode_krb5_enc_tkt_part(encpart->session->enctype,
+                                            encpart->session->length,
+                                            encpart->session->contents,
+                                            encpart->client->realm.data,
+                                            encpart->client->type,
+                                            encpart->client->length,
+                                            names,
+                                            encpart->transited.tr_type,
+                                            encpart->transited.tr_contents.length,
+                                            encpart->transited.tr_contents.data,
+                                            encpart->times.authtime,
+                                            encpart->times.starttime,
+                                            encpart->times.endtime,
+                                            encpart->times.renew_till,
+                                            &out_len,
+                                            &out_data);
+    if (code != 0)
+	goto cleanup;
+
+    out->length = out_len;
+    out->data = out_data;
+    *a_out = out;
+    out = NULL;
+
+ cleanup:
+    free(names);
+    free(out);
+    return code;
+
+ invalid:
+    /* We don't handle all possible ticket options, features, etc. If we are
+     * given a ticket we can't handle, bail out with EINVAL. */
+    code = EINVAL;
+    goto cleanup;
+}
+# endif /* !HAVE_ENCODE_KRB5_ENC_TKT_PART */
+
+# if !defined(HAVE_KRB5_ENCRYPT_TKT_PART)
+krb5_error_code
+krb5_encrypt_tkt_part(krb5_context context,
+		      const krb5_keyblock *key,
+		      krb5_ticket *ticket)
+{
+    krb5_data *data = 0;
+    int code;
+    size_t enclen;
+
+    if ((code = encode_krb5_enc_tkt_part(ticket->enc_part2, &data)))
+	goto Done;
+    if ((code = krb5_c_encrypt_length(context, key->enctype,
+				      data->length, &enclen)))
+	goto Done;
+    ticket->enc_part.ciphertext.length = enclen;
+    if (!(ticket->enc_part.ciphertext.data = malloc(enclen))) {
+	code = ENOMEM;
+	goto Done;
+    }
+    if ((code = krb5_c_encrypt(context, key, KRB5_KEYUSAGE_KDC_REP_TICKET,
+			       0, data, &ticket->enc_part))) {
+	free(ticket->enc_part.ciphertext.data);
+	ticket->enc_part.ciphertext.data = 0;
+    }
+Done:
+    if (data) {
+	if (data->data)
+	    free(data->data);
+	free(data);
+    }
+    return code;
+}
+# else
+extern krb5_error_code krb5_encrypt_tkt_part(krb5_context context,
+					     const krb5_keyblock *key,
+					     krb5_ticket *ticket);
+# endif /* HAVE_KRB5_ENCRYPT_TKT_PART */
+#endif /* USING_MIT */
+
+static const int any_enctype[2] = {0, 0};
+static const krb5_data empty_string;
+
+/*
+ * Routines to allocate/free the extra storage involved in a ticket structure.
+ * When changing one, ensure that the other is changed to reflect the
+ * allocation contract.
+ */
+#if USING_HEIMDAL
+static int
+alloc_ticket(Ticket **out)
+{
+    *out = calloc(1, sizeof(Ticket));
+    if (*out == NULL)
+	return ENOMEM;
+
+    (*out)->enc_part.kvno = malloc(sizeof(*(*out)->enc_part.kvno));
+    if ((*out)->enc_part.kvno == NULL)
+	return ENOMEM;
+
+    return 0;
+}
+#else
+static int
+alloc_ticket(krb5_ticket **out)
+{
+    *out = calloc(1, sizeof(krb5_ticket));
+    if (*out == NULL)
+	return ENOMEM;
+
+    return 0;
+}
+#endif
+
+static void
+free_ticket(void *in)
+{
+#if USING_HEIMDAL
+    Ticket *ticket_reply;
+#else
+    krb5_ticket *ticket_reply;
+#endif
+
+    /* requisite aliasing for MIT/Heimdal support. */
+    ticket_reply = in;
+    if (ticket_reply == NULL)
+	return;
+
+#if USING_HEIMDAL
+    if (ticket_reply->enc_part.kvno != NULL)
+	free(ticket_reply->enc_part.kvno);
+#else
+    /* No allocations needed for MIT's krb5_ticket structure. */
+#endif
+    free(ticket_reply);
+}
+
+/*
+ * Routines to allocate/free the extra storage involved in an encrypted
+ * ticket part structure.
+ * When changing one, ensure that the other is changed to reflect the
+ * allocation contract.
+ */
+#if USING_HEIMDAL
+static int
+alloc_enc_tkt_part(EncTicketPart **out)
+{
+    *out = calloc(1, sizeof(EncTicketPart));
+    if (*out == NULL)
+	return ENOMEM;
+
+    (*out)->starttime = malloc(sizeof(*(*out)->starttime));
+    if ((*out)->starttime == NULL)
+	return ENOMEM;
+    return 0;
+}
+#else
+static int
+alloc_enc_tkt_part(krb5_enc_tkt_part **out)
+{
+    *out = calloc(1, sizeof(krb5_enc_tkt_part));
+    if (*out == NULL)
+	return ENOMEM;
+
+    return 0;
+}
+#endif
+
+static void
+free_enc_tkt_part(void *in)
+{
+#if USING_HEIMDAL
+    EncTicketPart *enc_tkt_reply;
+#else
+    krb5_enc_tkt_part *enc_tkt_reply;
+#endif
+
+    /* Aliasing for MIT/Heimdal support. */
+    enc_tkt_reply = in;
+    if (enc_tkt_reply == NULL)
+	return;
+
+#if USING_HEIMDAL
+    if (enc_tkt_reply->starttime != NULL)
+	free(enc_tkt_reply->starttime);
+#else
+    /* No allocations needed for MIT's krb5_enc_tkt_part structure. */
+#endif
+    free(enc_tkt_reply);
+}
+
+/*
+ * Given a keytab, extract the principal name of the (first) entry with
+ * the highest kvno in the keytab.  This provides compatibility with the
+ * rxkad KeyFile behavior of always using the highest kvno entry when
+ * printing tickets.  We could return the kvno as well, but krb5_kt_get_entry
+ * can find the highest kvno on its own.
+ *
+ * Returns 0 on success, krb5 errors on failure.
+ */
+static int
+pick_principal(krb5_context context, krb5_keytab kt,
+	       krb5_principal *service_principal)
+{
+    krb5_error_code code;
+    krb5_kvno vno = 0;
+    krb5_kt_cursor c;
+    krb5_keytab_entry n_entry;
+
+    /* Nothing to do */
+    if (*service_principal != NULL)
+	return 0;
+
+    memset(&n_entry, 0, sizeof(n_entry));
+
+    code = krb5_kt_start_seq_get(context, kt, &c);
+    if (code != 0)
+	goto cleanup;
+    while (code == 0 && krb5_kt_next_entry(context, kt, &n_entry, &c) == 0) {
+	if (n_entry.vno > vno) {
+	    vno = n_entry.vno;
+	    (void)krb5_free_principal(context, *service_principal);
+	    code = krb5_copy_principal(context, n_entry.principal,
+				       service_principal);
+	}
+	(void)krb5_free_keytab_entry_contents(context, &n_entry);
+    }
+    if (code != 0) {
+	(void)krb5_kt_end_seq_get(context, kt, &c);
+	goto cleanup;
+    }
+    code = krb5_kt_end_seq_get(context, kt, &c);
+
+cleanup:
+    return code;
+}
+
+/*
+ * Given a keytab and a list of allowed enctypes, and optionally a known
+ * service principal, choose an appropriate enctype, and choose a
+ * service principal if one was not given.  Return the keytab entry
+ * corresponding to this service principal and enctype.
+ *
+ * The list of allowed enctypes must be zero-terminated.
+ */
+static int
+pick_enctype_and_principal(krb5_context context, krb5_keytab kt,
+			   const int *allowed_enctypes, krb5_enctype *enctype,
+			   krb5_principal *service_principal,
+			   krb5_keytab_entry *entry)
+{
+    krb5_error_code code;
+    int i;
+
+    if (*service_principal == NULL) {
+	code = pick_principal(context, kt, service_principal);
+	if (code != 0) {
+	    goto cleanup;
+	}
+    }
+
+    /* We always have a service_principal, now. */
+    i = 0;
+    do {
+	*enctype = allowed_enctypes[i];
+	code = krb5_kt_get_entry(context, kt, *service_principal, 0 /* any */,
+				 *enctype, entry);
+	if (code == 0) {
+	    if (*enctype == 0)
+		*enctype = deref_entry_enctype(entry);
+	    break;
+	}
+	++i;
+    } while(allowed_enctypes[i] != 0);
+    if (code != 0)
+	goto cleanup;
+
+cleanup:
+    return code;
+}
+
+/*
+ * Populate the encrypted part of the ticket.
+ */
+static void
+populate_enc_tkt(krb5_keyblock *session_key, krb5_principal client_principal,
+		 time_t starttime, time_t endtime, void *out)
+{
+#if USING_HEIMDAL
+    EncTicketPart *enc_tkt_reply;
+#else
+    krb5_enc_tkt_part *enc_tkt_reply;
+#endif
+
+    /* Alias through void* since Heimdal and MIT's types differ. */
+    enc_tkt_reply = out;
+
+#if USING_HEIMDAL
+    enc_tkt_reply->flags.initial = 1;
+    enc_tkt_reply->transited.tr_type = DOMAIN_X500_COMPRESS;
+    enc_tkt_reply->cname = client_principal->name;
+    enc_tkt_reply->crealm = client_principal->realm;
+    enc_tkt_reply->key = *session_key;
+    enc_tkt_reply->transited.contents = empty_string;
+    enc_tkt_reply->authtime = starttime;
+    *enc_tkt_reply->starttime = starttime;
+    enc_tkt_reply->endtime = endtime;
+#else
+    enc_tkt_reply->magic = KV5M_ENC_TKT_PART;
+    enc_tkt_reply->flags |= TKT_FLG_INITIAL;
+    enc_tkt_reply->transited.tr_type = KRB5_DOMAIN_X500_COMPRESS;
+    enc_tkt_reply->session = session_key;
+    enc_tkt_reply->client = client_principal;
+    enc_tkt_reply->transited.tr_contents = empty_string;
+    enc_tkt_reply->times.authtime = starttime;
+    enc_tkt_reply->times.starttime = starttime; /* krb524init needs this */
+    enc_tkt_reply->times.endtime = endtime;
+#endif  /* USING_HEIMDAL */
+}
+
+/*
+ * Encrypt the provided enc_tkt_part structure with the key from the keytab
+ * entry entry, and place the resulting blob in the ticket_reply structure.
+ */
+static int
+encrypt_enc_tkt(krb5_context context, krb5_principal service_principal,
+		krb5_keytab_entry *entry, void *tr_out, void *er_in)
+{
+    krb5_error_code code;
+#if USING_HEIMDAL
+    Ticket *ticket_reply;
+    EncTicketPart *enc_tkt_reply;
+    krb5_crypto crypto = 0;
+    unsigned char *buf = 0;
+    size_t buf_size, buf_len;
+#else
+    krb5_ticket *ticket_reply;
+    krb5_enc_tkt_part *enc_tkt_reply;
+#endif
+
+    /* Requisite aliasing for Heimdal/MIT support. */
+    ticket_reply = tr_out;
+    enc_tkt_reply = er_in;
+
+#if USING_HEIMDAL
+    ticket_reply->sname = service_principal->name;
+    ticket_reply->realm = service_principal->realm;
+
+    ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size, enc_tkt_reply,
+		       &buf_len, code);
+    if (code != 0)
+	goto cleanup;
+
+    if (buf_len != buf_size)
+	goto cleanup;
+    code = krb5_crypto_init(context,
+			    &deref_entry_keyblock(entry),
+			    deref_entry_enctype(entry),
+			    &crypto);
+    if (code != 0)
+	goto cleanup;
+    code = krb5_encrypt_EncryptedData(context, crypto, KRB5_KU_TICKET, buf,
+				      buf_len, entry->vno,
+				      &(ticket_reply->enc_part));
+    if (code != 0)
+	goto cleanup;
+    ticket_reply->enc_part.etype = deref_entry_enctype(entry);
+    *ticket_reply->enc_part.kvno = entry->vno;
+    ticket_reply->tkt_vno = 5;
+#else
+    ticket_reply->server = service_principal;
+    ticket_reply->enc_part2 = enc_tkt_reply;
+    code = krb5_encrypt_tkt_part(context, &deref_entry_keyblock(entry),
+				 ticket_reply);
+    if (code != 0)
+        goto cleanup;
+    ticket_reply->enc_part.kvno = entry->vno;
+#endif
+
+cleanup:
+#if USING_HEIMDAL
+    if (buf != NULL)
+	free(buf);
+    if (crypto != NULL)
+	krb5_crypto_destroy(context, crypto);
+#endif
+    return code;
+}
+
+/*
+ * Populate the credentials structure corresponding to the ticket we are
+ * printing.
+ */
+static int
+populate_creds(krb5_context context, krb5_principal service_principal,
+	       krb5_principal client_principal, krb5_keyblock *session_key,
+	       void *tr_in, void *er_in, krb5_creds *creds)
+{
+    krb5_error_code code;
+#if USING_HEIMDAL
+    Ticket *ticket_reply;
+    EncTicketPart *enc_tkt_reply;
+    size_t dummy;
+#else
+    krb5_ticket *ticket_reply;
+    krb5_enc_tkt_part *enc_tkt_reply;
+    krb5_data *temp = NULL;
+#endif
+
+    /* Requisite aliasing for Heimdal/MIT support. */
+    ticket_reply = tr_in;
+    enc_tkt_reply = er_in;
+
+    code = krb5_copy_principal(context, service_principal, &creds->server);
+    if (code != 0)
+        goto cleanup;
+    code = krb5_copy_principal(context, client_principal, &creds->client);
+    if (code != 0)
+        goto cleanup;
+    code = krb5_copy_keyblock_contents(context, session_key,
+				       &deref_session_key(creds));
+    if (code != 0)
+        goto cleanup;
+
+#if USING_HEIMDAL
+    creds->times.authtime = enc_tkt_reply->authtime;
+    creds->times.starttime = *(enc_tkt_reply->starttime);
+    creds->times.endtime = enc_tkt_reply->endtime;
+    creds->times.renew_till = 0; /* *(enc_tkt_reply->renew_till) */
+    creds->flags.b = enc_tkt_reply->flags;
+#else
+    creds->times = enc_tkt_reply->times;
+    creds->ticket_flags = enc_tkt_reply->flags;
+#endif
+
+#if USING_HEIMDAL
+    ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
+		       ticket_reply, &dummy, code);
+    if (code != 0 || dummy != creds->ticket.length)
+	goto cleanup;
+#else
+    code = encode_krb5_ticket(ticket_reply, &temp);
+    if (code != 0)
+	goto cleanup;
+    creds->ticket = *temp;
+#endif
+
+cleanup:
+#if USING_HEIMDAL
+    /* nothing */
+#else
+    free(temp);
+#endif
+    return code;
+}
+
+/*
+ * Print a krb5 ticket in our service key, for the supplied client principal.
+ * The path to a keytab is mandatory, but the service principal may be
+ * guessed from the keytab contents if desired.  The keytab entry must be
+ * one of the allowed_enctypes (a zero-terminated list) if a non-NULL
+ * parameter is passed.
+ */
+krb5_error_code
+get_credv5_akimpersonate(krb5_context context, char* keytab,
+			 krb5_principal service_principal,
+			 krb5_principal client_principal, time_t starttime,
+			 time_t endtime, const int *allowed_enctypes,
+			 krb5_creds** out_creds /* out */ )
+{
+    krb5_error_code code;
+    krb5_keytab kt = 0;
+    krb5_keytab_entry entry[1];
+    krb5_creds *creds = 0;
+    krb5_enctype enctype;
+    krb5_keyblock session_key[1];
+#if USING_HEIMDAL
+    Ticket *ticket_reply;
+    EncTicketPart *enc_tkt_reply;
+#else
+    krb5_ticket *ticket_reply;
+    krb5_enc_tkt_part *enc_tkt_reply;
+#endif
+    *out_creds = NULL;
+    enctype = 0; /* AKIMPERSONATE_IGNORE_ENCTYPE */
+    memset(entry, 0, sizeof *entry);
+    memset(session_key, 0, sizeof *session_key);
+    ticket_reply = NULL;
+    enc_tkt_reply = NULL;
+
+    creds = calloc(1, sizeof(*creds));
+    if (creds == NULL) {
+        code = ENOMEM;
+        goto cleanup;
+    }
+    code = alloc_ticket(&ticket_reply);
+    if (code != 0)
+	goto cleanup;
+    code = alloc_enc_tkt_part(&enc_tkt_reply);
+    if (code != 0)
+	goto cleanup;
+    /* Empty list of allowed etypes must fail.  Do it here to avoid issues. */
+    if (allowed_enctypes != NULL && *allowed_enctypes == 0) {
+	code = KRB5_BAD_ENCTYPE;
+	goto cleanup;
+    }
+    if (allowed_enctypes == NULL)
+        allowed_enctypes = any_enctype;
+
+    if (keytab != NULL)
+      code = krb5_kt_resolve(context, keytab, &kt);
+    else
+      code = krb5_kt_default(context, &kt);
+    if (code != 0)
+        goto cleanup;
+
+    code = pick_enctype_and_principal(context, kt, allowed_enctypes,
+				      &enctype, &service_principal, entry);
+    if (code != 0)
+	goto cleanup;
+
+    /* Conjure up a random session key */
+    deref_keyblock_enctype(session_key) = enctype;
+#if USING_HEIMDAL
+    code = krb5_generate_random_keyblock(context, enctype, session_key);
+#else
+    code = krb5_c_make_random_key(context, enctype, session_key);
+#endif
+    if (code != 0)
+        goto cleanup;
+
+    populate_enc_tkt(session_key, client_principal, starttime, endtime,
+		     enc_tkt_reply);
+
+    code = encrypt_enc_tkt(context, service_principal, entry, ticket_reply,
+			   enc_tkt_reply);
+    if (code != 0)
+	goto cleanup;
+
+    code = populate_creds(context, service_principal, client_principal,
+			  session_key, ticket_reply, enc_tkt_reply, creds);
+    if (code != 0)
+	goto cleanup;
+
+    /* return creds */
+    *out_creds = creds;
+    creds = NULL;
+cleanup:
+    if (deref_enc_data(&ticket_reply->enc_part) != NULL)
+        free(deref_enc_data(&ticket_reply->enc_part));
+    krb5_free_keytab_entry_contents(context, entry);
+    if (client_principal != NULL)
+        krb5_free_principal(context, client_principal);
+    if (service_principal != NULL)
+        krb5_free_principal(context, service_principal);
+    if (kt != NULL)
+        krb5_kt_close(context, kt);
+    if (creds != NULL)
+	krb5_free_creds(context, creds);
+    krb5_free_keyblock_contents(context, session_key);
+    free_ticket(ticket_reply);
+    free_enc_tkt_part(enc_tkt_reply);
+    return code;
+}
--- /dev/null
+++ openafs-1.6.1/src/auth/akimpersonate.h
@@ -0,0 +1,21 @@
+#ifndef __AKIMPERSONATE_H__
+#define __AKIMPERSONATE_H__
+
+#if defined(HAVE_KRB5_CREDS_KEYBLOCK)
+#define get_cred_keydata(c)	((c)->keyblock.contents)
+#define get_cred_keylen(c)	((c)->keyblock.length)
+#define get_creds_enctype(c)	((c)->keyblock.enctype)
+#elif defined(HAVE_KRB5_CREDS_SESSION)
+#define get_cred_keydata(c)	((c)->session.keyvalue.data)
+#define get_cred_keylen(c)	((c)->session.keyvalue.length)
+#define get_creds_enctype(c)	((c)->session.keytype)
+#else
+#error "Must have either keyblock or session member of krb5_creds"
+#endif
+
+/* The caller must include krb5.h to get prototypes for the types used. */
+krb5_error_code
+get_credv5_akimpersonate(krb5_context, char*, krb5_principal, krb5_principal,
+			 time_t, time_t, const int *, krb5_creds**);
+
+#endif
--- /dev/null
+++ openafs-1.6.1/src/auth/akimpersonate_v5gen.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2013 Sine Nomine Associates
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+
+/* are we using MIT krb5, and are we missing the functions encode_krb5_ticket
+ * and encode_krb5_enc_tkt_part? */
+#if defined(HAVE_KRB5_CREDS_KEYBLOCK) && !defined(HAVE_KRB5_CREDS_SESSION) \
+    && !defined(HAVE_ENCODE_KRB5_TICKET) && !defined(HAVE_ENCODE_KRB5_ENC_TKT_PART)
+
+# include <afs/stds.h>
+
+# include <sys/types.h>
+# include <time.h>
+# include <errno.h>
+# include <netinet/in.h>
+# include <string.h>
+# include <rx/xdr.h>
+# include <rx/rx.h>
+# include <des.h>
+# include <des_prototypes.h>
+
+# include "lifetimes.h"
+# include "rxkad.h"
+
+# include "v5gen-rewrite.h"
+# include "v5gen.h"
+# include "der.h"
+
+# include "akimpersonate_v5gen.h"
+
+int
+akv5gen_encode_krb5_ticket(int kvno,
+                           char *realm,
+                           int name_type,
+                           int name_len,
+                           char **name_parts,
+                           int enctype,
+			   size_t cipher_len,
+			   char *cipher_data,
+			   size_t *a_out_len,
+			   char **a_out_data)
+{
+    Ticket v5gen_tkt;
+    int code = 0;
+    size_t dummy;
+    char *outdata = NULL;
+    size_t outlen = 0;
+
+    memset(&v5gen_tkt, 0, sizeof(v5gen_tkt));
+
+    v5gen_tkt.tkt_vno = 5;
+    v5gen_tkt.realm = realm;
+
+    v5gen_tkt.sname.name_type = name_type;
+    v5gen_tkt.sname.name_string.len = name_len;
+    v5gen_tkt.sname.name_string.val = name_parts;
+
+    v5gen_tkt.enc_part.etype = enctype;
+    v5gen_tkt.enc_part.kvno = &kvno;
+    v5gen_tkt.enc_part.cipher.length = cipher_len;
+    v5gen_tkt.enc_part.cipher.data = cipher_data;
+
+    ASN1_MALLOC_ENCODE(Ticket, outdata, outlen,
+                       &v5gen_tkt, &dummy, code);
+    if (code == 0 && dummy != outlen)
+	code = EINVAL;
+    if (code)
+	goto cleanup;
+
+    *a_out_len = outlen;
+    *a_out_data = outdata;
+    outdata = NULL;
+
+ cleanup:
+    free(outdata);
+    return code;
+}
+
+int
+akv5gen_encode_krb5_enc_tkt_part(int enctype,
+                                 size_t key_len,
+                                 unsigned char *key_data,
+                                 char *realm,
+                                 int name_type,
+                                 int name_len,
+                                 char **name_parts,
+                                 int transited_type,
+                                 int transited_len,
+                                 char *transited_data,
+                                 time_t authtime,
+                                 time_t starttime,
+                                 time_t endtime,
+                                 time_t renew_till,
+			         size_t *a_out_len,
+			         char **a_out_data)
+{
+    EncTicketPart v5gen_enc;
+    size_t dummy;
+    int code = 0;
+    char *outdata = NULL;
+    size_t outlen = 0;
+
+    memset(&v5gen_enc, 0, sizeof(v5gen_enc));
+
+    /* assume the only flag that should be set is _INITIAL */
+    v5gen_enc.flags.initial = 1;
+
+    v5gen_enc.key.keytype = enctype;
+    v5gen_enc.key.keyvalue.length = key_len;
+    v5gen_enc.key.keyvalue.data = key_data;
+
+    v5gen_enc.crealm = realm;
+
+    v5gen_enc.cname.name_type = name_type;
+    v5gen_enc.cname.name_string.len = name_len;
+    v5gen_enc.cname.name_string.val = name_parts;
+
+    v5gen_enc.transited.tr_type = transited_type;
+    v5gen_enc.transited.contents.length = transited_len;
+    v5gen_enc.transited.contents.data = transited_data;
+
+    v5gen_enc.authtime = authtime;
+    v5gen_enc.starttime = &starttime;
+    v5gen_enc.endtime = endtime;
+    v5gen_enc.renew_till = &renew_till;
+
+    /* assume we have no addresses */
+    v5gen_enc.caddr = NULL;
+
+    /* assume we have no authz data */
+    v5gen_enc.authorization_data = NULL;
+
+    ASN1_MALLOC_ENCODE(EncTicketPart, outdata, outlen,
+                       &v5gen_enc, &dummy, code);
+    if (code == 0 && dummy != outlen)
+	code = EINVAL;
+    if (code)
+	goto cleanup;
+
+    *a_out_len = outlen;
+    *a_out_data = outdata;
+    outdata = NULL;
+
+ cleanup:
+    free(outdata);
+    return code;
+}
+
+#endif
--- /dev/null
+++ openafs-1.6.1/src/auth/akimpersonate_v5gen.h
@@ -0,0 +1,30 @@
+#ifndef __AKIMPERSONATE_V5GEN_H__
+#define __AKIMPERSONATE_V5GEN_H__
+extern int akv5gen_encode_krb5_ticket(int kvno,
+                                      char *realm,
+                                      int name_type,
+                                      int name_len,
+                                      char **name_parts,
+                                      int enctype,
+                                      size_t cipher_len,
+                                      char *cipher_data,
+                                      size_t *a_out_len,
+                                      char **a_out_data);
+
+extern int akv5gen_encode_krb5_enc_tkt_part(int enctype,
+                                            size_t key_len,
+                                            unsigned char *key_data,
+                                            char *realm,
+                                            int name_type,
+                                            int name_len,
+                                            char **name_parts,
+                                            int transited_type,
+                                            int transited_len,
+                                            char *transited_data,
+                                            time_t authtime,
+                                            time_t starttime,
+                                            time_t endtime,
+                                            time_t renew_till,
+                                            size_t *a_out_len,
+                                            char **a_out_data);
+#endif
--- openafs-1.6.1.orig/src/auth/authcon.c
+++ openafs-1.6.1/src/auth/authcon.c
@@ -26,10 +26,19 @@
 #include <des.h>
 #include <des_prototypes.h>
 #include <rx/rxkad.h>
+#if defined(USE_RXKAD_KEYTAB) && !defined(UKERNEL)
+#include <afs/dirpath.h>
+#include <krb5.h>
+#endif
 #include <rx/rx.h>
+#include <errno.h>
+#include <afs/afsutil.h>
 #include "cellconfig.h"
 #include "keys.h"
 #include "auth.h"
+#if defined(USE_RXKAD_KEYTAB) && !defined(UKERNEL)
+#include "akimpersonate.h"
+#endif
 
 /* return a null security object if nothing else can be done */
 static afs_int32
@@ -51,13 +60,37 @@ afsconf_ServerAuth(void *arock,
 {
     struct afsconf_dir *adir = (struct afsconf_dir *) arock;
     struct rx_securityClass *tclass;
-
+#ifdef USE_RXKAD_KEYTAB
+    int keytab_enable = 0;
+    char *csdb_name;
+    size_t csdblen;
+    char *keytab_name;
+    size_t ktlen;
+    csdblen = strlen(adir->name) + 1 + strlen(AFSDIR_CELLSERVDB_FILE) + 1;
+    csdb_name = malloc(csdblen);
+    ktlen = 5 + strlen(adir->name) + 1 + strlen(AFSDIR_RXKAD_KEYTAB_FILE) + 1;
+    keytab_name = malloc(ktlen);
+    if (csdb_name != NULL && keytab_name != NULL) {
+	strcompose(csdb_name, csdblen, adir->name, "/",
+	           AFSDIR_CELLSERVDB_FILE, (char *)NULL);
+	strcompose(keytab_name, ktlen, "FILE:", adir->name, "/",
+		   AFSDIR_RXKAD_KEYTAB_FILE, (char *)NULL);
+	if (rxkad_InitKeytabDecrypt(csdb_name, keytab_name) == 0)
+	    keytab_enable = 1;
+    }
+    free(csdb_name);
+    free(keytab_name);
+#endif
     LOCK_GLOBAL_MUTEX;
     tclass = (struct rx_securityClass *)
 	rxkad_NewServerSecurityObject(0, adir, afsconf_GetKey, NULL);
     if (tclass) {
 	*astr = tclass;
 	*aindex = RX_SECIDX_KAD;
+#ifdef USE_RXKAD_KEYTAB
+	if (keytab_enable)
+	    rxkad_BindKeytabDecrypt(tclass);
+#endif
 	UNLOCK_GLOBAL_MUTEX;
 	return 0;
     } else {
@@ -67,11 +100,82 @@ afsconf_ServerAuth(void *arock,
 }
 #endif /* !defined(UKERNEL) */
 
+#if defined(USE_RXKAD_KEYTAB) && !defined(UKERNEL)
+static afs_int32
+K5Auth(struct afsconf_dir *adir,
+       struct rx_securityClass **astr,
+       afs_int32 *aindex,
+       rxkad_level enclevel)
+{
+    struct rx_securityClass *tclass;
+    krb5_context context = NULL;
+    krb5_creds* fake_princ = NULL;
+    krb5_principal client_princ = NULL;
+    krb5_error_code r = 0;
+    struct ktc_encryptionKey session;
+    char *keytab_name = NULL;
+    size_t ktlen;
+
+    ktlen = 5 + strlen(adir->name) + 1 + strlen(AFSDIR_RXKAD_KEYTAB_FILE) + 1;
+    keytab_name = malloc(ktlen);
+    if (!keytab_name) {
+	return errno;
+    }
+    strcompose(keytab_name, ktlen, "FILE:", adir->name, "/",
+	       AFSDIR_RXKAD_KEYTAB_FILE, (char *)NULL);
+
+    r = krb5_init_context(&context);
+    if (r)
+	goto cleanup;
+
+    r = krb5_build_principal(context, &client_princ, 1, "\0", "afs", NULL);
+    if (r)
+	goto cleanup;
+
+    r = get_credv5_akimpersonate(context, keytab_name,
+				 NULL, client_princ,
+				 0, 0x7fffffff,
+				 NULL,
+				 &fake_princ);
+
+    if (r == 0) {
+	if (tkt_DeriveDesKey(get_creds_enctype(fake_princ),
+			     get_cred_keydata(fake_princ),
+			     get_cred_keylen(fake_princ),
+			     &session) != 0) {
+	    r = RXKADBADKEY;
+	    goto cleanup;
+	}
+	tclass = (struct rx_securityClass *)
+            rxkad_NewClientSecurityObject(enclevel, &session,
+					  RXKAD_TKT_TYPE_KERBEROS_V5,
+					  fake_princ->ticket.length,
+					  fake_princ->ticket.data);
+	if (tclass != NULL) {
+	    *astr = tclass;
+	    *aindex = RX_SECIDX_KAD;
+	    r = 0;
+	    goto cleanup;
+	}
+	r = 1;
+    }
+
+cleanup:
+    free(keytab_name);
+    if (fake_princ != NULL)
+	krb5_free_creds(context, fake_princ);
+    if (context != NULL)
+	krb5_free_context(context);
+    return r;
+}
+#endif
+
 static afs_int32
 GenericAuth(struct afsconf_dir *adir,
 	    struct rx_securityClass **astr,
 	    afs_int32 *aindex,
-	    rxkad_level enclevel)
+	    rxkad_level enclevel,
+	    int noauth_fallback)
 {
     char tbuffer[256];
     struct ktc_encryptionKey key, session;
@@ -80,17 +184,24 @@ GenericAuth(struct afsconf_dir *adir,
     afs_int32 ticketLen;
     afs_int32 code;
 
+#if defined(USE_RXKAD_KEYTAB) && !defined(UKERNEL)
+    /* Try to do things the v5 way, before switching down to v4 */
+    code = K5Auth(adir, astr, aindex, enclevel);
+    if (code == 0)
+	return 0;
+#endif
+
     /* first, find the right key and kvno to use */
     code = afsconf_GetLatestKey(adir, &kvno, &key);
     if (code) {
-	return QuickAuth(astr, aindex);
+	goto error;
     }
 
     /* next create random session key, using key for seed to good random */
     des_init_random_number_generator(ktc_to_cblock(&key));
     code = des_random_key(ktc_to_cblock(&session));
     if (code) {
-	return QuickAuth(astr, aindex);
+	goto error;
     }
 
     /* now create the actual ticket */
@@ -103,7 +214,7 @@ GenericAuth(struct afsconf_dir *adir,
      * name, instance and cell, start time, end time, session key to seal
      * in ticket, inet host, server name and server instance */
     if (code) {
-	return QuickAuth(astr, aindex);
+	goto error;
     }
 
     /* Next, we have ticket, kvno and session key, authenticate the connection.
@@ -116,6 +227,12 @@ GenericAuth(struct afsconf_dir *adir,
     *astr = tclass;
     *aindex = RX_SECIDX_KAD;
     return 0;
+
+ error:
+    if (noauth_fallback) {
+	return QuickAuth(astr, aindex);
+    }
+    return code;
 }
 
 /* build a fake ticket for 'afs' using keys from adir, returning an
@@ -129,7 +246,7 @@ afsconf_ClientAuth(void *arock, struct r
     afs_int32 rc;
 
     LOCK_GLOBAL_MUTEX;
-    rc = GenericAuth(adir, astr, aindex, rxkad_clear);
+    rc = GenericAuth(adir, astr, aindex, rxkad_clear, 1);
     UNLOCK_GLOBAL_MUTEX;
     return rc;
 }
@@ -147,7 +264,7 @@ afsconf_ClientAuthSecure(void *arock,
     afs_int32 rc;
 
     LOCK_GLOBAL_MUTEX;
-    rc = GenericAuth(adir, astr, aindex, rxkad_crypt);
+    rc = GenericAuth(adir, astr, aindex, rxkad_crypt, 1);
     UNLOCK_GLOBAL_MUTEX;
     return rc;
 }
@@ -231,6 +348,27 @@ afsconf_BuildServerSecurityObjects(struc
 			           struct rx_securityClass ***classes,
 			           afs_int32 *numClasses)
 {
+#ifdef USE_RXKAD_KEYTAB
+    int keytab_enable = 0;
+    char *csdb_name;
+    size_t csdblen;
+    char *keytab_name;
+    size_t ktlen;
+    csdblen = strlen(dir->name) + 1 + strlen(AFSDIR_CELLSERVDB_FILE) + 1;
+    csdb_name = malloc(csdblen);
+    ktlen = 5 + strlen(dir->name) + 1 + strlen(AFSDIR_RXKAD_KEYTAB_FILE) + 1;
+    keytab_name = malloc(ktlen);
+    if (csdb_name != NULL && keytab_name != NULL) {
+	strcompose(csdb_name, csdblen, dir->name, "/",
+	           AFSDIR_CELLSERVDB_FILE, (char *)NULL);
+	strcompose(keytab_name, ktlen, "FILE:", dir->name, "/",
+		   AFSDIR_RXKAD_KEYTAB_FILE, (char *)NULL);
+	if (rxkad_InitKeytabDecrypt(csdb_name, keytab_name) == 0)
+	    keytab_enable = 1;
+    }
+    free(csdb_name);
+    free(keytab_name);
+#endif
     if (flags & AFSCONF_SEC_OBJS_RXKAD_CRYPT)
 	*numClasses = 4;
     else
@@ -242,9 +380,18 @@ afsconf_BuildServerSecurityObjects(struc
     (*classes)[1] = NULL;
     (*classes)[2] = rxkad_NewServerSecurityObject(0, dir,
 						  afsconf_GetKey, NULL);
-    if (flags & AFSCONF_SEC_OBJS_RXKAD_CRYPT)
+#ifdef USE_RXKAD_KEYTAB
+    if (keytab_enable)
+	rxkad_BindKeytabDecrypt((*classes)[2]);
+#endif
+    if (flags & AFSCONF_SEC_OBJS_RXKAD_CRYPT) {
 	(*classes)[3] = rxkad_NewServerSecurityObject(rxkad_crypt, dir,
 						      afsconf_GetKey, NULL);
+#ifdef USE_RXKAD_KEYTAB
+	if (keytab_enable)
+	    rxkad_BindKeytabDecrypt((*classes)[3]);
+#endif
+    }
 }
 #endif
 
@@ -303,14 +450,16 @@ afsconf_PickClientSecObj(struct afsconf_
 	    return AFSCONF_NOCELLDB;
 
 	if (flags & AFSCONF_SECOPTS_LOCALAUTH) {
-	    code = afsconf_GetLatestKey(dir, 0, 0);
-	    if (code)
-		goto out;
+	    int fallback = 0;
+	    if (flags & AFSCONF_SECOPTS_FALLBACK_NULL)
+		fallback = 1;
 
+	    LOCK_GLOBAL_MUTEX;
 	    if (flags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
-		code = afsconf_ClientAuthSecure(dir, sc, scIndex);
+		code = GenericAuth(dir, sc, scIndex, rxkad_crypt, fallback);
 	    else
-		code = afsconf_ClientAuth(dir, sc, scIndex);
+		code = GenericAuth(dir, sc, scIndex, rxkad_clear, fallback);
+	    UNLOCK_GLOBAL_MUTEX;
 
 	    if (code)
 		goto out;
--- openafs-1.6.1.orig/src/bozo/Makefile.in
+++ openafs-1.6.1/src/bozo/Makefile.in
@@ -96,13 +96,13 @@ bos.o: bos.c ${INCLS} AFS_component_vers
 	$(CC) $(CFLAGS) -c ${srcdir}/bos.c
 
 bos: bos.o $(LIBS) libbos.a
-	${CC} ${CFLAGS} -o bos bos.o libbos.a $(LIBS)  ${XLIBS}
+	${CC} ${CFLAGS} -o bos bos.o libbos.a $(LIBS)  ${XLIBS} ${KRB5_LIBS}
 
 bos_util.o: bos_util.c ${INCLS} AFS_component_version_number.o ${TOP_INCDIR}/afs/bnode.h
 	$(CC) $(CFLAGS) -c ${srcdir}/bos_util.c
 
 bos_util: bos_util.o $(LIBS) 
-	${CC} ${CFLAGS} -o bos_util bos_util.o $(LIBS)  ${XLIBS}
+	${CC} ${CFLAGS} -o bos_util bos_util.o $(LIBS)  ${XLIBS} ${KRB5_LIBS}
 
 ezbnodeops.o: ezbnodeops.c ${INCLS}
 
@@ -114,7 +114,7 @@ libbos.a: bosint.xdr.o bosint.cs.o boser
 	$(RANLIB) $@
 
 bosserver: $(OBJS) $(LIBS)
-	${CC} $(CFLAGS) -o bosserver $(OBJS) ${TOP_LIBDIR}/libaudit.a $(LIBS)  ${XLIBS} 
+	${CC} $(CFLAGS) -o bosserver $(OBJS) ${TOP_LIBDIR}/libaudit.a $(LIBS)  ${XLIBS} ${KRB5_LIBS}
 
 #
 # Install targets
--- openafs-1.6.1.orig/src/bozo/bos.c
+++ openafs-1.6.1/src/bozo/bos.c
@@ -240,7 +240,7 @@ SetAuth(struct cmd_syndesc *as, void *ar
     afs_int32 flag;
     char *tp;
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     tp = as->parms[1].items->data;
     if (strcmp(tp, "on") == 0)
 	flag = 0;		/* auth req.: noauthflag is false */
@@ -305,7 +305,7 @@ Prune(struct cmd_syndesc *as, void *aroc
     struct rx_connection *tconn;
     afs_int32 flags;
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     flags = 0;
     if (as->parms[1].items)
 	flags |= BOZO_PRUNEBAK;
@@ -327,7 +327,7 @@ Exec(struct cmd_syndesc *as, void *arock
     struct rx_connection *tconn;
     afs_int32 code;
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     code = BOZO_Exec(tconn, as->parms[1].items->data);
     if (code)
 	printf("bos: failed to execute command (%s)\n", em(code));
@@ -393,7 +393,7 @@ UnInstall(struct cmd_syndesc *as, void *
     struct cmd_item *ti;
     struct rx_connection *tconn;
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     if (!as->parms[1].items) {
 	printf("bos: no files to uninstall\n");
 	return 1;
@@ -452,7 +452,7 @@ Install(struct cmd_syndesc *as, void *ar
     struct rx_call *tcall;
     char destDir[256];
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     if (!as->parms[1].items) {
 	printf("bos: no files to install\n");
 	return 1;
@@ -504,7 +504,7 @@ Shutdown(struct cmd_syndesc *as, void *a
     afs_int32 code;
     struct cmd_item *ti;
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     if (as->parms[1].items == 0) {
 	code = BOZO_ShutdownAll(tconn);
 	if (code)
@@ -611,7 +611,7 @@ SetRestartCmd(struct cmd_syndesc *as, vo
     struct rx_connection *tconn;
 
     count = 0;
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     if (as->parms[2].items) {
 	count++;
 	type = 1;
@@ -648,7 +648,7 @@ Startup(struct cmd_syndesc *as, void *ar
     afs_int32 code;
     struct cmd_item *ti;
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     if (as->parms[1].items == 0) {
 	code = BOZO_StartupAll(tconn);
 	if (code)
@@ -671,7 +671,7 @@ Restart(struct cmd_syndesc *as, void *ar
     afs_int32 code;
     struct cmd_item *ti;
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     if (as->parms[2].items) {
 	/* this is really a rebozo command */
 	if (as->parms[1].items) {
@@ -715,7 +715,7 @@ SetCellName(struct cmd_syndesc *as, void
     struct rx_connection *tconn;
     afs_int32 code;
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     code = BOZO_SetCellName(tconn, as->parms[1].items->data);
     if (code)
 	printf("bos: failed to set cell (%s)\n", em(code));
@@ -730,7 +730,7 @@ AddHost(struct cmd_syndesc *as, void *ar
     struct cmd_item *ti;
     char name[MAXHOSTCHARS];
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     for (ti = as->parms[1].items; ti; ti = ti->next) {
 	if (as->parms[2].items) {
 	    if (strlen(ti->data) > MAXHOSTCHARS - 3) {
@@ -756,7 +756,7 @@ RemoveHost(struct cmd_syndesc *as, void
     afs_int32 code;
     struct cmd_item *ti;
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     for (ti = as->parms[1].items; ti; ti = ti->next) {
 	code = BOZO_DeleteCellHost(tconn, ti->data);
 	if (code)
@@ -873,7 +873,7 @@ RemoveKey(struct cmd_syndesc *as, void *
     afs_int32 temp;
     struct cmd_item *ti;
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     for (ti = as->parms[1].items; ti; ti = ti->next) {
 	temp = atoi(ti->data);
 	code = BOZO_DeleteKey(tconn, temp);
@@ -934,7 +934,7 @@ AddSUser(struct cmd_syndesc *as, void *a
     struct cmd_item *ti;
 
     failed = 0;
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     for (ti = as->parms[1].items; ti; ti = ti->next) {
 	code = BOZO_AddSUser(tconn, ti->data);
 	if (code) {
@@ -954,7 +954,7 @@ RemoveSUser(struct cmd_syndesc *as, void
     int failed;
 
     failed = 0;
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     for (ti = as->parms[1].items; ti; ti = ti->next) {
 	code = BOZO_DeleteSUser(tconn, ti->data);
 	if (code) {
@@ -1053,7 +1053,7 @@ CreateServer(struct cmd_syndesc *as, voi
     int i;
     char *type, *name, *notifier = NONOTIFIER;
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     for (i = 0; i < 6; i++)
 	parms[i] = "";
     for (i = 0, ti = as->parms[3].items; (ti && i < 6); ti = ti->next, i++) {
@@ -1083,7 +1083,7 @@ DeleteServer(struct cmd_syndesc *as, voi
     struct cmd_item *ti;
 
     code = 0;
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     for (ti = as->parms[1].items; ti; ti = ti->next) {
 	code = BOZO_DeleteBnode(tconn, ti->data);
 	if (code) {
@@ -1105,7 +1105,7 @@ StartServer(struct cmd_syndesc *as, void
     struct cmd_item *ti;
 
     code = 0;
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     for (ti = as->parms[1].items; ti; ti = ti->next) {
 	code = BOZO_SetStatus(tconn, ti->data, BSTAT_NORMAL);
 	if (code)
@@ -1123,7 +1123,7 @@ StopServer(struct cmd_syndesc *as, void
     struct cmd_item *ti;
 
     code = 0;
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     for (ti = as->parms[1].items; ti; ti = ti->next) {
 	code = BOZO_SetStatus(tconn, ti->data, BSTAT_SHUTDOWN);
 	if (code)
@@ -1385,7 +1385,7 @@ GetLogCmd(struct cmd_syndesc *as, void *
     int error;
 
     printf("Fetching log file '%s'...\n", as->parms[1].items->data);
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     tcall = rx_NewCall(tconn);
     code = StartBOZO_GetLog(tcall, as->parms[1].items->data);
     if (code) {
@@ -1463,7 +1463,7 @@ SalvageCmd(struct cmd_syndesc *as, void
     memset(&mrafsParm, 0, sizeof(mrafsParm));
 
     /* parm 0 is machine name, 1 is partition, 2 is volume, 3 is -all flag */
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
 
     tp = &tname[0];
 
@@ -1592,9 +1592,18 @@ SalvageCmd(struct cmd_syndesc *as, void
 
 	for (i = MRAFS_OFFSET; i < ADDPARMOFFSET; i++) {
 	    if (as->parms[i].items) {
-		printf(" %s only possible for MR-AFS fileserver.\n",
-		       as->parms[i].name);
-		stop = 1;
+		if (i == MRAFS_OFFSET + 5) { /* -salvagedirs */
+		    if (as->parms[4].items) { /* -all */
+			mrafsParm.Optsalvagedirs = 1; /* Let this one slide. */
+		    } else {
+			printf(" -salvagedirs only possible with -all.\n");
+			stop = 1;
+		    }
+		} else {
+		    printf(" %s only possible for MR-AFS fileserver.\n",
+			   as->parms[i].name);
+		    stop = 1;
+		}
 	    }
 	}
 	if (stop)
@@ -1878,7 +1887,7 @@ SetRestrict(struct cmd_syndesc *as, void
     struct rx_connection *tconn;
     afs_int32 code, val;
 
-    tconn = GetConn(as, 0);
+    tconn = GetConn(as, 1);
     util_GetInt32(as->parms[1].items->data, &val);
     code = BOZO_SetRestrictedMode(tconn, val);
     if (code)
--- openafs-1.6.1.orig/src/bucoord/Makefile.in
+++ openafs-1.6.1/src/bucoord/Makefile.in
@@ -67,7 +67,7 @@ main.o: AFS_component_version_number.c
 $(BACKOBJS): bc.h ${TOP_INCDIR}/afs/butc.h
 
 backup:  $(BACKOBJS) ${LIBS}
-	${CC} ${CFLAGS} -o backup $(BACKOBJS) ${LIBS} ${XLIBS}
+	${CC} ${CFLAGS} -o backup $(BACKOBJS) ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 bc.h: bucoord_errs.c
 
--- openafs-1.6.1.orig/src/budb/Makefile.in
+++ openafs-1.6.1/src/budb/Makefile.in
@@ -96,7 +96,7 @@ struct_ops.o: budb_errs.h ${TOP_INCDIR}/
 server.o: server.c budb_errs.h ${INCLS} AFS_component_version_number.c
 
 budb_server: $(SERVER_OBJS) ${LIBS} ${TOP_INCDIR}/afs/budb_client.h
-	${CC} ${LDFLAGS} -o budb_server $(SERVER_OBJS) ${LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o budb_server $(SERVER_OBJS) ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 budb.cs.c: budb.rg
 	${RXGEN} -A -u -C -o $@ ${srcdir}/budb.rg
--- openafs-1.6.1.orig/src/butc/Makefile.in
+++ openafs-1.6.1/src/butc/Makefile.in
@@ -56,15 +56,15 @@ SOBJS=dbentries.o tcprocs.o lwps.o tcmai
 all: butc read_tape
 
 butc_test: ${TESTOBJS} ${LIBS} ${INCLS} ${HACKS}
-	${CC} ${CFLAGS} ${TESTOBJS} ${LIBS} ${XLIBS} -o butc_test
+	${CC} ${CFLAGS} ${TESTOBJS} ${LIBS} ${XLIBS} ${KRB5_LIBS} -o butc_test
 
 tdump: tdump.c AFS_component_version_number.c
 	${CC} ${CFLAGS} ${srcdir}/tdump.c -o tdump
 
 butc: ${SOBJS} ${LIBS} ${INCLS} ${HACKS}
 	@case ${SYS_NAME} in \
-	  rs_aix*) ${CC} ${CFLAGS} ${SOBJS} ${LIBS} ${XLIBS} /usr/lib/libc_r.a -o butc;; \
-	  *)        ${CC} ${CFLAGS} ${SOBJS} ${LIBS} ${XLIBS} -o butc;; \
+	  rs_aix*) ${CC} ${CFLAGS} ${SOBJS} ${LIBS} ${XLIBS} ${KRB5_LIBS} /usr/lib/libc_r.a -o butc;; \
+	  *)        ${CC} ${CFLAGS} ${SOBJS} ${LIBS} ${XLIBS} ${KRB5_LIBS} -o butc;; \
 	esac
 
 tcmain.o: tcmain.c ${INCLS} AFS_component_version_number.c
--- openafs-1.6.1.orig/src/config/Makefile.config.in
+++ openafs-1.6.1/src/config/Makefile.config.in
@@ -47,6 +47,7 @@ FSINCLUDES = @FSINCLUDES@
 INCLUDE_LIBINTL = @INCLUDE_libintl@
 KERN_DBG = @KERN_DBG@
 KERN_OPTMZ = @KERN_OPTMZ@
+KRB5_LIBS = @KRB5_LIBS@
 LD = @LD@
 LEX = @LEX@
 LIB_AFSDB = @LIB_AFSDB@
--- openafs-1.6.1.orig/src/dviced/Makefile.in
+++ openafs-1.6.1/src/dviced/Makefile.in
@@ -211,7 +211,7 @@ state_analyzer.o: ${TVICED}/state_analyz
 	${CCRULE}
 
 dafileserver: ${objects} ${LIBS}
-	${CC} ${LDFLAGS} -o dafileserver ${objects} ${LIBS} ${MT_LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o dafileserver ${objects} ${LIBS} ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 state_analyzer: ${SDBGOBJS}
 	${CC} ${LDFLAGS} -o state_analyzer ${SDBGOBJS} ${MT_LIBS} ${XLIBS}
--- openafs-1.6.1.orig/src/dvolser/Makefile.in
+++ openafs-1.6.1/src/dvolser/Makefile.in
@@ -218,7 +218,7 @@ afsint.xdr.o: ${FSINT}/afsint.xdr.c
 	${COMPILE}
 
 davolserver: ${objects} ${LIBS}
-	${CC} ${LDFLAGS} -o davolserver ${objects} ${LIBS} ${MT_LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o davolserver ${objects} ${LIBS} ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 install: davolserver
 	${INSTALL} -d ${DESTDIR}${afssrvlibexecdir}
--- openafs-1.6.1.orig/src/fsprobe/Makefile.in
+++ openafs-1.6.1/src/fsprobe/Makefile.in
@@ -51,7 +51,7 @@ fsprobe_callback.o: fsprobe_callback.c $
 
 fsprobe_test: fsprobe_test.o libfsprobe.a ${LIBS}
 	${CC} ${CFLAGS} -o fsprobe_test fsprobe_test.o libfsprobe.a \
-		${LIBS} ${XLIBS}
+		${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 #
 # Install targets
--- openafs-1.6.1.orig/src/kauth/Makefile.in
+++ openafs-1.6.1/src/kauth/Makefile.in
@@ -89,7 +89,7 @@ test tests: all
 	cd test; $(MAKE)
 
 kaserver: kautils.o kalocalcell.o kadatabase.o kaprocs.o kalog.o kauth.ss.o kauth.xdr.o kaserver.o kaaux.o krb_udp.o kaauxdb.o $(LIBS) 
-	${CC} ${LDFLAGS} -o kaserver kaserver.o kautils.o kalocalcell.o kadatabase.o krb_udp.o kaprocs.o kalog.o kauth.ss.o kauth.xdr.o kaaux.o kaauxdb.o $(LIBS) ${XLIBS} ${TOP_LIBDIR}/libaudit.a
+	${CC} ${LDFLAGS} -o kaserver kaserver.o kautils.o kalocalcell.o kadatabase.o krb_udp.o kaprocs.o kalog.o kauth.ss.o kauth.xdr.o kaaux.o kaauxdb.o $(LIBS) ${XLIBS} ${TOP_LIBDIR}/libaudit.a ${KRB5_LIBS}
 
 kaserver.o: kaserver.c ${INCLS} AFS_component_version_number.o
 
@@ -175,19 +175,19 @@ krb_tf.o: krb_tf.c ${INCLS}
 
 kas: kauth.h kautils.h admin_tools.o libkauth.a $(LIBS) kas.o kkids.o
 	${CC} ${LDFLAGS} -o kas kas.o admin_tools.o kkids.o libkauth.a \
-			${LIBS} ${XLIBS}
+			${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 klog: AFS_component_version_number.o kauth.h kautils.h libkauth.a $(LIBS) \
 	klog.o
-	${CC} ${LDFLAGS} -o klog klog.o libkauth.a ${LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o klog klog.o libkauth.a ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 klog.o: klog.c kauth.h kautils.h AFS_component_version_number.o
 
 klog.krb: kauth.h kautils.h libkauth.krb.a $(KLIBS) klog.o
-	${CC} ${LDFLAGS} -o klog.krb klog.o libkauth.krb.a ${KLIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o klog.krb klog.o libkauth.krb.a ${KLIBS} ${XLIBS} ${KRB5_LIBS}
 
 knfs: kauth.h kautils.h libkauth.a $(LIBS) knfs.o
-	${CC} ${LDFLAGS} -o knfs knfs.o libkauth.a ${LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o knfs knfs.o libkauth.a ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 knfs.o: knfs.c AFS_component_version_number.o
 
@@ -195,22 +195,22 @@ klogin.o: klogin.c ${INCLS} AFS_componen
 	${CC} ${CFLAGS} -c ${srcdir}/klogin.c -DKAUTH
 
 klogin: libkauth.a $(LIBS) klogin.o
-	${CC} ${LDFLAGS} -o klogin klogin.o libkauth.a ${LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o klogin klogin.o libkauth.a ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 klogin.krb: libkauth.a $(KLIBS) klogin.o
-	${CC} ${LDFLAGS} -o klogin.krb klogin.o libkauth.krb.a ${KLIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o klogin.krb klogin.o libkauth.krb.a ${KLIBS} ${XLIBS} ${KRB5_LIBS}
 
 kpasswd.o: kauth.h kautils.h ${INCLS} kpasswd.c AFS_component_version_number.o
 	${CC} ${CFLAGS} -c ${srcdir}/kpasswd.c 
 
 kpasswd: kauth.h kautils.h libkauth.a $(LIBS) kpasswd.o kkids.o
-	${CC} ${LDFLAGS} -o kpasswd kpasswd.o kkids.o libkauth.a ${LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o kpasswd kpasswd.o kkids.o libkauth.a ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 kpwvalid.o: kpwvalid.c AFS_component_version_number.o
 	${CC} ${CFLAGS} -c ${srcdir}/kpwvalid.c
 
 kpwvalid: kpwvalid.o $(LIBS)
-	${CC} ${LDFLAGS} -o kpwvalid kpwvalid.o ${LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o kpwvalid kpwvalid.o ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 user.krb.o: user.c ${INCLS} ${TOP_INCDIR}/afs/vice.h
 	${CCOBJ} ${CFLAGS} -DAFS_KERBEROS_ENV -c ${srcdir}/user.c -o user.krb.o
@@ -219,7 +219,7 @@ user.o: user.c ${INCLS} ${TOP_INCDIR}/af
 	${CCOBJ} ${CFLAGS} -c ${srcdir}/user.c
 
 kdb: kdb.o ${INCLS} ${LIBS} libkauth.a
-	${CC} ${LDFLAGS} -o kdb kdb.o libkauth.a ${LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o kdb kdb.o libkauth.a ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 kdb.o: kdb.c AFS_component_version_number.o
 
@@ -232,12 +232,12 @@ krb_udp: krb_udp.o libkauth.a $(KLIBS)
 ka-forwarder.o: ka-forwarder.c
 
 ka-forwarder: ka-forwarder.o
-	${CC} -o $@ ${CFLAGS} ka-forwarder.o ${LIBS} ${XLIBS}
+	${CC} -o $@ ${CFLAGS} ka-forwarder.o ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 rebuild.o: rebuild.c $(INCLS) AFS_component_version_number.o
 
 rebuild: rebuild.o kautils.o $(LIBS)
-	${CC} ${LDFLAGS} -o rebuild rebuild.o kautils.o $(LIBS) ${XLIBS}
+	${CC} ${LDFLAGS} -o rebuild rebuild.o kautils.o $(LIBS) ${XLIBS} ${KRB5_LIBS}
 
 #
 # Install targets
--- openafs-1.6.1.orig/src/libacl/aclprocs.c
+++ openafs-1.6.1/src/libacl/aclprocs.c
@@ -23,13 +23,13 @@
 #else
 #include <netinet/in.h>
 #endif
+#include <limits.h>
 #include <string.h>
 #include <rx/xdr.h>
 #include <rx/rx.h>
 #include <afs/ptclient.h>
 #include <afs/ptuser.h>
 #include "acl.h"
-
 #ifdef AFS_PTHREAD_ENV
 #include <assert.h>
 #include <pthread.h>
@@ -251,7 +251,7 @@ acl_Internalize_pr(int (*func)(namelist
 
     if (sscanf(elist, "%d\n%d\n", &p, &n) != 2)
 	return -1;
-    if (p + n > ACL_MAXENTRIES)
+    if (p < 0 || n < 0 || p > INT_MAX - n || p + n > ACL_MAXENTRIES)
 	return (-1);
     acl_NewACL(p + n, acl);
     (*acl)->total = p + n;
@@ -276,7 +276,7 @@ acl_Internalize_pr(int (*func)(namelist
     nextc++;			/* now at the beginning of the entry list */
     for (i = 0; i < (*acl)->positive; i++) {
 	int k;
-	if (sscanf(nextc, "%s\t%d\n", lnames.namelist_val[i], &k) != 2) {
+	if (sscanf(nextc, "%63s\t%d\n", lnames.namelist_val[i], &k) != 2) {
 	    free(lnames.namelist_val);
 	    return (-1);
 	}
@@ -288,7 +288,7 @@ acl_Internalize_pr(int (*func)(namelist
     for (i = (*acl)->total - 1; i >= (*acl)->total - (*acl)->negative;
 	 i--, j++) {
 	if (sscanf
-	    (nextc, "%s\t%d\n", lnames.namelist_val[j],
+	    (nextc, "%63s\t%d\n", lnames.namelist_val[j],
 	     &((*acl)->entries[j].rights)) != 2) {
 	    free(lnames.namelist_val);
 	    return (-1);
--- openafs-1.6.1.orig/src/libadmin/client/afs_clientAdmin.c
+++ openafs-1.6.1/src/libadmin/client/afs_clientAdmin.c
@@ -1542,7 +1542,7 @@ afsclient_ACLEntryAdd(const char *direct
      */
 
     is_dfs =
-	sscanf(old_acl_string, "%d dfs:%d %s", &cur_acl.nplus, &cur_acl.dfs,
+	sscanf(old_acl_string, "%d dfs:%d %1024s", &cur_acl.nplus, &cur_acl.dfs,
 	       cur_acl.cell);
     ptr = strchr(old_acl_string, '\n');
     ptr++;
@@ -1567,7 +1567,7 @@ afsclient_ACLEntryAdd(const char *direct
      */
 
     for (i = 0; i < (cur_acl.nplus + cur_acl.nminus); i++) {
-	sscanf(ptr, "%s%d\n", cur_user, &cur_user_acl);
+	sscanf(ptr, "%63s%d\n", cur_user, &cur_user_acl);
 	/*
 	 * Skip the entry for the user we are replacing/adding
 	 */
--- openafs-1.6.1.orig/src/libafsauthent/Makefile.in
+++ openafs-1.6.1/src/libafsauthent/Makefile.in
@@ -36,7 +36,7 @@ AUTHOBJS = \
 	writeconfig.o \
 	authcon.o \
 	ktc_errors.o \
-	acfg_errors.o
+	acfg_errors.o @MAKE_KRB5@ akimpersonate.o akimpersonate_v5gen.o
 
 KAUTHOBJS = \
 	kauth.xdr.o \
@@ -69,7 +69,7 @@ UTILOBJS = \
 	fileutil.o
 
 RXKADOBJS = \
-	rxkad_errs.o
+	rxkad_errs.o @MAKE_KRB5@ ticket5_keytab.o
 
 SYSOBJS = \
 	rmtsysc.o \
@@ -131,7 +131,13 @@ writeconfig.o: ${AUTH}/writeconfig.c
 	${CCRULE} -I../auth
 
 authcon.o: ${AUTH}/authcon.c
-	${CCRULE} -I../auth
+	${CCRULE} -I../auth @KRB5_CPPFLAGS@
+
+akimpersonate.o: ${AUTH}/akimpersonate.c
+	${CCRULE} -I../auth @KRB5_CPPFLAGS@
+
+akimpersonate_v5gen.o: ${AUTH}/akimpersonate_v5gen.c
+	${CCRULE} -I../auth @KRB5_CPPFLAGS@ -I../rxkad
 
 ktc_errors.o: ${AUTH}/ktc_errors.c
 	${CCRULE}
@@ -214,6 +220,9 @@ pthread_glock.o: ${UTIL}/pthread_glock.c
 rxkad_errs.o: ${RXKAD}/rxkad_errs.c
 	${CCRULE}
 
+ticket5_keytab.o: ${RXKAD}/ticket5_keytab.c
+	${CCRULE} @KRB5_CPPFLAGS@
+
 ptclient.o: ${PTSERVER}/ptclient.c
 	${CCRULE} -I../ptserver
 
--- openafs-1.6.1.orig/src/packaging/Debian/module/sysname
+++ openafs-1.6.1/src/packaging/Debian/module/sysname
@@ -21,7 +21,7 @@ alpha)
         ;;
     esac
     ;;
-arm|armel|armv5tel)
+arm|armel|armhf|armv5tel)
     case $KVERS in
     2.4*)
         echo arm_linux24
--- openafs-1.6.1.orig/src/packaging/Debian/sysname
+++ openafs-1.6.1/src/packaging/Debian/sysname
@@ -9,7 +9,7 @@ case `dpkg --print-architecture` in
 alpha)
     echo alpha_linux_26
     ;;
-arm|armel|armv5tel)
+arm|armel|armhf|armv5tel)
     echo arm_linux26
     ;;
 amd64)
--- openafs-1.6.1.orig/src/pam/Makefile.in
+++ openafs-1.6.1/src/pam/Makefile.in
@@ -22,9 +22,10 @@ AFSLIBS = ${TOP_LIBDIR}/librxkad.a ${TOP
 
 LDFLAGS = ${SHLIB_LDFLAGS}
    LIBS = ${TOP_LIBDIR}/libafsauthent_pic.a ${TOP_LIBDIR}/libafsrpc_pic.a \
-	  ${PAM_LIBS} @LIB_AFSDB@ ${MT_LIBS}
+	  ${PAM_LIBS} ${KRB5_LIBS} @LIB_AFSDB@ ${MT_LIBS}
   KLIBS = ktc_krb.o ${TOP_LIBDIR}/libafsauthent_pic.a \
-	  ${TOP_LIBDIR}/libafsrpc_pic.a ${PAM_LIBS} @LIB_AFSDB@ ${MT_LIBS}
+	  ${TOP_LIBDIR}/libafsrpc_pic.a ${PAM_LIBS} ${KRB5_LIBS} \
+	  @LIB_AFSDB@ ${MT_LIBS}
  SHOBJS = afs_account.o afs_session.o afs_password.o \
 	  afs_pam_msg.o afs_message.o AFS_component_version_number.o
    OBJS = $(SHOBJS) test_pam.o
--- openafs-1.6.1.orig/src/ptserver/Makefile.in
+++ openafs-1.6.1/src/ptserver/Makefile.in
@@ -96,7 +96,7 @@ ${TOP_INCDIR}/afs/ptserver.h: ptserver.h
 # Build targets
 #
 ptserver: ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o $(LIBS) ${TOP_LIBDIR}/libaudit.a map.o
-	$(CC) ${CFLAGS} -o ptserver ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o map.o $(LIBS) ${XLIBS} ${TOP_LIBDIR}/libaudit.a
+	$(CC) ${CFLAGS} -o ptserver ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o map.o $(LIBS) ${XLIBS} ${TOP_LIBDIR}/libaudit.a ${KRB5_LIBS}
 
 ptserver.o: ptserver.c ${INCLS} AFS_component_version_number.c
 
@@ -146,10 +146,10 @@ display.o: display.c ${INCLS}
 db_verify.o: db_verify.c ${INCLS} AFS_component_version_number.c
 
 db_verify: db_verify.o pterror.o display.o $(LIBS)
-	$(CC) ${CFLAGS} -o db_verify db_verify.o display.o pterror.o $(LIBS) ${XLIBS}
+	$(CC) ${CFLAGS} -o db_verify db_verify.o display.o pterror.o $(LIBS) ${XLIBS} ${KRB5_LIBS}
 
 ptclient: ptclient.o display.o libprot.a $(LIBS)
-	$(CC) ${CFLAGS} -o ptclient ptclient.o display.o libprot.a $(LIBS) ${XLIBS}
+	$(CC) ${CFLAGS} -o ptclient ptclient.o display.o libprot.a $(LIBS) ${XLIBS} ${KRB5_LIBS}
 
 ptclient.o: ptclient.c ${INCLS} AFS_component_version_number.c
 
@@ -165,32 +165,32 @@ libprot.a: ptuser.o pterror.o ptint.cs.o
 	$(RANLIB) $@
 
 pts: pts.o libprot.a ${TOP_LIBDIR}/libcmd.a $(LIBS)
-	$(CC) ${CFLAGS} -o pts pts.o ${TOP_LIBDIR}/libcmd.a libprot.a ${LIBS} ${XLIBS}
+	$(CC) ${CFLAGS} -o pts pts.o ${TOP_LIBDIR}/libcmd.a libprot.a ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 pts.o: pts.c ${LINCLS} ${TOP_INCDIR}/afs/cmd.h AFS_component_version_number.c
 
 readgroup: readgroup.o libprot.a $(LIBS)
-	$(CC) ${CFLAGS} -o readgroup readgroup.o libprot.a ${LIBS} ${XLIBS}
+	$(CC) ${CFLAGS} -o readgroup readgroup.o libprot.a ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 readgroup.o: readgroup.c ${LINCLS} AFS_component_version_number.c
 
 readpwd: readpwd.o libprot.a $(LIBS)
-	$(CC) ${CFLAGS} -o readpwd readpwd.o libprot.a ${LIBS} ${XLIBS}
+	$(CC) ${CFLAGS} -o readpwd readpwd.o libprot.a ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 readpwd.o: readpwd.c ${LINCLS} AFS_component_version_number.c
 
 testpt: testpt.o libprot.a ${TOP_LIBDIR}/libcmd.a $(LIBS)
 	case "$(SYS_NAME)" in \
 	*_darwin_12 ) \
-		$(CC) ${CFLAGS} -o testpt testpt.o ${TOP_LIBDIR}/libcmd.a libprot.a $(LIBS) ;; \
+		$(CC) ${CFLAGS} -o testpt testpt.o ${TOP_LIBDIR}/libcmd.a libprot.a $(LIBS) ${KRB5_LIBS} ;; \
 	* ) \
-		$(CC) ${CFLAGS} -o testpt testpt.o -lm ${TOP_LIBDIR}/libcmd.a libprot.a $(LIBS) ${XLIBS} ;; \
+		$(CC) ${CFLAGS} -o testpt testpt.o -lm ${TOP_LIBDIR}/libcmd.a libprot.a $(LIBS) ${XLIBS} ${KRB5_LIBS} ;; \
 	esac
 
 testpt.o: testpt.c ${INCLS} ${TOP_INCDIR}/afs/cmd.h AFS_component_version_number.c
 
 pt_util: pt_util.o ptutils.o ubik.o utils.o map.o libprot.a $(LIBS)
-	$(CC) ${CFLAGS} -o pt_util pt_util.o ptutils.o ubik.o utils.o map.o libprot.a ${TOP_LIBDIR}/libcmd.a $(LIBS) ${XLIBS}
+	$(CC) ${CFLAGS} -o pt_util pt_util.o ptutils.o ubik.o utils.o map.o libprot.a ${TOP_LIBDIR}/libcmd.a $(LIBS) ${XLIBS} ${KRB5_LIBS}
 
 ubik.o: ubik.c ${INCLS}
 
--- openafs-1.6.1.orig/src/ptserver/ptprocs.c
+++ openafs-1.6.1/src/ptserver/ptprocs.c
@@ -345,13 +345,19 @@ newEntry(struct rx_call *call, char anam
      * automatic id assignment.
      */
     code = WhoIsThisWithName(call, tt, cid, cname);
-    if (code != 2) {		/* 2 specifies that this is a foreign cell request */
-	if (code)
-	    ABORT_WITH(tt, PRPERM);
-	admin = IsAMemberOf(tt, *cid, SYSADMINID);
-    } else {
-	admin = ((!restricted && !strcmp(aname, cname))) || IsAMemberOf(tt, *cid, SYSADMINID);
-	oid = *cid = SYSADMINID;
+    if (code && code != 2)
+	ABORT_WITH(tt, PRPERM);
+    admin = IsAMemberOf(tt, *cid, SYSADMINID);
+    if (code == 2 /* foreign cell request */) {
+	if (!restricted && (strcmp(aname, cname) == 0)) {
+	    /* can't autoregister while providing an owner id */
+	    if (oid != 0)
+		ABORT_WITH(tt, PRPERM);
+
+	    admin = 1;
+	    oid = SYSADMINID;
+	    *cid = SYSADMINID;
+	}
     }
     if (!CreateOK(tt, *cid, oid, flag, admin))
 	ABORT_WITH(tt, PRPERM);
@@ -679,7 +685,7 @@ idToName(struct rx_call *call, idlist *a
     size = aid->idlist_len;
     if (size == 0)
 	return 0;
-    if (size < 0)
+    if (size < 0 || size > INT_MAX / PR_MAXNAMELEN)
 	return PRTOOMANY;
     aname->namelist_val = (prname *) malloc(size * PR_MAXNAMELEN);
     aname->namelist_len = 0;
--- openafs-1.6.1.orig/src/ptserver/ptserver.c
+++ openafs-1.6.1/src/ptserver/ptserver.c
@@ -210,7 +210,6 @@ main(int argc, char **argv)
     struct rx_service *tservice;
     struct rx_securityClass **securityClasses;
     afs_int32 numClasses;
-    int kerberosKeys;		/* set if found some keys */
     int lwps = 3;
     char clones[MAXHOSTSPERCELL];
     afs_uint32 host = htonl(INADDR_ANY);
@@ -455,16 +454,6 @@ main(int argc, char **argv)
     pr_realmName = info.name;
 
     {
-	afs_int32 kvno;		/* see if there is a KeyFile here */
-	struct ktc_encryptionKey key;
-	code = afsconf_GetLatestKey(prdir, &kvno, &key);
-	kerberosKeys = (code == 0);
-	if (!kerberosKeys)
-	    printf
-		("ptserver: can't find any Kerberos keys, code = %d, ignoring\n",
-		 code);
-    }
-    if (kerberosKeys) {
 	/* initialize ubik */
 	ubik_CRXSecurityProc = afsconf_ClientAuth;
 	ubik_CRXSecurityRock = prdir;
--- openafs-1.6.1.orig/src/ptserver/ptuser.c
+++ openafs-1.6.1/src/ptserver/ptuser.c
@@ -292,16 +292,13 @@ pr_Initialize(IN afs_int32 secLevel, IN
      * to force use of the KeyFile.  secLevel == 0 implies -noauth was
      * specified. */
     if (secLevel == 2) {
-	code = afsconf_GetLatestKey(tdir, 0, 0);
+	secFlags = AFSCONF_SECOPTS_LOCALAUTH;
+	secFlags |= AFSCONF_SECOPTS_ALWAYSENCRYPT;
+	code = afsconf_PickClientSecObj(tdir, secFlags, &info, cell, &sc, &scIndex, NULL);
 	if (code) {
 	    afs_com_err(whoami, code, "(getting key from local KeyFile)\n");
-	} else {
-	    /* If secLevel is two assume we're on a file server and use
-	     * ClientAuthSecure if possible. */
-	    code = afsconf_ClientAuthSecure(tdir, &sc, &scIndex);
-	    if (code)
-		afs_com_err(whoami, code, "(calling client secure)\n");
         }
+
     } else if (secLevel > 0) {
 	secFlags = 0;
 	if (secLevel > 1)
--- openafs-1.6.1.orig/src/rx/rx.c
+++ openafs-1.6.1/src/rx/rx.c
@@ -4551,12 +4551,20 @@ rxi_ReceiveAckPacket(struct rx_call *cal
 	rx_packetread(np, rx_AckDataSize(ap->nAcks) + (int)sizeof(afs_int32),
 		      (int)sizeof(afs_int32), &tSize);
 	tSize = (afs_uint32) ntohl(tSize);
+	if (tSize > RX_MAX_PACKET_SIZE)
+	    tSize = RX_MAX_PACKET_SIZE;
+	if (tSize < RX_MIN_PACKET_SIZE)
+	    tSize = RX_MIN_PACKET_SIZE;
 	peer->natMTU = rxi_AdjustIfMTU(MIN(tSize, peer->ifMTU));
 
 	/* Get the maximum packet size to send to this peer */
 	rx_packetread(np, rx_AckDataSize(ap->nAcks), (int)sizeof(afs_int32),
 		      &tSize);
 	tSize = (afs_uint32) ntohl(tSize);
+	if (tSize > RX_MAX_PACKET_SIZE)
+	    tSize = RX_MAX_PACKET_SIZE;
+	if (tSize < RX_MIN_PACKET_SIZE)
+	    tSize = RX_MIN_PACKET_SIZE;
 	tSize = (afs_uint32) MIN(tSize, rx_MyMaxSendSize);
 	tSize = rxi_AdjustMaxMTU(peer->natMTU, tSize);
 
@@ -4578,6 +4586,10 @@ rxi_ReceiveAckPacket(struct rx_call *cal
 			  rx_AckDataSize(ap->nAcks) + 2 * (int)sizeof(afs_int32),
 			  (int)sizeof(afs_int32), &tSize);
 	    tSize = (afs_uint32) ntohl(tSize);	/* peer's receive window, if it's */
+	    if (tSize == 0)
+		tSize = 1;
+	    if (tSize >= rx_maxSendWindow)
+		tSize = rx_maxSendWindow;
 	    if (tSize < call->twind) {	/* smaller than our send */
 		call->twind = tSize;	/* window, we must send less... */
 		call->ssthresh = MIN(call->twind, call->ssthresh);
@@ -4599,6 +4611,10 @@ rxi_ReceiveAckPacket(struct rx_call *cal
 			  rx_AckDataSize(ap->nAcks) + 2 * (int)sizeof(afs_int32),
 			  sizeof(afs_int32), &tSize);
 	    tSize = (afs_uint32) ntohl(tSize);
+	    if (tSize == 0)
+		tSize = 1;
+	    if (tSize >= rx_maxSendWindow)
+		tSize = rx_maxSendWindow;
 	    /*
 	     * As of AFS 3.5 we set the send window to match the receive window.
 	     */
@@ -4767,6 +4783,30 @@ rxi_ReceiveAckPacket(struct rx_call *cal
     return np;
 }
 
+/**
+ * Schedule a connection abort to be sent after some delay.
+ *
+ * @param[in] conn The connection to send the abort on.
+ * @param[in] msec The number of milliseconds to wait before sending.
+ *
+ * @pre conn_data_lock must be held
+ */
+static void
+rxi_SendConnectionAbortLater(struct rx_connection *conn, int msec)
+{
+    struct clock when, now;
+    if (!conn->error) {
+	return;
+    }
+    if (!conn->delayedAbortEvent) {
+	clock_GetTime(&now);
+	when = now;
+	clock_Addmsec(&when, msec);
+	conn->delayedAbortEvent =
+	    rxevent_PostNow(&when, &now, rxi_SendDelayedConnAbort, conn, 0);
+    }
+}
+
 /* Received a response to a challenge packet */
 struct rx_packet *
 rxi_ReceiveResponsePacket(struct rx_connection *conn,
@@ -4786,13 +4826,12 @@ rxi_ReceiveResponsePacket(struct rx_conn
     error = RXS_CheckResponse(conn->securityObject, conn, np);
     if (error) {
 	/* If the response is invalid, reset the connection, sending
-	 * an abort to the peer */
-#ifndef KERNEL
-	rxi_Delay(1);
-#endif
+	 * an abort to the peer. Send the abort with a 1 second delay,
+	 * to avoid a peer hammering us by constantly recreating a
+	 * connection with bad credentials. */
 	rxi_ConnectionError(conn, error);
 	MUTEX_ENTER(&conn->conn_data_lock);
-	np = rxi_SendConnectionAbort(conn, np, istack, 0);
+	rxi_SendConnectionAbortLater(conn, 1000);
 	MUTEX_EXIT(&conn->conn_data_lock);
 	return np;
     } else {
@@ -5182,7 +5221,6 @@ rxi_SendConnectionAbort(struct rx_connec
 			struct rx_packet *packet, int istack, int force)
 {
     afs_int32 error;
-    struct clock when, now;
 
     if (!conn->error)
 	return packet;
@@ -5204,12 +5242,8 @@ rxi_SendConnectionAbort(struct rx_connec
 			    RX_PACKET_TYPE_ABORT, (char *)&error,
 			    sizeof(error), istack);
 	MUTEX_ENTER(&conn->conn_data_lock);
-    } else if (!conn->delayedAbortEvent) {
-	clock_GetTime(&now);
-	when = now;
-	clock_Addmsec(&when, rxi_connAbortDelay);
-	conn->delayedAbortEvent =
-	    rxevent_PostNow(&when, &now, rxi_SendDelayedConnAbort, conn, 0);
+    } else {
+	rxi_SendConnectionAbortLater(conn, rxi_connAbortDelay);
     }
     return packet;
 }
@@ -5488,6 +5522,9 @@ rxi_ResetCall(struct rx_call *call, int
     int	reason;			 Reason an acknowledge was prompted
 */
 
+#define RX_ZEROS 1024
+static char rx_zeros[RX_ZEROS];
+
 struct rx_packet *
 rxi_SendAck(struct rx_call *call,
 	    struct rx_packet *optionalPacket, int serial, int reason,
@@ -5643,6 +5680,11 @@ rxi_SendAck(struct rx_call *call,
     ap->nAcks = offset;
     p->length = rx_AckDataSize(offset) + 4 * sizeof(afs_int32);
 
+    /* Must zero the 3 octets that rx_AckDataSize skips at the end of the
+     * ACK list.
+     */
+    rx_packetwrite(p, rx_AckDataSize(offset) - 3, 3, rx_zeros);
+
     /* these are new for AFS 3.3 */
     templ = rxi_AdjustMaxMTU(call->conn->peer->ifMTU, rx_maxReceiveSize);
     templ = htonl(templ);
@@ -5661,6 +5703,8 @@ rxi_SendAck(struct rx_call *call,
     rx_packetwrite(p, rx_AckDataSize(offset) + 3 * sizeof(afs_int32),
 		   sizeof(afs_int32), &templ);
 
+    p->length = rx_AckDataSize(offset) + 4 * sizeof(afs_int32);
+
     p->header.serviceId = call->conn->serviceId;
     p->header.cid = (call->conn->cid | call->channel);
     p->header.callNumber = *call->callNumber;
@@ -5674,19 +5718,20 @@ rxi_SendAck(struct rx_call *call,
 #ifdef ADAPT_WINDOW
 	clock_GetTime(&call->pingRequestTime);
 #endif
-	if (padbytes) {
-	    p->length = padbytes +
-		rx_AckDataSize(call->rwind) + 4 * sizeof(afs_int32);
-
-	    while (padbytes--)
-		/* not fast but we can potentially use this if truncated
-		 * fragments are delivered to figure out the mtu.
-		 */
-		rx_packetwrite(p, rx_AckDataSize(offset) + 4 *
-			       sizeof(afs_int32), sizeof(afs_int32),
-			       &padbytes);
+    }
+
+    while (padbytes > 0) {
+	if (padbytes > RX_ZEROS) {
+	    rx_packetwrite(p, p->length, RX_ZEROS, rx_zeros);
+	    p->length += RX_ZEROS;
+	    padbytes -= RX_ZEROS;
+	} else {
+	    rx_packetwrite(p, p->length, padbytes, rx_zeros);
+	    p->length += padbytes;
+	    padbytes = 0;
 	}
     }
+
     if (call->conn->type == RX_CLIENT_CONNECTION)
 	p->header.flags |= RX_CLIENT_INITIATED;
 
--- openafs-1.6.1.orig/src/rxkad/Makefile.in
+++ openafs-1.6.1/src/rxkad/Makefile.in
@@ -21,7 +21,7 @@ INCLS=${TOP_INCDIR}/rx/rx.h ${TOP_INCDIR
 
 OBJS=rxkad_client.o rxkad_server.o rxkad_common.o rxkad_errs.o \
 	fcrypt.o crypt_conn.o ticket.o ticket5.o crc.o \
-	md4.o md5.o
+	md4.o md5.o @MAKE_KRB5@ ticket5_keytab.o
 
 fc_test_OBJS=fc_test.o
 
@@ -92,6 +92,9 @@ fcrypt.o: fcrypt.c fcrypt.h sboxes.h rxk
 
 crypt_conn.o: crypt_conn.c fcrypt.h private_data.h ${INCLS}
 
+ticket5_keytab.o: ticket5_keytab.c ${INCLS}
+	${CC} ${CFLAGS} -c ${srcdir}/ticket5_keytab.c @KRB5_CPPFLAGS@
+
 tcrypt.o: tcrypt.c AFS_component_version_number.o
 
 tcrypt: tcrypt.o librxkad.a 
--- openafs-1.6.1.orig/src/rxkad/private_data.h
+++ openafs-1.6.1/src/rxkad/private_data.h
@@ -82,6 +82,7 @@ struct rxkad_sprivate {
 		    char *, afs_int32);
 				/* func called with new client name */
     afs_uint32 flags;		/* configuration flags */
+    rxkad_alt_decrypt_func alt_decrypt;
 };
 
 /* private data in server-side connection */
--- openafs-1.6.1.orig/src/rxkad/rxkad.p.h
+++ openafs-1.6.1/src/rxkad/rxkad.p.h
@@ -93,6 +93,11 @@ typedef signed char rxkad_level;
 
 extern int rxkad_EpochWasSet;	/* TRUE => we called rx_SetEpoch */
 
+/* An alternate decryption function for rxkad.  Using the given kvno and
+ * enctype, decrypt the input data + length to output data + length. */
+typedef int (*rxkad_alt_decrypt_func)(int, int, void *, size_t, void *,
+				      size_t *);
+
 #include <rx/rxkad_prototypes.h>
 
 #endif /* OPENAFS_RXKAD_RXKAD_H */
--- openafs-1.6.1.orig/src/rxkad/rxkad_prototypes.h
+++ openafs-1.6.1/src/rxkad/rxkad_prototypes.h
@@ -130,6 +130,8 @@ extern afs_int32 rxkad_SetConfiguration(
                                         struct rx_connection *aconn,
                                         rx_securityConfigVariables atype,
                                         void * avalue, void **aresult);
+extern int rxkad_SetAltDecryptProc(struct rx_securityClass *aobj,
+				   rxkad_alt_decrypt_func alt_decrypt);
 
 /* ticket.c */
 extern int tkt_DecodeTicket(char *asecret, afs_int32 ticketLen,
@@ -159,7 +161,17 @@ extern int tkt_DecodeTicket5(char *ticke
 			     char *get_key_rock, int serv_kvno, char *name,
 			     char *inst, char *cell, struct ktc_encryptionKey *session_key,
 			     afs_int32 * host, afs_uint32 * start,
-			     afs_uint32 * end, afs_int32 disableDotCheck);
+			     afs_uint32 * end, afs_int32 disableDotCheck,
+			     rxkad_alt_decrypt_func alt_decrypt);
+/*
+ * Compute a des key from a key of a semi-arbitrary kerberos 5 enctype.
+ * Modifies keydata if enctype is 3des.
+ */
+extern int tkt_DeriveDesKey(int enctype, void *keydata, size_t keylen, struct ktc_encryptionKey
+			    *output);
+/* ticket5_keytab.c */
+extern int rxkad_InitKeytabDecrypt(const char *, const char *);
+extern int rxkad_BindKeytabDecrypt(struct rx_securityClass *);
 
 #if !defined(NO_DES_H_INCLUDE)
 static_inline unsigned char *
--- openafs-1.6.1.orig/src/rxkad/rxkad_server.c
+++ openafs-1.6.1/src/rxkad/rxkad_server.c
@@ -336,7 +336,8 @@ rxkad_CheckResponse(struct rx_securityCl
 	    tkt_DecodeTicket5(tix, tlen, tsp->get_key, tsp->get_key_rock,
 			      kvno, client.name, client.instance, client.cell,
 			      &sessionkey, &host, &start, &end,
-			      tsp->flags & RXS_CONFIG_FLAGS_DISABLE_DOTCHECK);
+			      tsp->flags & RXS_CONFIG_FLAGS_DISABLE_DOTCHECK,
+			      tsp->alt_decrypt);
 	if (code)
 	    return code;
     }
@@ -484,3 +485,13 @@ afs_int32 rxkad_SetConfiguration(struct
     }
     return 0;
 }
+
+int rxkad_SetAltDecryptProc(struct rx_securityClass *aobj,
+			    rxkad_alt_decrypt_func alt_decrypt)
+{
+    struct rxkad_sprivate *private =
+    (struct rxkad_sprivate *)aobj->privateData;
+
+    private->alt_decrypt = alt_decrypt;
+    return 0;
+}
--- openafs-1.6.1.orig/src/rxkad/ticket5.c
+++ openafs-1.6.1/src/rxkad/ticket5.c
@@ -71,6 +71,8 @@
 #include <string.h>
 #include <rx/xdr.h>
 #include <rx/rx.h>
+#include <des.h>
+#include <des_prototypes.h>
 #include "lifetimes.h"
 #include "rxkad.h"
 
@@ -176,8 +178,11 @@ static const struct krb_convert sconv_li
 static int
   krb5_des_decrypt(struct ktc_encryptionKey *, int, void *, size_t, void *,
 		   size_t *);
-
-
+static int rxkad_derive_des_key(const void *, size_t,
+				struct ktc_encryptionKey *);
+static int compress_parity_bits(void *, size_t *);
+static void hmac_md5_iov(const void *, size_t, const struct iovec *,
+			 unsigned int, void *);
 
 
 int
@@ -185,7 +190,8 @@ tkt_DecodeTicket5(char *ticket, afs_int3
 		  int (*get_key) (void *, int, struct ktc_encryptionKey *),
 		  char *get_key_rock, int serv_kvno, char *name, char *inst,
 		  char *cell, struct ktc_encryptionKey *session_key, afs_int32 * host,
-		  afs_uint32 * start, afs_uint32 * end, afs_int32 disableCheckdot)
+		  afs_uint32 * start, afs_uint32 * end, afs_int32 disableCheckdot,
+		  rxkad_alt_decrypt_func alt_decrypt)
 {
     char plain[MAXKRB5TICKETLEN];
     struct ktc_encryptionKey serv_key;
@@ -226,33 +232,41 @@ tkt_DecodeTicket5(char *ticket, afs_int3
 	v5_serv_kvno = *t5.enc_part.kvno;
     }
 
-    /* Check that the key type really fit into 8 bytes */
+    /* check ticket */
+    if (t5.enc_part.cipher.length > sizeof(plain))
+	goto bad_ticket;
     switch (t5.enc_part.etype) {
     case ETYPE_DES_CBC_CRC:
     case ETYPE_DES_CBC_MD4:
     case ETYPE_DES_CBC_MD5:
+	/* Check that the key type really fit into 8 bytes */
+	if (t5.enc_part.cipher.length % 8 != 0)
+	    goto bad_ticket;
+
+	code = (*get_key) (get_key_rock, v5_serv_kvno, &serv_key);
+	if (code)
+	    goto unknown_key;
+
+	/* Decrypt data here, save in plain, assume it will shrink */
+	code =
+	    krb5_des_decrypt(&serv_key, t5.enc_part.etype,
+			     t5.enc_part.cipher.data,
+			     t5.enc_part.cipher.length, plain, &plainsiz);
+	if (code != 0)
+	    goto bad_ticket;
 	break;
     default:
-	goto unknown_key;
+	if (alt_decrypt != NULL) {
+	    plainsiz = sizeof(plain);
+	    code = alt_decrypt(v5_serv_kvno, t5.enc_part.etype,
+			       t5.enc_part.cipher.data,
+			       t5.enc_part.cipher.length, plain, &plainsiz);
+	    if (code != 0)
+		goto cleanup;
+	} else
+	    goto unknown_key;
     }
 
-    /* check ticket */
-    if (t5.enc_part.cipher.length > sizeof(plain)
-	|| t5.enc_part.cipher.length % 8 != 0)
-	goto bad_ticket;
-
-    code = (*get_key) (get_key_rock, v5_serv_kvno, &serv_key);
-    if (code)
-	goto unknown_key;
-
-    /* Decrypt data here, save in plain, assume it will shrink */
-    code =
-	krb5_des_decrypt(&serv_key, t5.enc_part.etype,
-			 t5.enc_part.cipher.data, t5.enc_part.cipher.length,
-			 plain, &plainsiz);
-    if (code != 0)
-	goto bad_ticket;
-
     /* Decode ticket */
     code = decode_EncTicketPart((unsigned char *)plain, plainsiz, &decr_part, &siz);
     if (code != 0)
@@ -313,21 +327,9 @@ tkt_DecodeTicket5(char *ticket, afs_int3
     }
 
     /* Verify that decr_part.key is of right type */
-    switch (decr_part.key.keytype) {
-    case ETYPE_DES_CBC_CRC:
-    case ETYPE_DES_CBC_MD4:
-    case ETYPE_DES_CBC_MD5:
-	break;
-    default:
+    if (tkt_DeriveDesKey(decr_part.key.keytype, decr_part.key.keyvalue.data,
+			 decr_part.key.keyvalue.length, session_key) != 0)
 	goto bad_ticket;
-    }
-
-    if (decr_part.key.keyvalue.length != 8)
-	goto bad_ticket;
-
-    /* Extract session key */
-    memcpy(session_key, decr_part.key.keyvalue.data, 8);
-
     /* Check lifetimes and host addresses, flags etc */
     {
 	time_t now = time(0);	/* Use fast time package instead??? */
@@ -475,3 +477,176 @@ krb5_des_decrypt(struct ktc_encryptionKe
 
     return ret;
 }
+
+/*
+ * Use NIST SP800-108 with HMAC(MD5) in counter mode as the PRF to derive a
+ * des key from another type of key.
+ *
+ * L is 64, as we take 64 random bits and turn them into a 56-bit des key.
+ * The output of hmac_md5 is 128 bits; we take the first 64 only, so n
+ * properly should be 1.  However, we apply a slight variation due to the
+ * possibility of producing a weak des key.  If the output key is weak, do NOT
+ * simply correct it, instead, the counter is advanced and the next output
+ * used.  As such, we code so as to have n be the full 255 permitted by our
+ * encoding of the counter i in an 8-bit field.  L itself is encoded as a
+ * 32-bit field, big-endian.  We use the constant string "rxkad" as a label
+ * for this key derivation, the standard NUL byte separator, and omit a
+ * key-derivation context.  The input key is unique to the krb5 service ticket,
+ * which is unlikely to be used in an other location.  If it is used in such
+ * a fashion, both locations will derive the same des key from the PRF, but
+ * this is no different from if a krb5 des key had been used in the same way,
+ * as traditional krb5 rxkad uses the ticket session key directly as the token
+ * key.
+ */
+static int
+rxkad_derive_des_key(const void *in, size_t insize,
+		     struct ktc_encryptionKey *out)
+{
+    unsigned char i;
+    char Lbuf[4];		/* bits of output, as 32 bit word, MSB first */
+    char tmp[16];
+    struct iovec iov[3];
+    des_cblock ktmp;
+
+    Lbuf[0] = 0;
+    Lbuf[1] = 0;
+    Lbuf[2] = 0;
+    Lbuf[3] = 64;
+
+    iov[0].iov_base = &i;
+    iov[0].iov_len = 1;
+    iov[1].iov_base = "rxkad";
+    iov[1].iov_len = strlen("rxkad") + 1;   /* includes label and separator */
+    iov[2].iov_base = Lbuf;
+    iov[2].iov_len = 4;
+
+    /* stop when 8 bit counter wraps to 0 */
+    for (i = 1; i ; i++) {
+	hmac_md5_iov(in, insize, iov, 3, tmp);
+	memcpy(ktmp, tmp, 8);
+	des_fixup_key_parity(ktmp);
+	if (!des_is_weak_key(ktmp)) {
+	    memcpy(out->data, ktmp, 8);
+	    return 0;
+	}
+    }
+    return -1;
+}
+
+/*
+ * This is the inverse of the random-to-key for 3des specified in
+ * rfc3961, converting blocks of 8 bytes to blocks of 7 bytes by distributing
+ * the bits of each 8th byte as the lsb of the previous 7 bytes.
+ */
+static int
+compress_parity_bits(void *buffer, size_t *bufsiz)
+{
+    unsigned char *cb, tmp;
+    int i, j, nk;
+
+    if (*bufsiz % 8 != 0)
+	return 1;
+    cb = (unsigned char *)buffer;
+    nk = *bufsiz / 8;
+    for (i = 0; i < nk; i++) {
+	tmp = cb[8 * i + 7] >> 1;
+	for (j = 0; j < 7; j++) {
+	    cb[8 * i + j] &= 0xfe;
+	    cb[8 * i + j] |= tmp & 0x1;
+	    tmp >>= 1;
+	}
+    }
+    for (i = 1; i < nk; i++)
+	memmove(cb + 7 * i, cb + 8 * i, 7);
+    *bufsiz = 7 * nk;
+    return 0;
+}
+
+/* HMAC: Keyed-Hashing for Message Authentication, using MD5 as the hash.
+ * See RFC 2104.
+ *
+ * The constants 64 and 16 are the input block size and output length,
+ * respectively, of md5.
+ */
+static void
+hmac_md5_iov(const void *key, size_t ks,
+	     const struct iovec *data, unsigned int niov, void *output)
+{
+    MD5_CTX md5;
+    const unsigned char *kp;
+    unsigned int i;
+    unsigned char tmp[16], tmpk[16], i_pad[64], o_pad[64];
+    if (ks > 64) {
+	MD5_Init(&md5);
+	MD5_Update(&md5, key, ks);
+	MD5_Final(tmpk, &md5);
+	key = tmpk;
+	ks = 16;
+    }
+    kp = key;
+    for (i = 0; i < ks; i++)
+	i_pad[i] = kp[i] ^ 0x36;
+    memset(i_pad + ks, 0x36, 64 - ks);
+    MD5_Init(&md5);
+    MD5_Update(&md5, i_pad, 64);
+    for (i = 0; i < niov; i++)
+	MD5_Update(&md5, data[i].iov_base, data[i].iov_len);
+    MD5_Final(tmp, &md5);
+    for (i = 0; i < ks; i++)
+	o_pad[i] = kp[i] ^ 0x5c;
+    memset(o_pad + ks, 0x5c, 64 - ks);
+    MD5_Init(&md5);
+    MD5_Update(&md5, o_pad, 64);
+    MD5_Update(&md5, tmp, 16);
+    MD5_Final(output, &md5);
+}
+
+/*
+ * Enctype-specific knowledge about how to derive a des key from a given
+ * key.  If given a des key, use it directly; otherwise, perform any
+ * parity fixup that may be needed and pass through to the hmad-md5 bits.
+ */
+int
+tkt_DeriveDesKey(int enctype, void *keydata, size_t keylen,
+		 struct ktc_encryptionKey *output)
+{
+    switch (enctype) {
+    case ETYPE_DES_CBC_CRC:
+    case ETYPE_DES_CBC_MD4:
+    case ETYPE_DES_CBC_MD5:
+	if (keylen != 8)
+	    return 1;
+
+	/* Extract session key */
+	memcpy(output, keydata, 8);
+	break;
+    case ETYPE_NULL:
+    case 4:
+    case 6:
+    case 8:
+    case 9:
+    case 10:
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+    case 15:
+	return 1;
+	/*In order to become a "Cryptographic Key" as specified in
+	 * SP800-108, it must be indistinguishable from a random bitstring. */
+    case ETYPE_DES3_CBC_MD5:
+    case ETYPE_OLD_DES3_CBC_SHA1:
+    case ETYPE_DES3_CBC_SHA1:
+	if (compress_parity_bits(keydata, &keylen))
+	    return 1;
+	/* FALLTHROUGH */
+    default:
+	if (enctype < 0)
+	    return 1;
+	if (keylen < 7)
+	    return 1;
+	if (rxkad_derive_des_key(keydata, keylen, output) != 0)
+	    return 1;
+    }
+    return 0;
+}
--- /dev/null
+++ openafs-1.6.1/src/rxkad/ticket5_keytab.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2013 Chaskiel Grundman <cg2v@andrew.cmu.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+#include <afs/stds.h>
+#include <rx/rx.h>
+#include <rx/rxkad.h>
+
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <krb5.h>
+
+#ifdef  RX_ENABLE_LOCKS
+static afs_kmutex_t krb5_lock;
+#endif
+
+/* these globals are expected to be set only once, so locking is not needed */
+static char *checkfile_path;
+static char *keytab_name;
+static int have_keytab_keys;
+
+/*
+ * krb5_lock must be held to use/set these globals, including any
+ * krb5 api use with k5ctx
+ */
+static krb5_context k5ctx;
+static int nkeys;
+static krb5_keytab_entry *ktent;
+static time_t last_reload;
+
+#ifdef HAVE_KRB5_KEYBLOCK_ENCTYPE
+# define kb_enctype(keyblock)     ((keyblock)->enctype)
+#elif defined(HAVE_KRB5_KEYBLOCK_KEYTYPE)
+# define kb_enctype(keyblock)     ((keyblock)->keytype)
+#else
+# error Cannot figure out how keyblocks work
+#endif
+#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK
+# define kte_keyblock(kte) (&(kte).keyblock)
+#elif defined(HAVE_KRB5_KEYTAB_ENTRY_KEY)
+# define kte_keyblock(kte) (&(kte).key)
+#else
+# error  Cannot figure out how keytab entries work
+#endif
+#if HAVE_DECL_KRB5_FREE_KEYTAB_ENTRY_CONTENTS
+/* nothing */
+#elif HAVE_DECL_KRB5_KT_FREE_ENTRY
+# define krb5_free_keytab_entry_contents krb5_kt_free_entry
+#else
+static_inline int
+krb5_free_keytab_entry_contents(krb5_context ctx, krb5_keytab_entry *ent)
+{
+    krb5_free_principal(ctx, ent->principal);
+    krb5_free_keyblock_contents(ctx, kte_keyblock(ent));
+    return 0;
+}
+#endif
+#ifndef KRB5_KEYUSAGE_KDC_REP_TICKET
+# ifdef HAVE_DECL_KRB5_KU_TICKET
+#  define KRB5_KEYUSAGE_KDC_REP_TICKET KRB5_KU_TICKET
+# else
+#  define KRB5_KEYUSAGE_KDC_REP_TICKET 2
+# endif
+#endif
+
+static krb5_error_code
+reload_keys(void)
+{
+    krb5_error_code ret;
+    krb5_keytab fkeytab = NULL;
+    krb5_kt_cursor c;
+    krb5_keytab_entry kte;
+    int i, n_nkeys, o_nkeys;
+    krb5_keytab_entry *n_ktent = NULL, *o_ktent;
+    struct stat tstat;
+
+    if (stat(checkfile_path, &tstat) == 0) {
+	if (have_keytab_keys && tstat.st_mtime == last_reload) {
+	    /* We haven't changed since the last time we loaded our keys, so
+	     * there's nothing to do. */
+	    ret = 0;
+	    goto cleanup;
+	}
+	last_reload = tstat.st_mtime;
+    } else if (have_keytab_keys) {
+	/* stat() failed, but we already have keys, so don't do anything. */
+	ret = 0;
+	goto cleanup;
+    }
+
+    if (keytab_name != NULL)
+	ret = krb5_kt_resolve(k5ctx, keytab_name, &fkeytab);
+    else
+	ret = krb5_kt_default(k5ctx, &fkeytab);
+    if (ret != 0)
+	goto cleanup;
+    ret = krb5_kt_start_seq_get(k5ctx, fkeytab, &c);
+    if (ret != 0)
+	goto cleanup;
+    n_nkeys = 0;
+    while (krb5_kt_next_entry(k5ctx, fkeytab, &kte, &c) == 0) {
+	krb5_free_keytab_entry_contents(k5ctx, &kte);
+	n_nkeys++;
+    }
+    krb5_kt_end_seq_get(k5ctx, fkeytab, &c);
+    if (n_nkeys == 0) {
+	ret = KRB5_KT_NOTFOUND;
+	goto cleanup;
+    }
+    n_ktent = calloc(n_nkeys, sizeof(krb5_keytab_entry));
+    if (n_ktent == NULL) {
+	ret = KRB5_KT_NOTFOUND;
+	goto cleanup;
+    }
+    ret = krb5_kt_start_seq_get(k5ctx, fkeytab, &c);
+    if (ret != 0)
+	goto cleanup;
+    for (i = 0; i < n_nkeys; i++)
+	if (krb5_kt_next_entry(k5ctx, fkeytab, &n_ktent[i], &c) != 0)
+	    break;
+    krb5_kt_end_seq_get(k5ctx, fkeytab, &c);
+    if (i < n_nkeys)
+	goto cleanup;
+    have_keytab_keys = 1;
+    o_ktent = ktent;
+    ktent = n_ktent;
+
+    o_nkeys = nkeys;
+    nkeys = n_nkeys;
+
+    /* for cleanup */
+    n_ktent = o_ktent;
+    n_nkeys = o_nkeys;
+cleanup:
+    if (n_ktent != NULL) {
+	for (i = 0; i < n_nkeys; i++)
+	    krb5_free_keytab_entry_contents(k5ctx, &n_ktent[i]);
+	free(n_ktent);
+    }
+    if (fkeytab != NULL) {
+	krb5_kt_close(k5ctx, fkeytab);
+    }
+    return ret;
+}
+
+#if defined(HAVE_KRB5_DECRYPT_TKT_PART) && !defined(HAVE_KRB5_C_DECRYPT)
+extern krb5_error_code
+encode_krb5_enc_tkt_part(krb5_enc_tkt_part *encpart, krb5_data **a_out);
+/*
+ * AIX krb5 has krb5_decrypt_tkt_part, but no krb5_c_decrypt. So, implement our
+ * own krb5_c_decrypt. Note that this krb5_c_decrypt is only suitable for
+ * decrypting an encrypted krb5_enc_tkt_part. But since that's all we ever use
+ * it for, that should be fine.
+ */
+static krb5_error_code
+krb5_c_decrypt(krb5_context context, const krb5_keyblock *key,
+               krb5_keyusage usage, const krb5_data *cipher_state,
+               const krb5_enc_data *input, krb5_data *output)
+{
+    krb5_ticket tkt;
+    krb5_error_code code;
+    krb5_data *tout = NULL;
+
+    /* We only handle a subset of possible arguments; if we somehow get passed
+     * something else, bail out with EINVAL. */
+    if (cipher_state != NULL)
+	return EINVAL;
+    if (usage != KRB5_KEYUSAGE_KDC_REP_TICKET)
+	return EINVAL;
+
+    memset(&tkt, 0, sizeof(tkt));
+
+    tkt.enc_part = *input;
+
+    code = krb5_decrypt_tkt_part(context, key, &tkt);
+    if (code != 0)
+	return code;
+
+    code = encode_krb5_enc_tkt_part(tkt.enc_part2, &tout);
+    if (code != 0)
+	return code;
+
+    if (tout->length > output->length) {
+	/* This should never happen, but don't assert since we may be dealing
+	 * with untrusted user data. */
+	code = EINVAL;
+	goto error;
+    }
+
+    memcpy(output->data, tout->data, tout->length);
+    output->length = tout->length;
+
+ error:
+    if (tout)
+	krb5_free_data(context, tout);
+    return code;
+}
+#endif /* HAVE_KRB5_DECRYPT_TKT_PART && !HAVE_KRB5_C_DECRYPT */
+
+static int
+rxkad_keytab_decrypt(int kvno, int et, void *in, size_t inlen,
+		     void *out, size_t *outlen)
+{
+    krb5_error_code code;
+    /* use heimdal api if available, since heimdal's interface to
+       krb5_c_decrypt is non-standard and annoying to use */
+#ifdef HAVE_KRB5_CRYPTO_INIT
+    krb5_crypto kcrypto;
+#else
+    krb5_enc_data ind;
+#endif
+    krb5_data outd;
+    int i, foundkey;
+    MUTEX_ENTER(&krb5_lock);
+    reload_keys();
+    if (have_keytab_keys == 0) {
+	MUTEX_EXIT(&krb5_lock);
+	return RXKADUNKNOWNKEY;
+    }
+    foundkey = 0;
+    code = -1;
+    for (i = 0; i < nkeys; i++) {
+	/* foundkey determines what error code we return for failure */
+	if (ktent[i].vno == kvno)
+	    foundkey = 1;
+	/* but check against all keys if the enctype matches, for robustness */
+	if (kb_enctype(kte_keyblock(ktent[i])) == et) {
+#ifdef HAVE_KRB5_CRYPTO_INIT
+	    code = krb5_crypto_init(k5ctx, kte_keyblock(ktent[i]), et,
+				    &kcrypto);
+	    if (code == 0) {
+		code = krb5_decrypt(k5ctx, kcrypto,
+				    KRB5_KEYUSAGE_KDC_REP_TICKET, in, inlen,
+				    &outd);
+		krb5_crypto_destroy(k5ctx, kcrypto);
+	    }
+	    if (code == 0) {
+		if (outd.length > *outlen) {
+		    /* This should never happen, but don't assert since we may
+		     * be dealing with untrusted user data. */
+		    code = EINVAL;
+		    krb5_data_free(&outd);
+		    outd.data = NULL;
+		}
+	    }
+	    if (code == 0) {
+		/* heimdal allocates new memory for the decrypted data; put
+		 * the data back into the requested 'out' buffer */
+		*outlen = outd.length;
+		memcpy(out, outd.data, outd.length);
+		krb5_data_free(&outd);
+		break;
+	    }
+#else
+	    outd.length = *outlen;
+	    outd.data = out;
+	    ind.ciphertext.length = inlen;
+	    ind.ciphertext.data = in;
+	    ind.enctype = et;
+	    ind.kvno = kvno;
+	    code = krb5_c_decrypt(k5ctx, kte_keyblock(ktent[i]),
+				  KRB5_KEYUSAGE_KDC_REP_TICKET, NULL, &ind,
+				  &outd);
+	    if (code == 0) {
+		*outlen = outd.length;
+		break;
+	    }
+#endif
+	}
+    }
+    MUTEX_EXIT(&krb5_lock);
+    if (code == 0)
+	return 0;
+    if (foundkey != 0)
+	return RXKADBADTICKET;
+    return RXKADUNKNOWNKEY;
+}
+
+#ifdef RX_ENABLE_LOCKS
+static void
+init_krb5_lock(void)
+{
+    MUTEX_INIT(&krb5_lock, "krb5 api", MUTEX_DEFAULT, 0);
+}
+
+static pthread_once_t rxkad_keytab_once_init = PTHREAD_ONCE_INIT;
+#define INIT_PTHREAD_LOCKS osi_Assert(pthread_once(&rxkad_keytab_once_init, init_krb5_lock)==0)
+#else
+#define INIT_PTHREAD_LOCKS
+#endif
+int
+rxkad_InitKeytabDecrypt(const char *csdb, const char *ktname)
+{
+    int code;
+    static int keytab_init;
+    INIT_PTHREAD_LOCKS;
+    MUTEX_ENTER(&krb5_lock);
+    if (keytab_init) {
+	MUTEX_EXIT(&krb5_lock);
+	return 0;
+    }
+    checkfile_path = strdup(csdb);
+    if (checkfile_path == NULL) {
+	code = ENOMEM;
+	goto cleanup;
+    }
+    k5ctx = NULL;
+    keytab_name = NULL;
+    code = krb5_init_context(&k5ctx);
+    if (code != 0)
+	goto cleanup;
+    if (ktname != NULL) {
+	keytab_name = strdup(ktname);
+	if (keytab_name == NULL) {
+	    code = KRB5_KT_BADNAME;
+	    goto cleanup;
+	}
+    }
+    keytab_init=1;
+    reload_keys();
+    MUTEX_EXIT(&krb5_lock);
+    return 0;
+cleanup:
+    if (checkfile_path != NULL) {
+	free(checkfile_path);
+    }
+    if (keytab_name != NULL) {
+	free(keytab_name);
+    }
+    if (k5ctx != NULL) {
+	krb5_free_context(k5ctx);
+    }
+    MUTEX_EXIT(&krb5_lock);
+    return code;
+}
+
+int
+rxkad_BindKeytabDecrypt(struct rx_securityClass *aclass)
+{
+    return rxkad_SetAltDecryptProc(aclass, rxkad_keytab_decrypt);
+}
--- openafs-1.6.1.orig/src/scout/Makefile.in
+++ openafs-1.6.1/src/scout/Makefile.in
@@ -53,7 +53,7 @@ all: scout
 scout.o: scout.c ${INCLS} AFS_component_version_number.c
 
 scout: scout.o $(LIBS)
-	${CC} ${LDFLAGS} -o scout scout.o $(LIBS) ${LIB_curses} ${XLIBS}
+	${CC} ${LDFLAGS} -o scout scout.o $(LIBS) ${LIB_curses} ${XLIBS} ${KRB5_LIBS}
 
 #
 # Installation targets
--- openafs-1.6.1.orig/src/shlibafsauthent/Makefile.in
+++ openafs-1.6.1/src/shlibafsauthent/Makefile.in
@@ -41,7 +41,7 @@ AUTHOBJS = \
 	writeconfig.o \
 	authcon.o \
 	ktc_errors.o \
-	acfg_errors.o
+	acfg_errors.o @MAKE_KRB5@ akimpersonate.o akimpersonate_v5gen.o
 
 KAUTHOBJS = \
 	kauth.xdr.o \
@@ -74,7 +74,7 @@ UTILOBJS = \
 	fileutil.o
 
 RXKADOBJS = \
-	rxkad_errs.o
+	rxkad_errs.o @MAKE_KRB5@ ticket5_keytab.o
 
 SYSOBJS = \
 	rmtsysc.o \
@@ -133,7 +133,7 @@ dest: ${LIBAFSAUTHENT} libafsauthent_pic
 ${LIBAFSAUTHENT}: ${LIBOBJS} libafsauthent.map
 	../config/shlib-build -d $(srcdir) -l libafsauthent \
 		-M ${LIBAFSAUTHENTMAJOR} -m ${LIBAFSAUTHENTMINOR} -- \
-		-L${TOP_LIBDIR} -lafsrpc ${LIB_crypt} ${LIBOBJS} ${LIB_AFSDB} ${MT_LIBS}
+		-L${TOP_LIBDIR} -lafsrpc ${LIB_crypt} ${LIBOBJS} ${LIB_AFSDB} ${MT_LIBS} ${KRB5_LIBS}
 
 libafsauthent_pic.a: ${LIBOBJS}
 	$(RM) -f $@
@@ -162,7 +162,13 @@ writeconfig.o: ${AUTH}/writeconfig.c
 	${CCRULE}
 
 authcon.o: ${AUTH}/authcon.c
-	${CCRULE}
+	${CCRULE} @KRB5_CPPFLAGS@
+
+akimpersonate.o: ${AUTH}/akimpersonate.c
+	${CCRULE} @KRB5_CPPFLAGS@
+
+akimpersonate_v5gen.o: ${AUTH}/akimpersonate_v5gen.c
+	${CCRULE} @KRB5_CPPFLAGS@ -I../rxkad
 
 ktc_errors.o: ${AUTH}/ktc_errors.c
 	${CCRULE}
@@ -245,6 +251,9 @@ pthread_glock.o: ${UTIL}/pthread_glock.c
 rxkad_errs.o: ${RXKAD}/rxkad_errs.c
 	${CCRULE}
 
+ticket5_keytab.o: ${RXKAD}/ticket5_keytab.c
+	${CCRULE} @KRB5_CPPFLAGS@
+
 ptclient.o: ${PTSERVER}/ptclient.c
 	${CCRULE}
 
--- openafs-1.6.1.orig/src/shlibafsrpc/libafsrpc.map
+++ openafs-1.6.1/src/shlibafsrpc/libafsrpc.map
@@ -48,12 +48,14 @@
 	rxkad_GetServerInfo;
 	rxkad_NewClientSecurityObject;
 	rxkad_NewServerSecurityObject;
+	rxkad_SetAltDecryptProc;
 	rxnull_NewClientSecurityObject;
 	rxnull_NewServerSecurityObject;
 	rxs_Release;
 	time_to_life;
 	tkt_CheckTimes;
 	tkt_DecodeTicket;
+	tkt_DeriveDesKey;
 	tkt_MakeTicket;
 	xdrrx_create;
 	hton_syserr_conv;
@@ -146,6 +148,10 @@
 	rx_SetBusyChannelError;
 	rx_KeepAliveOn;
 	rx_KeepAliveOff;
+	_rxkad_v5_encode_EncTicketPart;
+	_rxkad_v5_encode_Ticket;
+	_rxkad_v5_length_EncTicketPart;
+	_rxkad_v5_length_Ticket;
     local:
 	*;
 };
--- openafs-1.6.1.orig/src/tbudb/Makefile.in
+++ openafs-1.6.1/src/tbudb/Makefile.in
@@ -155,7 +155,7 @@ server.o: ${BUDB}/server.c budb_errs.h $
 
 
 budb_server: $(SERVER_OBJS) ${LIBS}
-	${CC} ${LDFLAGS} -o budb_server $(SERVER_OBJS) ${LIBS} ${MT_LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o budb_server $(SERVER_OBJS) ${LIBS} ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 budb.cs.c: ${BUDB}/budb.rg
 	${RXGEN} -u -C -o $@ ${srcdir}/${BUDB}/budb.rg
--- openafs-1.6.1.orig/src/tbutc/Makefile.in
+++ openafs-1.6.1/src/tbutc/Makefile.in
@@ -70,7 +70,7 @@ BUTCLIBS=${TOP_LIBDIR}/libbudb.a \
 all: butc
 
 butc: ${BUTCOBJS} ${BUTCLIBS}
-	${CC} ${CFLAGS} ${BUTCOBJS} ${BUTCLIBS} ${MT_LIBS} ${XLIBS} -o butc
+	${CC} ${CFLAGS} ${BUTCOBJS} ${BUTCLIBS} ${MT_LIBS} ${XLIBS} ${KRB5_LIBS} -o butc
 
 libbutm.a: ${BUTMOBJS} AFS_component_version_number.o
 	-$(RM) -f libbutm.a
--- openafs-1.6.1.orig/src/tptserver/Makefile.in
+++ openafs-1.6.1/src/tptserver/Makefile.in
@@ -155,7 +155,7 @@ display.o: ${PTSERVER}/display.c ${INCLS
 	${CCRULE} ${srcdir}/${PTSERVER}/display.c
 
 ptserver: ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o $(LIBS) ${TOP_LIBDIR}/libaudit.a map.o
-	${CC} ${LDFLAGS} -o ptserver ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o map.o $(LIBS) ${MT_LIBS} ${XLIBS} ${TOP_LIBDIR}/libaudit.a
+	${CC} ${LDFLAGS} -o ptserver ptserver.o ptutils.o ptprocs.o ptint.ss.o ptint.xdr.o utils.o map.o $(LIBS) ${MT_LIBS} ${XLIBS} ${TOP_LIBDIR}/libaudit.a ${KRB5_LIBS}
 
 db_verify.o: ${PTSERVER}/db_verify.c ${INCLS}
 	${CCRULE} ${srcdir}/${PTSERVER}/db_verify.c
@@ -164,7 +164,7 @@ db_verify: db_verify.o pterror.o display
 	$(CC) ${LDFLAGS} -o db_verify db_verify.o display.o pterror.o $(LIBS) ${MT_LIBS} ${XLIBS}
 
 ptclient: ptclient.o display.o ptuser.o pterror.o ptint.cs.o ptint.xdr.o AFS_component_version_number.o $(LIBS)
-	$(CC) ${LDFLAGS} -o ptclient ptclient.o display.o $(PTOBJS) $(LIBS) ${MT_LIBS} ${XLIBS}
+	$(CC) ${LDFLAGS} -o ptclient ptclient.o display.o $(PTOBJS) $(LIBS) ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 ptclient.o: ${PTSERVER}/ptclient.c ${INCLS}
 	${CCRULE} ${srcdir}/${PTSERVER}/ptclient.c
@@ -177,31 +177,31 @@ pterror.h pterror.c: ${PTSERVER}/pterror
 	${COMPILE_ET} -p ${srcdir}/${PTSERVER} pterror
 
 pts: pts.o $(PTOBJS) ${TOP_LIBDIR}/libcmd.a $(LIBS) ${INCLS}
-	$(CC) ${LDFLAGS} -o pts pts.o ${TOP_LIBDIR}/libcmd.a $(PTOBJS) ${LIBS} ${MT_LIBS} ${XLIBS}
+	$(CC) ${LDFLAGS} -o pts pts.o ${TOP_LIBDIR}/libcmd.a $(PTOBJS) ${LIBS} ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 pts.o: ${PTSERVER}/pts.c
 	${CCRULE} ${srcdir}/${PTSERVER}/pts.c
 
 readgroup: readgroup.o $(PTOBJS) $(LIBS)
-	$(CC) ${CFLAGS} -o readgroup readgroup.o $(PTOBJS) ${LIBS} ${MT_LIBS} ${XLIBS}
+	$(CC) ${CFLAGS} -o readgroup readgroup.o $(PTOBJS) ${LIBS} ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 readgroup.o: ${PTSERVER}/readgroup.c ${INCLS}
 	${CCRULE} ${srcdir}/${PTSERVER}/readgroup.c
 
 readpwd: readpwd.o $(PTOBJS) $(LIBS)
-	$(CC) ${CFLAGS} -o readpwd readpwd.o $(PTOBJS) ${LIBS} ${MT_LIBS} ${XLIBS}
+	$(CC) ${CFLAGS} -o readpwd readpwd.o $(PTOBJS) ${LIBS} ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 readpwd.o: ${PTSERVER}/readpwd.c ${INCLS}
 	${CCRULE} ${srcdir}/${PTSERVER}/readpwd.c
 
 testpt: testpt.o $(PTOBJS) ${TOP_LIBDIR}/libcmd.a $(LIBS)
-	$(CC) ${CFLAGS} -o testpt testpt.o -lm ${TOP_LIBDIR}/libcmd.a $(PTOBJS) $(LIBS) ${MT_LIBS} ${XLIBS}
+	$(CC) ${CFLAGS} -o testpt testpt.o -lm ${TOP_LIBDIR}/libcmd.a $(PTOBJS) $(LIBS) ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 testpt.o: ${PTSERVER}/testpt.c ${INCLS}
 	${CCRULE} ${srcdir}/${PTSERVER}/testpt.c
 
 pt_util: pt_util.o ptutils.o ubik.o utils.o map.o $(PTOBJS) $(LIBS)
-	$(CC) ${CFLAGS} -o pt_util pt_util.o ptutils.o ubik.o utils.o map.o $(PTOBJS) ${TOP_LIBDIR}/libcmd.a $(LIBS) ${MT_LIBS} ${XLIBS}
+	$(CC) ${CFLAGS} -o pt_util pt_util.o ptutils.o ubik.o utils.o map.o $(PTOBJS) ${TOP_LIBDIR}/libcmd.a $(LIBS) ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 pt_util.o: ${PTSERVER}/pt_util.c
 	${CCRULE} ${srcdir}/${PTSERVER}/pt_util.c
--- openafs-1.6.1.orig/src/tsm41/Makefile.in
+++ openafs-1.6.1/src/tsm41/Makefile.in
@@ -79,10 +79,10 @@ aklog_dynamic_auth: ${AUTH_KRB5_OBJS} ${
 	$(LD) -o $@ ${AUTH_KRB5_OBJS} $(AFSLIBS) ${AUTHFILES} @KRB5_LIBS@ ${XLIBS} ${AKLDFLAGS}
 
 afs_dynamic_auth: ${AUTH_OBJS} ${AFSLIBS} ${AUTHFILES}
-	$(LD) -o $@ ${AUTH_OBJS} $(AFSLIBS) ${AUTHFILES} ${XLIBS} ${LDFLAGS}
+	$(LD) -o $@ ${AUTH_OBJS} $(AFSLIBS) ${AUTHFILES} @KRB5_LIBS@ ${XLIBS} ${LDFLAGS}
 
 afs_dynamic_kerbauth: ${AUTH_KRB_OBJS} ${KAFSLIBS} ${AUTHFILES}
-	$(LD) -o $@ ${AUTH_KRB_OBJS} $(KAFSLIBS) ${AUTHFILES} ${XLIBS} ${LDFLAGS}
+	$(LD) -o $@ ${AUTH_KRB_OBJS} $(KAFSLIBS) ${AUTHFILES} @KRB5_LIBS@ ${XLIBS} ${LDFLAGS}
 
 aix_auth_common.o: ${srcdir}/aix_auth_common.c
 	${CCRULE}
--- openafs-1.6.1.orig/src/tviced/Makefile.in
+++ openafs-1.6.1/src/tviced/Makefile.in
@@ -205,7 +205,7 @@ afsint.xdr.o: ${FSINT}/afsint.xdr.c
 	${CCRULE}
 
 fileserver: ${objects} ${LIBS}
-	${CC} ${LDFLAGS} -o fileserver ${objects} ${LIBS} ${MT_LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o fileserver ${objects} ${LIBS} ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 install: fileserver
 	${INSTALL} -d ${DESTDIR}${afssrvlibexecdir}
--- openafs-1.6.1.orig/src/tvlserver/Makefile.in
+++ openafs-1.6.1/src/tvlserver/Makefile.in
@@ -109,26 +109,26 @@ get_krbrlm.o: ${UTIL}/get_krbrlm.c
 
 
 vldb_check: vldb_check.o ${LIBS} AFS_component_version_number.o
-	$(CC) ${LDFLAGS} -o vldb_check vldb_check.o AFS_component_version_number.o ${LIBS} ${MT_LIBS} ${XLIBS} 
+	$(CC) ${LDFLAGS} -o vldb_check vldb_check.o AFS_component_version_number.o ${LIBS} ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 vldb_check.o: ${VLSERVER}/vldb_check.c 
 	${CCRULE} ${srcdir}/${VLSERVER}/vldb_check.c
 
 cnvldb: cnvldb.o ${LIBS} 
-	$(CC) ${LDFLAGS} -o cnvldb cnvldb.o ${LIBS} ${MT_LIBS} ${XLIBS}
+	$(CC) ${LDFLAGS} -o cnvldb cnvldb.o ${LIBS} ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 cnvldb.o: ${VLSERVER}/cnvldb.c
 	${CCRULE} ${srcdir}/${VLSERVER}/cnvldb.c
 
 sascnvldb: sascnvldb.o ${LIBS} 
-	$(CC) ${LDFLAGS} -o sascnvldb sascnvldb.o ${LIBS} ${MT_LIBS} ${XLIBS}
+	$(CC) ${LDFLAGS} -o sascnvldb sascnvldb.o ${LIBS} ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 sascnvldb.o: ${VLSERVER}/sascnvldb.c
 	${CCRULE} ${srcdir}/${VLSERVER}/sascnvldb.c
 
 vlserver: vlserver.o vlutils.o vlprocs.o vldbint.ss.o vldbint.xdr.o $(LIBS)
 	$(CC) ${LDFLAGS} -o vlserver vlserver.o vlutils.o vlprocs.o vldbint.ss.o \
-		vldbint.xdr.o $(LIBS) ${MT_LIBS} ${XLIBS} ${TOP_LIBDIR}/libaudit.a
+		vldbint.xdr.o $(LIBS) ${MT_LIBS} ${XLIBS} ${TOP_LIBDIR}/libaudit.a ${KRB5_LIBS}
 
 vlserver.o: ${VLSERVER}/vlserver.c ${INCLS} AFS_component_version_number.o
 	${CCRULE} ${srcdir}/${VLSERVER}/vlserver.c
@@ -171,7 +171,7 @@ Kvldbint.xdr.c: ${VLSERVER}/vldbint.xg
 	${RXGEN} -A -x -k -c -o $@ ${srcdir}/${VLSERVER}/vldbint.xg
 
 vlclient: vlclient.o $(OBJS) $(LIBS) ${INCLS}
-	$(CC) ${LDFLAGS} -o vlclient vlclient.o $(OBJS) $(LIBS) ${MT_LIBS} ${XLIBS} ${TOP_LIBDIR}/libcmd.a
+	$(CC) ${LDFLAGS} -o vlclient vlclient.o $(OBJS) $(LIBS) ${MT_LIBS} ${XLIBS} ${TOP_LIBDIR}/libcmd.a ${KRB5_LIBS}
 
 vlclient.o: ${VLSERVER}/vlclient.c
 	${CCRULE} ${srcdir}/${VLSERVER}/vlclient.c
--- openafs-1.6.1.orig/src/tvolser/Makefile.in
+++ openafs-1.6.1/src/tvolser/Makefile.in
@@ -231,7 +231,7 @@ vos: vos.o  ${VOSOBJS} ${VLSERVEROBJS} $
 	${CC} ${LDFLAGS} -o vos vos.o ${VOSOBJS} ${VLSERVEROBJS} ${LIBS} ${TOP_LIBDIR}/libubik_pthread.a ${MT_LIBS} ${XLIBS}
 
 volserver: ${objects} ${LIBS}
-	${CC} ${LDFLAGS} -o volserver ${objects} ${LIBS} ${MT_LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o volserver ${objects} ${LIBS} ${MT_LIBS} ${XLIBS} ${KRB5_LIBS}
 
 install: volserver
 	${INSTALL} -d ${DESTDIR}${afssrvlibexecdir}
--- openafs-1.6.1.orig/src/ubik/uinit.c
+++ openafs-1.6.1/src/ubik/uinit.c
@@ -80,6 +80,9 @@ ugen_ClientInit(int noAuthFlag, const ch
 	secFlags |= AFSCONF_SECOPTS_NOAUTH;
     }
 
+    if (gen_rxkad_level == rxkad_crypt)
+	secFlags |= AFSCONF_SECOPTS_ALWAYSENCRYPT;
+
     tdir = afsconf_Open(confdir);
     if (!tdir) {
 	fprintf(stderr,
--- openafs-1.6.1.orig/src/update/Makefile.in
+++ openafs-1.6.1/src/update/Makefile.in
@@ -30,10 +30,10 @@ generated: update.cs.c update.ss.c updat
 # Build targets
 #
 upclient: client.o update.cs.o utils.o ${LIBS} 
-	${CC} ${CFLAGS} -o upclient client.o update.cs.o utils.o ${LIBS} ${XLIBS}
+	${CC} ${CFLAGS} -o upclient client.o update.cs.o utils.o ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 upserver: server.o utils.o update.ss.o ${LIBS}
-	${CC} ${CFLAGS} -o upserver server.o utils.o update.ss.o ${LIBS} ${XLIBS}
+	${CC} ${CFLAGS} -o upserver server.o utils.o update.ss.o ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 utils.o: utils.c update.h global.h
 
--- openafs-1.6.1.orig/src/uss/Makefile.in
+++ openafs-1.6.1/src/uss/Makefile.in
@@ -47,7 +47,7 @@ OBJS =  uss_procs.o \
 	y.tab.o 
 
 uss: uss.o ${OBJS} 
-	${CC} ${CFLAGS} -o uss uss.o ${OBJS} ${LIBS}
+	${CC} ${CFLAGS} -o uss uss.o ${OBJS} ${LIBS} ${KRB5_LIBS}
 
 uss.o:  uss.c AFS_component_version_number.c
 	${CC} -c ${CFLAGS} ${srcdir}/uss.c
--- openafs-1.6.1.orig/src/util/dirpath.c
+++ openafs-1.6.1/src/util/dirpath.c
@@ -389,6 +389,9 @@ initDirPathArray(void)
     pathp = dirPathArray[AFSDIR_SERVER_FSSTATE_FILEPATH_ID];
     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_FSSTATE_FILE);
 
+    pathp = dirPathArray[AFSDIR_SERVER_RXKAD_KEYTAB_FILEPATH_ID];
+    AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_RXKAD_KEYTAB_FILE);
+
     /* client file paths */
 #ifdef AFS_NT40_ENV
     strcpy(dirPathArray[AFSDIR_CLIENT_THISCELL_FILEPATH_ID],
--- openafs-1.6.1.orig/src/util/dirpath.hin
+++ openafs-1.6.1/src/util/dirpath.hin
@@ -149,6 +149,7 @@ ConstructLocalLogPath(const char *cpath,
 #define AFSDIR_VOLSERLOG_FILE   "VolserLog"
 #define AFSDIR_AUDIT_FILE       "Audit"
 #define AFSDIR_KRB_EXCL_FILE    "krb.excl"
+#define AFSDIR_RXKAD_KEYTAB_FILE "rxkad.keytab"
 
 #define AFSDIR_ROOTVOL_FILE     "RootVolume"
 #define AFSDIR_HOSTDUMP_FILE    "hosts.dump"
@@ -282,6 +283,7 @@ typedef enum afsdir_id {
       AFSDIR_SERVER_SALSRV_FILEPATH_ID,
       AFSDIR_SERVER_SALSRVLOG_FILEPATH_ID,
       AFSDIR_SERVER_FSSTATE_FILEPATH_ID,
+      AFSDIR_SERVER_RXKAD_KEYTAB_FILEPATH_ID,
       AFSDIR_PATHSTRING_MAX } afsdir_id_t;
 
 /* getDirPath() returns a pointer to a string from an internal array of path strings 
@@ -355,6 +357,7 @@ const char *getDirPath(afsdir_id_t strin
 #define AFSDIR_SERVER_MIGRATELOG_FILEPATH getDirPath(AFSDIR_SERVER_MIGRATELOG_FILEPATH_ID)
 #define AFSDIR_SERVER_KRB_EXCL_FILEPATH getDirPath(AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID)
 #define AFSDIR_SERVER_FSSTATE_FILEPATH getDirPath(AFSDIR_SERVER_FSSTATE_FILEPATH_ID)
+#define AFSDIR_SERVER_RXKAD_KEYTAB_FILEPATH getDirPath(AFSDIR_SERVER_RXKAD_KEYTAB_FILEPATH_ID)
 
 /* client file paths */
 #define AFSDIR_CLIENT_THISCELL_FILEPATH getDirPath(AFSDIR_CLIENT_THISCELL_FILEPATH_ID)
--- openafs-1.6.1.orig/src/venus/Makefile.in
+++ openafs-1.6.1/src/venus/Makefile.in
@@ -68,7 +68,7 @@ all: fs up fstrace cmdebug livesys kdump
 # Build targets
 #
 cacheout: cacheout.o
-	$(CC) ${CFLAGS} -o cacheout cacheout.o ${LIBS} ${XLIBS} ${CMLIBS}
+	$(CC) ${CFLAGS} -o cacheout cacheout.o ${LIBS} ${XLIBS} ${CMLIBS} ${KRB5_LIBS}
 
 cacheout.o: cacheout.c
 
@@ -84,7 +84,7 @@ up: up.o
 fs.o: fs.c ${INCLS} AFS_component_version_number.c
 
 fs: fs.o $(LIBS)
-	${CC} ${CFLAGS} -o fs fs.o ${TOP_LIBDIR}/libprot.a $(LIBS) ${XLIBS}
+	${CC} ${CFLAGS} -o fs fs.o ${TOP_LIBDIR}/libprot.a $(LIBS) ${XLIBS} ${KRB5_LIBS}
 
 afsio.o: ${srcdir}/afsio.c ${AFSIO_INCLS} AFS_component_version_number.c
 	${PTH_CCRULE} ${srcdir}/afsio.c
@@ -102,10 +102,10 @@ afsio: afsio.o vldbint.cs.o afscbint.ss.
 livesys.o: livesys.c ${INCLS} AFS_component_version_number.c
 
 livesys: livesys.c $(LIBS)
-	${CC} ${CFLAGS} -o livesys ${srcdir}/livesys.c $(LIBS) ${XLIBS}
+	${CC} ${CFLAGS} -o livesys ${srcdir}/livesys.c $(LIBS) ${XLIBS} ${KRB5_LIBS}
 
 twiddle: twiddle.c $(LIBS)
-	${CC} ${CFLAGS} -o twiddle ${srcdir}/twiddle.c $(LIBS) ${XLIBS}
+	${CC} ${CFLAGS} -o twiddle ${srcdir}/twiddle.c $(LIBS) ${XLIBS} ${KRB5_LIBS}
 
 gcpags: gcpags.c $(LIBS)
 	${CC} ${CFLAGS} -o gcpags ${srcdir}/gcpags.c $(LIBS) ${XLIBS}
@@ -113,7 +113,7 @@ gcpags: gcpags.c $(LIBS)
 whatfid.o: whatfid.c ${INCLS} AFS_component_version_number.c
 
 whatfid: whatfid.o ${LIBS}
-	${CC} ${CFLAGS} -o whatfid whatfid.o ${LIBS} ${XLIBS}
+	${CC} ${CFLAGS} -o whatfid whatfid.o ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 fstrace.o: fstrace.c AFS_component_version_number.c
 	case ${SYS_NAME} in \
@@ -140,12 +140,12 @@ fstrace: fstrace.o
 cmdebug.o: cmdebug.c ${INCLS} AFS_component_version_number.c
 
 cmdebug: cmdebug.o ${CMLIBS}
-	$(CC) -o cmdebug cmdebug.o ${CFLAGS} ${CMLIBS} ${XLIBS}
+	$(CC) -o cmdebug cmdebug.o ${CFLAGS} ${CMLIBS} ${XLIBS} ${KRB5_LIBS}
 
 dedebug.o: dedebug.c ${INCLS} AFS_component_version_number.c
 
 dedebug: dedebug.o ${CMLIBS}
-	$(CC) -o dedebug dedebug.o ${CFLAGS} ${CMLIBS} ${XLIBS}
+	$(CC) -o dedebug dedebug.o ${CFLAGS} ${CMLIBS} ${XLIBS} ${KRB5_LIBS}
 
 
 
--- openafs-1.6.1.orig/src/venus/fs.c
+++ openafs-1.6.1/src/venus/fs.c
@@ -561,7 +561,7 @@ EmptyAcl(char *astr)
     tp->nplus = tp->nminus = 0;
     tp->pluslist = tp->minuslist = 0;
     tp->dfs = 0;
-    sscanf(astr, "%d dfs:%d %s", &junk, &tp->dfs, tp->cell);
+    sscanf(astr, "%d dfs:%d %1024s", &junk, &tp->dfs, tp->cell);
     return tp;
 }
 
@@ -576,7 +576,7 @@ ParseAcl(char *astr)
     ta = (struct Acl *)malloc(sizeof(struct Acl));
     assert(ta);
     ta->dfs = 0;
-    sscanf(astr, "%d dfs:%d %s", &ta->nplus, &ta->dfs, ta->cell);
+    sscanf(astr, "%d dfs:%d %1024s", &ta->nplus, &ta->dfs, ta->cell);
     astr = SkipLine(astr);
     sscanf(astr, "%d", &ta->nminus);
     astr = SkipLine(astr);
@@ -587,7 +587,7 @@ ParseAcl(char *astr)
     last = 0;
     first = 0;
     for (i = 0; i < nplus; i++) {
-	sscanf(astr, "%100s %d", tname, &trights);
+	sscanf(astr, "%99s %d", tname, &trights);
 	astr = SkipLine(astr);
 	tl = (struct AclEntry *)malloc(sizeof(struct AclEntry));
 	assert(tl);
@@ -605,7 +605,7 @@ ParseAcl(char *astr)
     last = 0;
     first = 0;
     for (i = 0; i < nminus; i++) {
-	sscanf(astr, "%100s %d", tname, &trights);
+	sscanf(astr, "%99s %d", tname, &trights);
 	astr = SkipLine(astr);
 	tl = (struct AclEntry *)malloc(sizeof(struct AclEntry));
 	assert(tl);
--- openafs-1.6.1.orig/src/viced/Makefile.in
+++ openafs-1.6.1/src/viced/Makefile.in
@@ -79,23 +79,23 @@ fileserver: ${objects} ${headers} ${LIBS
 	case ${SYS_NAME} in \
 	rs_aix*) \
 	    ${CC} -K ${LDFLAGS} -o fileserver ${objects} \
-	    ${TOP_LIBDIR}/libaudit.a ${LIBS} ${XLIBS} ;; \
+	    ${TOP_LIBDIR}/libaudit.a ${LIBS} ${XLIBS} ${KRB5_LIBS} ;; \
 	*) \
 	    ${CC} ${LDFLAGS} -o fileserver ${objects} \
-	    ${TOP_LIBDIR}/libaudit.a ${LIBS} ${XLIBS} ;; \
+	    ${TOP_LIBDIR}/libaudit.a ${LIBS} ${XLIBS} ${KRB5_LIBS} ;; \
 	esac
 
 fsprobe.o: fsprobe.c AFS_component_version_number.c
 	${CC} ${CFLAGS} @CFLAGS_NOERROR@ -DINTERPRET_DUMP -c ${srcdir}/fsprobe.c
 
 fsprobe: fsprobe.o
-	${CC} ${CFLAGS} -o fsprobe fsprobe.o ${LIBS} ${XLIBS} 
+	${CC} ${CFLAGS} -o fsprobe fsprobe.o ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 cbd.o: callback.c AFS_component_version_number.c
 	${CC} ${CFLAGS} -DINTERPRET_DUMP -c -o cbd.o ${srcdir}/callback.c
 
 cbd: cbd.o
-	${CC} ${CFLAGS} -DINTERPRET_DUMP -o cbd cbd.o ${LIBS} ${XLIBS} 
+	${CC} ${CFLAGS} -DINTERPRET_DUMP -o cbd cbd.o ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 install: fileserver fs_stats.h
 	${INSTALL} -d ${DESTDIR}${afssrvlibexecdir}
--- openafs-1.6.1.orig/src/viced/afsfileprocs.c
+++ openafs-1.6.1/src/viced/afsfileprocs.c
@@ -5846,6 +5846,11 @@ SRXAFS_GetStatistics64(struct rx_call *a
     if ((code = CallPreamble(acall, NOTACTIVECALL, &tcon, &thost)))
 	goto Bad_GetStatistics64;
 
+    if (statsVersion != STATS64_VERSION) {
+	code = EINVAL;
+	goto Bad_GetStatistics64;
+    }
+
     ViceLog(1, ("SAFS_GetStatistics64 Received\n"));
     Statistics->ViceStatistics64_val =
 	malloc(statsVersion*sizeof(afs_int64));
--- openafs-1.6.1.orig/src/viced/host.c
+++ openafs-1.6.1/src/viced/host.c
@@ -305,15 +305,12 @@ hpr_Initialize(struct ubik_client **ucli
     /* Most callers use secLevel==1, however, the fileserver uses secLevel==2
      * to force use of the KeyFile.  secLevel == 0 implies -noauth was
      * specified. */
-    if ((afsconf_GetLatestKey(tdir, 0, 0) == 0)) {
-        code = afsconf_ClientAuthSecure(tdir, &sc, &scIndex);
-        if (code)
-	    ViceLog(0, ("hpr_Initialize: clientauthsecure returns %d %s (so trying noauth)", code, afs_error_message(code)));
-        if (code)
-            scIndex = RX_SECIDX_NULL;
-    } else {
-	afsconf_ClientAuthToken(&info, 0, &sc, &scIndex, NULL);
-    }
+    code = afsconf_ClientAuthSecure(tdir, &sc, &scIndex);
+    if (code)
+	ViceLog(0, ("hpr_Initialize: clientauthsecure returns %d %s (so trying noauth)", code, afs_error_message(code)));
+    if (code)
+        scIndex = RX_SECIDX_NULL;
+
     if ((scIndex == RX_SECIDX_NULL) && (sc == NULL))
         sc = rxnull_NewClientSecurityObject();
     if (scIndex == RX_SECIDX_NULL)
--- openafs-1.6.1.orig/src/vlserver/Makefile.in
+++ openafs-1.6.1/src/vlserver/Makefile.in
@@ -71,23 +71,23 @@ ${TOP_INCDIR}/afs/cnvldb.h: cnvldb.h
 	${INSTALL_DATA} $? $@
 
 vldb_check: vldb_check.o ${LIBS}
-	$(CC) ${CFLAGS} -o vldb_check vldb_check.o ${LIBS} ${XLIBS} 
+	$(CC) ${CFLAGS} -o vldb_check vldb_check.o ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 vldb_check.o: vldb_check.c AFS_component_version_number.o
 
 cnvldb: cnvldb.o ${LIBS}
-	$(CC) ${CFLAGS} -o cnvldb cnvldb.o ${LIBS} ${XLIBS}
+	$(CC) ${CFLAGS} -o cnvldb cnvldb.o ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 cnvldb.o: cnvldb.c cnvldb.h AFS_component_version_number.o
 
 sascnvldb: sascnvldb.o ${LIBS}
-	$(CC) ${CFLAGS} -o sascnvldb sascnvldb.o ${LIBS} ${XLIBS}
+	$(CC) ${CFLAGS} -o sascnvldb sascnvldb.o ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 sascnvldb.o: sascnvldb.c cnvldb.h AFS_component_version_number.o
 
 vlserver: vlserver.o vlutils.o vlprocs.o vldbint.ss.o vldbint.xdr.o $(LIBS)
 	$(CC) ${CFLAGS} -o vlserver vlserver.o vlutils.o vlprocs.o vldbint.ss.o \
-		vldbint.xdr.o $(LIBS) ${XLIBS} ${TOP_LIBDIR}/libaudit.a
+		vldbint.xdr.o $(LIBS) ${XLIBS} ${TOP_LIBDIR}/libaudit.a ${KRB5_LIBS}
 
 vlserver.o: vlserver.c ${INCLS} AFS_component_version_number.o
 vlutils.o: vlutils.c ${INCLS}
@@ -124,7 +124,7 @@ libvldb.a: $(OBJS) AFS_component_version
 	$(RANLIB) $@
 
 vlclient: vlclient.o libvldb.a $(LIBS)
-	$(CC) ${CFLAGS} -o vlclient vlclient.o libvldb.a $(LIBS) ${XLIBS} ${TOP_LIBDIR}/libcmd.a
+	$(CC) ${CFLAGS} -o vlclient vlclient.o libvldb.a $(LIBS) ${XLIBS} ${TOP_LIBDIR}/libcmd.a ${KRB5_LIBS}
 
 vlclient.o: vlclient.c ${INCLS} AFS_component_version_number.o
 
--- openafs-1.6.1.orig/src/vlserver/vlprocs.c
+++ openafs-1.6.1/src/vlserver/vlprocs.c
@@ -1423,11 +1423,10 @@ SVL_ListAttributesN2(struct rx_call *rxc
     afs_int32 blockindex = 0, count = 0, k, match;
     afs_int32 matchindex = 0;
     int serverindex = -1;	/* no server found */
-    int findserver = 0, findpartition = 0, findflag = 0, findname = 0;
+    int findserver = 0, findpartition = 0, findflag = 0;
     int pollcount = 0;
     int namematchRWBK, namematchRO, thismatch;
     int matchtype = 0;
-    char volumename[VL_MAXNAMELEN+2]; /* regex anchors */
     char rxstr[AFS_RXINFO_LEN];
 #ifdef HAVE_POSIX_REGEX
     regex_t re;
@@ -1476,8 +1475,7 @@ SVL_ListAttributesN2(struct rx_call *rxc
     }
 
     /* Search each entry in the database and return all entries
-     * that match the request. It checks volumename (with
-     * wildcarding), entry flags, server, and partition.
+     * that match the request. It checks entry flags, server, and partition.
      */
     else {
 	/* Get the server index for matching server address */
@@ -1491,21 +1489,9 @@ SVL_ListAttributesN2(struct rx_call *rxc
 	findpartition = ((attributes->Mask & VLLIST_PARTITION) ? 1 : 0);
 	findflag = ((attributes->Mask & VLLIST_FLAG) ? 1 : 0);
 	if (name && (strcmp(name, ".*") != 0) && (strcmp(name, "") != 0)) {
-	    sprintf(volumename, "^%s$", name);
-#ifdef HAVE_POSIX_REGEX
-	    if (regcomp(&re, volumename, REG_NOSUB) != 0) {
-		errorcode = VL_BADNAME;
-		goto done;
-	    }
-	    need_regfree = 1;
-#else
-	    t = (char *)re_comp(volumename);
-	    if (t) {
-		errorcode = VL_BADNAME;
-		goto done;
-	    }
-#endif
-	    findname = 1;
+	    /* regex-matching code has been disabled for security reasons. */
+	    errorcode = VL_BADNAME;
+	    goto done;
 	}
 
 	/* Read each entry and see if it is the one we want */
@@ -1535,38 +1521,12 @@ SVL_ListAttributesN2(struct rx_call *rxc
 		if (tentry.serverFlags[k] & VLSF_RWVOL) {
 		    /* Does the name match the RW name */
 		    if (tentry.flags & VLF_RWEXISTS) {
-			if (findname) {
-			    sprintf(volumename, "%s", tentry.name);
-#ifdef HAVE_POSIX_REGEX
-			    if (regexec(&re, volumename, 0, NULL, 0) == 0) {
-				thismatch = VLSF_RWVOL;
-			    }
-#else
-			    if (re_exec(volumename)) {
-				thismatch = VLSF_RWVOL;
-			    }
-#endif
-			} else {
-			    thismatch = VLSF_RWVOL;
-			}
+			thismatch = VLSF_RWVOL;
 		    }
 
 		    /* Does the name match the BK name */
 		    if (!thismatch && (tentry.flags & VLF_BACKEXISTS)) {
-			if (findname) {
-			    sprintf(volumename, "%s.backup", tentry.name);
-#ifdef HAVE_POSIX_REGEX
-			    if (regexec(&re, volumename, 0, NULL, 0) == 0) {
-				thismatch = VLSF_BACKVOL;
-			    }
-#else
-			    if (re_exec(volumename)) {
-				thismatch = VLSF_BACKVOL;
-			    }
-#endif
-			} else {
-			    thismatch = VLSF_BACKVOL;
-			}
+			thismatch = VLSF_BACKVOL;
 		    }
 
 		    namematchRWBK = (thismatch ? 1 : 2);
@@ -1578,25 +1538,7 @@ SVL_ListAttributesN2(struct rx_call *rxc
 		 */
 		else {
 		    if (tentry.flags & VLF_ROEXISTS) {
-			if (findname) {
-			    if (namematchRO) {
-				thismatch =
-				    ((namematchRO == 1) ? VLSF_ROVOL : 0);
-			    } else {
-				sprintf(volumename, "%s.readonly",
-					tentry.name);
-#ifdef HAVE_POSIX_REGEX
-			    if (regexec(&re, volumename, 0, NULL, 0) == 0) {
-				thismatch = VLSF_ROVOL;
-			    }
-#else
-				if (re_exec(volumename))
-				    thismatch = VLSF_ROVOL;
-#endif
-			    }
-			} else {
-			    thismatch = VLSF_ROVOL;
-			}
+			thismatch = VLSF_ROVOL;
 		    }
 		    namematchRO = (thismatch ? 1 : 2);
 		}
--- openafs-1.6.1.orig/src/volser/Makefile.in
+++ openafs-1.6.1/src/volser/Makefile.in
@@ -90,11 +90,11 @@ restorevol: restorevol.c
 		${TOP_LIBDIR}/libcmd.a ${TOP_LIBDIR}/util.a ${XLIBS}
 
 vos: vos.o ${VSOBJS} libvolser.a ${LIBS}
-	${CC} ${LDFLAGS} -o vos vos.o $(VSOBJS) libvolser.a ${LIBS} ${XLIBS}
+	${CC} ${LDFLAGS} -o vos vos.o $(VSOBJS) libvolser.a ${LIBS} ${XLIBS} ${KRB5_LIBS}
 
 volserver: $(SOBJS) $(LIBS) ${TOP_LIBDIR}/libdir.a
 	${CC} ${DBUG} -o volserver $(SOBJS) ${TOP_LIBDIR}/libdir.a \
-		${LDFLAGS} $(LIBS) ${XLIBS}
+		${LDFLAGS} $(LIBS) ${XLIBS} ${KRB5_LIBS}
 
 voldump: vol-dump.o ${VOLDUMP_LIBS}
 	${CC} ${CFLAGS} -o voldump vol-dump.o ${VOLDUMP_LIBS} ${XLIBS}
--- openafs-1.6.1.orig/src/volser/vos.c
+++ openafs-1.6.1/src/volser/vos.c
@@ -4502,7 +4502,7 @@ ListVLDB(struct cmd_syndesc *as, void *a
     aserver = 0;
     apart = 0;
 
-    attributes.Mask = 0;
+    memset(&attributes, 0, sizeof(attributes));
     lock = (as->parms[3].items ? 1 : 0);	/* -lock   flag */
     quiet = (as->parms[4].items ? 1 : 0);	/* -quit   flag */
     sort = (as->parms[5].items ? 0 : 1);	/* -nosort flag */
@@ -5005,7 +5005,7 @@ UnlockVLDB(struct cmd_syndesc *as, void
 
     apart = -1;
     totalE = 0;
-    attributes.Mask = 0;
+    memset(&attributes, 0, sizeof(attributes));
 
     if (as->parms[0].items) {	/* server specified */
 	aserver = GetServer(as->parms[0].items->data);
@@ -5518,6 +5518,8 @@ ConvertRO(struct cmd_syndesc *as, void *
     struct rx_connection *aconn;
     int c, dc;
 
+    memset(&storeEntry, 0, sizeof(struct nvldbentry));
+
     server = GetServer(as->parms[0].items->data);
     if (!server) {
 	fprintf(STDERR, "vos: host '%s' not found in host table\n",
--- openafs-1.6.1.orig/src/volser/vsprocs.c
+++ openafs-1.6.1/src/volser/vsprocs.c
@@ -736,6 +736,8 @@ UV_CreateVolume3(afs_uint32 aserver, afs
     aconn = (struct rx_connection *)0;
     error = 0;
 
+    memset(&storeEntry, 0, sizeof(struct nvldbentry));
+
     init_volintInfo(&tstatus);
     tstatus.maxquota = aquota;
 
@@ -860,6 +862,8 @@ UV_AddVLDBEntry(afs_uint32 aserver, afs_
     afs_int32 vcode;
     struct nvldbentry entry, storeEntry;	/*the new vldb entry */
 
+    memset(&storeEntry, 0, sizeof(struct nvldbentry));
+
     aconn = (struct rx_connection *)0;
     error = 0;
 
@@ -918,6 +922,8 @@ UV_DeleteVolume(afs_uint32 aserver, afs_
     afs_int32 avoltype = -1, vtype;
     int notondisk = 0, notinvldb = 0;
 
+    memset(&storeEntry, 0, sizeof(struct nvldbentry));
+
     /* Find and read bhe VLDB entry for this volume */
     code = ubik_VL_SetLock(cstruct, 0, avolid, avoltype, VLOP_DELETE);
     if (code) {
@@ -6910,6 +6916,7 @@ UV_SyncServer(afs_uint32 aserver, afs_in
     aconn = UV_Bind(aserver, AFSCONF_VOLUMEPORT);
 
     /* Set up attributes to search VLDB  */
+    memset(&attributes, 0, sizeof(attributes));
     attributes.server = ntohl(aserver);
     attributes.Mask = VLLIST_SERVER;
     if ((flags & 1)) {
@@ -7455,6 +7462,8 @@ MapNetworkToHost(struct nvldbentry *old,
 {
     int i, count;
 
+    memset(new, 0, sizeof(struct nvldbentry));
+
     /*copy all the fields */
     strcpy(new->name, old->name);
 /*    new->volumeType = old->volumeType;*/
--- openafs-1.6.1.orig/src/afs/VNOPS/afs_vnop_attrs.c
+++ openafs-1.6.1/src/afs/VNOPS/afs_vnop_attrs.c
@@ -347,6 +347,7 @@ afs_VAttrToAS(struct vcache *avc, struct
 {
     int mask;
     mask = 0;
+
     AFS_STATCNT(afs_VAttrToAS);
 #if     defined(AFS_DARWIN80_ENV)
     if (VATTR_IS_ACTIVE(av, va_mode)) {
@@ -472,6 +473,8 @@ afs_setattr(OSI_VC_DECL(avc), struct vat
     if ((code = afs_InitReq(&treq, acred)))
 	return code;
 
+    memset(&astat, 0, sizeof(astat));
+
     AFS_DISCON_LOCK();
 
     afs_InitFakeStat(&fakestate);
--- openafs-1.6.1.orig/src/afs/VNOPS/afs_vnop_create.c
+++ openafs-1.6.1/src/afs/VNOPS/afs_vnop_create.c
@@ -62,6 +62,9 @@ afs_create(OSI_VC_DECL(adp), char *aname
 
 
     AFS_STATCNT(afs_create);
+
+    memset(&InStatus, 0, sizeof(InStatus));
+
     if ((code = afs_InitReq(&treq, acred)))
 	goto done2;
 
--- openafs-1.6.1.orig/src/afs/VNOPS/afs_vnop_dirops.c
+++ openafs-1.6.1/src/afs/VNOPS/afs_vnop_dirops.c
@@ -59,6 +59,8 @@ afs_mkdir(OSI_VC_DECL(adp), char *aname,
     afs_Trace2(afs_iclSetp, CM_TRACE_MKDIR, ICL_TYPE_POINTER, adp,
 	       ICL_TYPE_STRING, aname);
 
+    memset(&InStatus, 0, sizeof(InStatus));
+
     if ((code = afs_InitReq(&treq, acred)))
 	goto done2;
     afs_InitFakeStat(&fakestate);
--- openafs-1.6.1.orig/src/afs/VNOPS/afs_vnop_symlink.c
+++ openafs-1.6.1/src/afs/VNOPS/afs_vnop_symlink.c
@@ -92,6 +92,8 @@ afs_symlink(OSI_VC_DECL(adp), char *anam
     afs_Trace2(afs_iclSetp, CM_TRACE_SYMLINK, ICL_TYPE_POINTER, adp,
 	       ICL_TYPE_STRING, aname);
 
+    memset(&InStatus, 0, sizeof(InStatus));
+
     if ((code = afs_InitReq(&treq, acred)))
 	goto done2;
 
--- openafs-1.6.1.orig/src/afs/afs_disconnected.c
+++ openafs-1.6.1/src/afs/afs_disconnected.c
@@ -669,6 +669,7 @@ afs_ProcessOpCreate(struct vcache *avc,
     tname = afs_osi_Alloc(AFSNAMEMAX);
     if (!tname)
 	return ENOMEM;
+    memset(&InStatus, 0, sizeof(InStatus));
 
     code = afs_GetParentVCache(avc, 0, &pdir_fid, tname, &tdp);
     if (code)
--- openafs-1.6.1.orig/src/bucoord/commands.c
+++ openafs-1.6.1/src/bucoord/commands.c
@@ -219,6 +219,7 @@ EvalVolumeSet2(struct bc_config *aconfig
     *avols = (struct bc_volumeDump *)0;
     bulkentries.nbulkentries_len = 0;
     bulkentries.nbulkentries_val = 0;
+    memset(&attributes, 0, sizeof(attributes));
 
     /* For each of the volume set entries - collect the volumes that match it */
     for (tve = avs->ventries; tve; tve = tve->next) {
--- openafs-1.6.1.orig/src/libadmin/vos/afs_vosAdmin.c
+++ openafs-1.6.1/src/libadmin/vos/afs_vosAdmin.c
@@ -1200,6 +1200,7 @@ GetServerRPC(void *rpc_specific, int slo
     bulkaddrs addr_multi;
     int i;
 
+    memset(&m_attrs, 0, sizeof(m_attrs));
     /*
      * Check to see if this is a multihomed address server
      */
--- openafs-1.6.1.orig/src/libadmin/vos/vsprocs.c
+++ openafs-1.6.1/src/libadmin/vos/vsprocs.c
@@ -3641,6 +3641,7 @@ UV_SyncServer(afs_cell_handle_p cellHand
     vcode = 0;
     noError = 1;
     arrayEntries.nbulkentries_val = 0;
+    memset(&attributes, 0, sizeof(attributes));
 
     /* Set up attributes to search VLDB  */
     attributes.server = ntohl(rx_HostOf(rx_PeerOf(server)));
--- openafs-1.6.1.orig/src/libafscp/afscp_file.c
+++ openafs-1.6.1/src/libafscp/afscp_file.c
@@ -124,6 +124,7 @@ afscp_PWrite(const struct afscp_venusfid
     off_t filesize;
     time_t now;
 
+    memset(&sst, 0, sizeof(sst));
     vol = afscp_VolumeById(fid->cell, fid->fid.Volume);
     if (vol == NULL) {
 	afscp_errno = ENOENT;
--- openafs-1.6.1.orig/src/venus/afsio.c
+++ openafs-1.6.1/src/venus/afsio.c
@@ -858,6 +858,7 @@ writeFile(struct cmd_syndesc *as, void *
     /* stdin on Windows defaults to _O_TEXT mode */
     _setmode(0, _O_BINARY);
 #endif
+    memset(&InStatus, 0, sizeof(InStatus));
 
     CmdProlog(as, &cell, &realm, &fname, &sSynthLen);
     afscp_AnonymousAuth(1);
--- openafs-1.6.1.orig/src/venus/cacheout.c
+++ openafs-1.6.1/src/venus/cacheout.c
@@ -69,6 +69,7 @@ ListServers(void)
     char hoststr[16];
     ListAddrByAttributes m_attrs;
 
+    memset(&m_attrs, 0, sizeof(m_attrs));
     memset(&addrs, 0, sizeof(addrs));
     memset(&spare3, 0, sizeof(spare3));
     code =
--- openafs-1.6.1.orig/src/vlserver/vlclient.c
+++ openafs-1.6.1/src/vlserver/vlclient.c
@@ -789,6 +789,7 @@ handleit(struct cmd_syndesc *as, void *a
 
 			printf("[0x%x %u] (special multi-homed entry)\n",
 			       *addrp, *addrp);
+			memset(&attrs, 0, sizeof(attrs));
 			attrs.Mask = VLADDR_INDEX;
 			mhaddrs.bulkaddrs_val = 0;
 			mhaddrs.bulkaddrs_len = 0;
@@ -864,6 +865,7 @@ handleit(struct cmd_syndesc *as, void *a
 
 			addrs2.bulkaddrs_val = 0;
 			addrs2.bulkaddrs_len = 0;
+			memset(&attrs, 0, sizeof(attrs));
 			attrs.Mask = VLADDR_INDEX;
 			attrs.index = (base * VL_MHSRV_PERBLK) + index;
 			code =
--- openafs-1.6.1.orig/src/afs/afs_buffer.c
+++ openafs-1.6.1/src/afs/afs_buffer.c
@@ -364,6 +364,8 @@ afs_newslot(struct dcache *adc, afs_int3
 	AFS_STATS(afs_stats_cmperf.bufFlushDirty++);
     }
 
+    /* Zero out the data so we don't leak something we shouldn't. */
+    memset(lp->data, 0, AFS_BUFFER_PAGESIZE);
     /* Now fill in the header. */
     lp->fid = adc->index;
     afs_copy_inode(&lp->inode, &adc->f.inode);
--- openafs-1.6.1.orig/src/dir/buffer.c
+++ openafs-1.6.1/src/dir/buffer.c
@@ -11,6 +11,7 @@
 #include <afs/param.h>
 
 
+#include <string.h>
 #include <stdlib.h>
 #include <lock.h>
 
@@ -449,7 +450,9 @@ DNew(afs_int32 *fid, int page)
     }
     ObtainWriteLock(&tb->lock);
     tb->lockers++;
+    memset(tb->data, 0, BUFFER_PAGE_SIZE);  /* don't leak other people's dirs */
     ReleaseWriteLock(&afs_bufferLock);
     ReleaseWriteLock(&tb->lock);
+
     return tb->data;
 }
--- openafs-1.6.1.orig/src/dir/dir.c
+++ openafs-1.6.1/src/dir/dir.c
@@ -204,7 +204,9 @@ Delete(void *dir, char *entry)
     DRelease(previtem, 1);
     index = DVOffset(firstitem) / 32;
     nitems = NameBlobs(firstitem->name);
-    DRelease(firstitem, 0);
+    /* Clear entire DirEntry and any DirXEntry extensions */
+    memset(firstitem, 0, nitems * sizeof(*firstitem));
+    DRelease(firstitem, 1);
     FreeBlobs(dir, index, nitems);
     return 0;
 }
--- openafs-1.6.1.orig/src/vol/salvaged.c
+++ openafs-1.6.1/src/vol/salvaged.c
@@ -206,6 +206,8 @@ handleit(struct cmd_syndesc *as, void *a
 	OKToZap = 1;
     if (as->parms[6].items)	/* -rootinodes */
 	ShowRootFiles = 1;
+    if (as->parms[7].items)	/* -salvagedirs */
+	RebuildDirs = 1;
     if (as->parms[8].items)	/* -ForceReads */
 	forceR = 1;
     if ((ti = as->parms[9].items)) {	/* -Parallel # */
