diff -Nru openafs-1.6.1/debian/changelog openafs-1.6.1/debian/changelog --- openafs-1.6.1/debian/changelog 2013-02-28 19:55:28.000000000 +0000 +++ openafs-1.6.1/debian/changelog 2013-07-24 02:34:20.000000000 +0000 @@ -1,3 +1,42 @@ +openafs (1.6.1-1+ubuntu0.2) precise-security; urgency=low + + * SECURITY UPDATE: Brute force DES attack permits compromise of AFS cell. + vos -encrypt doesn't encrypt connection data. + Buffer overflows which could cause a serverside denial of service. + - openafs-sa-2013-001.patch: Fix fileserver buffer overflow when parsing + client-supplied ACL entries and protect against client parsing of + bad ACL entries. Thanks to Nickolai Zeldovich. + - openafs-sa-2013-002.patch: Fix ptserver buffer overflow via integer + overflow in the IdToName RPC. Thanks to Nickolai Zeldovich + - 0001-Add-rxkad-server-hook-function-to-decrypt-more-types.patch + - 0002-New-optional-rxkad-functionality-for-decypting-krb5-.patch + - 0003-Integrate-keytab-based-decryption-into-afsconf_Build.patch + - 0004-Derive-DES-fcrypt-session-key-from-other-key-types.patch + - 0005-Move-akimpersonate-to-libauth.patch + - 0006-Clean-up-akimpersonate-and-use-for-server-to-server.patch + - 0007-auth-Do-not-always-fallback-to-noauth.patch + - 0008-Avoid-calling-afsconf_GetLatestKey-directly.patch + - 0009-Reload-rxkad.keytab-on-CellServDB-modification.patch + - 0010-Add-support-for-deriving-DES-keys-to-klog.krb5.patch + - 0011 skipped because it was a version bump + - 0012-ubik-Fix-encryption-selection-in-ugen.patch + - Thanks to Chaskiel Grundman, Alexander Chernyakhovsky, Ben Kaduk, + Andrew Deason, and Michael Meffie for the above patch series. + - swap-libs.patch: Resolve FTBFS with newer toolchains. Thanks to Anders + Kaseorg. + - OPENAFS-SA-2013-001 + - OPENAFS-SA-2013-002 + - OPENAFS-SA-2013-003 + - OPENAFS-SA-2013-004 + - CVE-2013-1794 + - CVE-2013-1795 + - CVE-2013-4134 + - CVE-2013-4135 + - LP: #1145560 + - LP: #1204195 + + -- Luke Faraone Tue, 23 Jul 2013 21:11:02 -0400 + openafs (1.6.1-1+ubuntu0.1) precise-proposed; urgency=low * Apply upstream deltas for Linux 3.5 (Closes: #685973) diff -Nru openafs-1.6.1/debian/patches/0001-Add-rxkad-server-hook-function-to-decrypt-more-types.patch openafs-1.6.1/debian/patches/0001-Add-rxkad-server-hook-function-to-decrypt-more-types.patch --- openafs-1.6.1/debian/patches/0001-Add-rxkad-server-hook-function-to-decrypt-more-types.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/0001-Add-rxkad-server-hook-function-to-decrypt-more-types.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,164 @@ +From 5e0cbc930508a697331bad07cc201c1e1985ff84 Mon Sep 17 00:00:00 2001 +From: Chaskiel Grundman +Date: Sat, 9 Feb 2013 12:01:37 -0500 +Subject: [PATCH 01/12] Add rxkad server hook function to decrypt more types + of tokens + +Allow tokens to be encrypted with algorithms other than DES. +The security object owner must provide an implementation +by calling rxkad_SetAltDecryptProc. + +Make sure plainsiz is initialized before calling the alternate decrypt +proc. +--- + src/rxkad/private_data.h | 1 + + src/rxkad/rxkad.p.h | 5 +++++ + src/rxkad/rxkad_prototypes.h | 5 ++++- + src/rxkad/rxkad_server.c | 13 +++++++++++- + src/rxkad/ticket5.c | 49 ++++++++++++++++++++++++++------------------ + 5 files changed, 51 insertions(+), 22 deletions(-) + +--- a/src/rxkad/private_data.h ++++ b/src/rxkad/private_data.h +@@ -82,6 +82,7 @@ + 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 */ +--- a/src/rxkad/rxkad.p.h ++++ b/src/rxkad/rxkad.p.h +@@ -93,6 +93,11 @@ + + 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 + + #endif /* OPENAFS_RXKAD_RXKAD_H */ +--- a/src/rxkad/rxkad_prototypes.h ++++ b/src/rxkad/rxkad_prototypes.h +@@ -130,6 +130,8 @@ + 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,8 @@ + 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); + + #if !defined(NO_DES_H_INCLUDE) + static_inline unsigned char * +--- a/src/rxkad/rxkad_server.c ++++ b/src/rxkad/rxkad_server.c +@@ -336,7 +336,8 @@ + 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 @@ + } + 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; ++} +--- a/src/rxkad/ticket5.c ++++ b/src/rxkad/ticket5.c +@@ -185,7 +185,8 @@ + 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 +227,41 @@ + 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) diff -Nru openafs-1.6.1/debian/patches/0002-New-optional-rxkad-functionality-for-decypting-krb5-.patch openafs-1.6.1/debian/patches/0002-New-optional-rxkad-functionality-for-decypting-krb5-.patch --- openafs-1.6.1/debian/patches/0002-New-optional-rxkad-functionality-for-decypting-krb5-.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/0002-New-optional-rxkad-functionality-for-decypting-krb5-.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,452 @@ +From 14db1a40e5be3b7325951d002885bbf288d570c1 Mon Sep 17 00:00:00 2001 +From: Chaskiel Grundman +Date: Sat, 9 Feb 2013 12:42:20 -0500 +Subject: [PATCH 02/12] New optional rxkad functionality for decypting krb5 + tokens + +An additional, optional mechanism for decrypting krb5-format tokens +is provided that uses the krb5 api with a key from a keytab +instead of using libdes and the AFS KeyFile. + +The AIX compat stub for krb5_c_decrypt is contributed by Andrew Deason. + +Change-Id: I97c08122c60482b84d602d6fa6482f1d5deef142 +--- + configure.ac | 13 +- + src/rxkad/Makefile.in | 5 +- + src/rxkad/rxkad_prototypes.h | 3 + + src/rxkad/ticket5_keytab.c | 353 ++++++++++++++++++++++++++++++++++++++++++ + src/shlibafsrpc/libafsrpc.map | 1 + + 5 files changed, 372 insertions(+), 3 deletions(-) + create mode 100644 src/rxkad/ticket5_keytab.c + +--- a/configure.ac ++++ b/configure.ac +@@ -56,8 +56,12 @@ + 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 +76,13 @@ + [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 ]) ++ 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 ]) ++ AC_CHECK_DECLS([krb5_free_keytab_entry_contents, krb5_kt_free_entry, ++ KRB5_KU_TICKET], [], [], [#include ]) + RRA_LIB_KRB5_RESTORE]) + AC_SUBST([BUILD_KRB5]) + AC_SUBST([MAKE_KRB5]) +--- a/src/rxkad/Makefile.in ++++ b/src/rxkad/Makefile.in +@@ -21,7 +21,7 @@ + + 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 @@ + + crypt_conn.o: crypt_conn.c fcrypt.h private_data.h ${INCLS} + ++ticket5_keytab.o: ticket5_keytab.c ${INCLS} ++ ${CCOBJ} ${CFLAGS} -c ${srcdir}/ticket5_keytab.c @KRB5_CPPFLAGS@ ++ + tcrypt.o: tcrypt.c AFS_component_version_number.o + + tcrypt: tcrypt.o librxkad.a +--- a/src/rxkad/rxkad_prototypes.h ++++ b/src/rxkad/rxkad_prototypes.h +@@ -163,6 +163,9 @@ + afs_int32 * host, afs_uint32 * start, + afs_uint32 * end, afs_int32 disableDotCheck, + rxkad_alt_decrypt_func alt_decrypt); ++/* ticket5_keytab.c */ ++extern int rxkad_InitKeytabDecrypt(const char *); ++extern int rxkad_BindKeytabDecrypt(struct rx_securityClass *); + + #if !defined(NO_DES_H_INCLUDE) + static_inline unsigned char * +--- /dev/null ++++ b/src/rxkad/ticket5_keytab.c +@@ -0,0 +1,353 @@ ++/* ++ * Copyright (c) 2013 Chaskiel Grundman ++ * 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 ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++#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 *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; ++ ++ time(&last_reload); ++ 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 retried, i, foundkey; ++ MUTEX_ENTER(&krb5_lock); ++ if (have_keytab_keys == 0) { ++ if (time(NULL) - last_reload > 600) { ++ reload_keys(); ++ } ++ if (have_keytab_keys == 0) { ++ MUTEX_EXIT(&krb5_lock); ++ return RXKADUNKNOWNKEY; ++ } ++ } ++ foundkey = 0; ++ code = -1; ++ retried = 0; ++retry: ++ 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 ++ } ++ } ++ if (code != 0 && time(NULL) - last_reload > 600 && !retried) { ++ reload_keys(); ++ retried = 1; ++ goto retry; ++ } ++ 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 *ktname) ++{ ++ int code; ++ static int keytab_init; ++ INIT_PTHREAD_LOCKS; ++ MUTEX_ENTER(&krb5_lock); ++ if (keytab_init) { ++ MUTEX_EXIT(&krb5_lock); ++ return 0; ++ } ++ 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 (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); ++} +--- a/src/shlibafsrpc/libafsrpc.map ++++ b/src/shlibafsrpc/libafsrpc.map +@@ -48,6 +48,7 @@ + rxkad_GetServerInfo; + rxkad_NewClientSecurityObject; + rxkad_NewServerSecurityObject; ++ rxkad_SetAltDecryptProc; + rxnull_NewClientSecurityObject; + rxnull_NewServerSecurityObject; + rxs_Release; diff -Nru openafs-1.6.1/debian/patches/0003-Integrate-keytab-based-decryption-into-afsconf_Build.patch openafs-1.6.1/debian/patches/0003-Integrate-keytab-based-decryption-into-afsconf_Build.patch --- openafs-1.6.1/debian/patches/0003-Integrate-keytab-based-decryption-into-afsconf_Build.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/0003-Integrate-keytab-based-decryption-into-afsconf_Build.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,878 @@ +From 33eecea7db14d06c59e1081b970d4caf0af773ca Mon Sep 17 00:00:00 2001 +From: Chaskiel Grundman +Date: Sun, 10 Feb 2013 13:27:03 -0500 +Subject: [PATCH 03/12] Integrate keytab-based decryption into + afsconf_BuildServerSecurityObjects + +Now all servers can have it. + +authcon.o grows a krb5 dependency and needs to get KRB5_CPPFLAGS. + +Change-Id: I95fecb3f88c19b3d5193ea8200fa20c86ec08ad7 +--- + configure.ac | 2 ++ + src/auth/Makefile.in | 3 +++ + src/auth/authcon.c | 48 +++++++++++++++++++++++++++++++++++++++-- + src/bozo/Makefile.in | 6 +++--- + src/bucoord/Makefile.in | 2 +- + src/budb/Makefile.in | 2 +- + src/butc/Makefile.in | 6 +++--- + src/config/Makefile.config.in | 1 + + src/dviced/Makefile.in | 2 +- + src/dvolser/Makefile.in | 2 +- + src/fsprobe/Makefile.in | 2 +- + src/kauth/Makefile.in | 24 ++++++++++----------- + src/libafsauthent/Makefile.in | 7 ++++-- + src/pam/Makefile.in | 5 +++-- + src/ptserver/Makefile.in | 18 ++++++++-------- + src/scout/Makefile.in | 2 +- + src/shlibafsauthent/Makefile.in | 9 +++++--- + src/tbudb/Makefile.in | 2 +- + src/tbutc/Makefile.in | 2 +- + src/tptserver/Makefile.in | 14 ++++++------ + src/tsm41/Makefile.in | 4 ++-- + src/tviced/Makefile.in | 2 +- + src/tvlserver/Makefile.in | 10 ++++----- + src/tvolser/Makefile.in | 2 +- + src/update/Makefile.in | 4 ++-- + src/uss/Makefile.in | 2 +- + src/util/dirpath.c | 3 +++ + src/util/dirpath.hin | 3 +++ + src/venus/Makefile.in | 14 ++++++------ + src/viced/Makefile.in | 8 +++---- + src/vlserver/Makefile.in | 10 ++++----- + src/volser/Makefile.in | 4 ++-- + 32 files changed, 144 insertions(+), 81 deletions(-) + +--- a/configure.ac ++++ b/configure.ac +@@ -50,6 +50,8 @@ + 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 \ +--- a/src/auth/Makefile.in ++++ b/src/auth/Makefile.in +@@ -57,7 +57,10 @@ + 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@ ++ + userok.o: userok.c ${INCLS} + cellconfig.o: cellconfig.c ${INCLS} + copyauth.o: copyauth.c ${INCLS} AFS_component_version_number.o +--- a/src/auth/authcon.c ++++ b/src/auth/authcon.c +@@ -26,7 +26,11 @@ + #include + #include + #include ++#ifdef USE_RXKAD_KEYTAB ++#include ++#endif + #include ++#include + #include "cellconfig.h" + #include "keys.h" + #include "auth.h" +@@ -51,13 +55,30 @@ + { + struct afsconf_dir *adir = (struct afsconf_dir *) arock; + struct rx_securityClass *tclass; +- ++#ifdef USE_RXKAD_KEYTAB ++ int keytab_enable = 0; ++ char *keytab_name; ++ size_t ktlen; ++ ktlen = 5 + strlen(adir->name) + 1 + strlen(AFSDIR_RXKAD_KEYTAB_FILE) + 1; ++ keytab_name = malloc(ktlen); ++ if (keytab_name != NULL) { ++ strcompose(keytab_name, ktlen, "FILE:", adir->name, "/", ++ AFSDIR_RXKAD_KEYTAB_FILE, (char *)NULL); ++ if (rxkad_InitKeytabDecrypt(keytab_name) == 0) ++ keytab_enable = 1; ++ 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 { +@@ -231,6 +252,20 @@ + struct rx_securityClass ***classes, + afs_int32 *numClasses) + { ++#ifdef USE_RXKAD_KEYTAB ++ int keytab_enable = 0; ++ char *keytab_name; ++ size_t ktlen; ++ ktlen = 5 + strlen(dir->name) + 1 + strlen(AFSDIR_RXKAD_KEYTAB_FILE) + 1; ++ keytab_name = malloc(ktlen); ++ if (keytab_name != NULL) { ++ strcompose(keytab_name, ktlen, "FILE:", dir->name, "/", ++ AFSDIR_RXKAD_KEYTAB_FILE, (char *)NULL); ++ if (rxkad_InitKeytabDecrypt(keytab_name) == 0) ++ keytab_enable = 1; ++ free(keytab_name); ++ } ++#endif + if (flags & AFSCONF_SEC_OBJS_RXKAD_CRYPT) + *numClasses = 4; + else +@@ -242,9 +277,18 @@ + (*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 + +--- a/src/bozo/Makefile.in ++++ b/src/bozo/Makefile.in +@@ -96,13 +96,13 @@ + $(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 @@ + $(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 +--- a/src/bucoord/Makefile.in ++++ b/src/bucoord/Makefile.in +@@ -67,7 +67,7 @@ + $(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 + +--- a/src/budb/Makefile.in ++++ b/src/budb/Makefile.in +@@ -96,7 +96,7 @@ + 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 +--- a/src/butc/Makefile.in ++++ b/src/butc/Makefile.in +@@ -56,15 +56,15 @@ + 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 +--- a/src/config/Makefile.config.in ++++ b/src/config/Makefile.config.in +@@ -47,6 +47,7 @@ + INCLUDE_LIBINTL = @INCLUDE_libintl@ + KERN_DBG = @KERN_DBG@ + KERN_OPTMZ = @KERN_OPTMZ@ ++KRB5_LIBS = @KRB5_LIBS@ + LD = @LD@ + LEX = @LEX@ + LIB_AFSDB = @LIB_AFSDB@ +--- a/src/dviced/Makefile.in ++++ b/src/dviced/Makefile.in +@@ -211,7 +211,7 @@ + ${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} +--- a/src/dvolser/Makefile.in ++++ b/src/dvolser/Makefile.in +@@ -218,7 +218,7 @@ + ${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} +--- a/src/fsprobe/Makefile.in ++++ b/src/fsprobe/Makefile.in +@@ -51,7 +51,7 @@ + + 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 +--- a/src/kauth/Makefile.in ++++ b/src/kauth/Makefile.in +@@ -89,7 +89,7 @@ + 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 @@ + + 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 @@ + ${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 @@ + ${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 @@ + 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 +--- a/src/libafsauthent/Makefile.in ++++ b/src/libafsauthent/Makefile.in +@@ -69,7 +69,7 @@ + fileutil.o + + RXKADOBJS = \ +- rxkad_errs.o ++ rxkad_errs.o @MAKE_KRB5@ ticket5_keytab.o + + SYSOBJS = \ + rmtsysc.o \ +@@ -131,7 +131,7 @@ + ${CCRULE} -I../auth + + authcon.o: ${AUTH}/authcon.c +- ${CCRULE} -I../auth ++ ${CCRULE} -I../auth @KRB5_CPPFLAGS@ + + ktc_errors.o: ${AUTH}/ktc_errors.c + ${CCRULE} +@@ -214,6 +214,9 @@ + 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 + +--- a/src/pam/Makefile.in ++++ b/src/pam/Makefile.in +@@ -22,9 +22,10 @@ + + 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 +--- a/src/ptserver/Makefile.in ++++ b/src/ptserver/Makefile.in +@@ -96,7 +96,7 @@ + # 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 @@ + 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 @@ + $(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} + +--- a/src/scout/Makefile.in ++++ b/src/scout/Makefile.in +@@ -53,7 +53,7 @@ + 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 +--- a/src/shlibafsauthent/Makefile.in ++++ b/src/shlibafsauthent/Makefile.in +@@ -74,7 +74,7 @@ + fileutil.o + + RXKADOBJS = \ +- rxkad_errs.o ++ rxkad_errs.o @MAKE_KRB5@ ticket5_keytab.o + + SYSOBJS = \ + rmtsysc.o \ +@@ -133,7 +133,7 @@ + ${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,7 @@ + ${CCRULE} + + authcon.o: ${AUTH}/authcon.c +- ${CCRULE} ++ ${CCRULE} @KRB5_CPPFLAGS@ + + ktc_errors.o: ${AUTH}/ktc_errors.c + ${CCRULE} +@@ -245,6 +245,9 @@ + rxkad_errs.o: ${RXKAD}/rxkad_errs.c + ${CCRULE} + ++ticket5_keytab.o: ${RXKAD}/ticket5_keytab.c ++ ${CCRULE} @KRB5_CPPFLAGS@ ++ + ptclient.o: ${PTSERVER}/ptclient.c + ${CCRULE} + +--- a/src/tbudb/Makefile.in ++++ b/src/tbudb/Makefile.in +@@ -155,7 +155,7 @@ + + + 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 +--- a/src/tbutc/Makefile.in ++++ b/src/tbutc/Makefile.in +@@ -70,7 +70,7 @@ + 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 +--- a/src/tptserver/Makefile.in ++++ b/src/tptserver/Makefile.in +@@ -155,7 +155,7 @@ + ${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 @@ + $(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 @@ + ${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 +--- a/src/tsm41/Makefile.in ++++ b/src/tsm41/Makefile.in +@@ -79,10 +79,10 @@ + $(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} +--- a/src/tviced/Makefile.in ++++ b/src/tviced/Makefile.in +@@ -205,7 +205,7 @@ + ${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} +--- a/src/tvlserver/Makefile.in ++++ b/src/tvlserver/Makefile.in +@@ -109,26 +109,26 @@ + + + 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 @@ + ${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 +--- a/src/tvolser/Makefile.in ++++ b/src/tvolser/Makefile.in +@@ -231,7 +231,7 @@ + ${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} +--- a/src/update/Makefile.in ++++ b/src/update/Makefile.in +@@ -30,10 +30,10 @@ + # 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 + +--- a/src/uss/Makefile.in ++++ b/src/uss/Makefile.in +@@ -47,7 +47,7 @@ + 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 +--- a/src/util/dirpath.c ++++ b/src/util/dirpath.c +@@ -389,6 +389,9 @@ + 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], +--- a/src/util/dirpath.hin ++++ b/src/util/dirpath.hin +@@ -149,6 +149,7 @@ + #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 @@ + 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 @@ + #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) +--- a/src/venus/Makefile.in ++++ b/src/venus/Makefile.in +@@ -68,7 +68,7 @@ + # 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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} + + + +--- a/src/viced/Makefile.in ++++ b/src/viced/Makefile.in +@@ -79,23 +79,23 @@ + 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} +--- a/src/vlserver/Makefile.in ++++ b/src/vlserver/Makefile.in +@@ -71,23 +71,23 @@ + ${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 @@ + $(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 + +--- a/src/volser/Makefile.in ++++ b/src/volser/Makefile.in +@@ -90,11 +90,11 @@ + ${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} diff -Nru openafs-1.6.1/debian/patches/0004-Derive-DES-fcrypt-session-key-from-other-key-types.patch openafs-1.6.1/debian/patches/0004-Derive-DES-fcrypt-session-key-from-other-key-types.patch --- openafs-1.6.1/debian/patches/0004-Derive-DES-fcrypt-session-key-from-other-key-types.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/0004-Derive-DES-fcrypt-session-key-from-other-key-types.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,308 @@ +From 1c7fa1405940a136a992d65023cc690b1111ab3e Mon Sep 17 00:00:00 2001 +From: Chaskiel Grundman +Date: Sun, 17 Mar 2013 21:58:47 -0400 +Subject: [PATCH 04/12] Derive DES/fcrypt session key from other key types + +If a kerberos 5 ticket has a session key with a non-DES enctype, +use the NIST SP800-108 KDF in counter mode with HMAC_MD5 as the PRF to +construct a DES key to be used by rxkad. + +To satisfy the requirements of the KDF, DES3 keys are first compressed into a +168 bit form by reversing the RFC3961 random-to-key algorithm + +Change-Id: I4dc8e83a641f9892b31c109fb9025251de3dcb27 +--- + src/aklog/aklog.c | 14 ++- + src/rxkad/rxkad_prototypes.h | 6 ++ + src/rxkad/ticket5.c | 198 ++++++++++++++++++++++++++++++++++++++---- + src/shlibafsrpc/libafsrpc.map | 1 + + 4 files changed, 199 insertions(+), 20 deletions(-) + +--- a/src/aklog/aklog.c ++++ b/src/aklog/aklog.c +@@ -692,6 +692,8 @@ + 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 +741,11 @@ + 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); + +@@ -2167,8 +2172,9 @@ + + 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[] = { +--- a/src/rxkad/rxkad_prototypes.h ++++ b/src/rxkad/rxkad_prototypes.h +@@ -163,6 +163,12 @@ + afs_int32 * host, afs_uint32 * start, + 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 *); + extern int rxkad_BindKeytabDecrypt(struct rx_securityClass *); +--- a/src/rxkad/ticket5.c ++++ b/src/rxkad/ticket5.c +@@ -71,6 +71,8 @@ + #include + #include + #include ++#include ++#include + #include "lifetimes.h" + #include "rxkad.h" + +@@ -176,8 +178,11 @@ + 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 +@@ -322,21 +327,9 @@ + } + + /* 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??? */ +@@ -484,3 +477,176 @@ + + 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; ++} +--- a/src/shlibafsrpc/libafsrpc.map ++++ b/src/shlibafsrpc/libafsrpc.map +@@ -55,6 +55,7 @@ + time_to_life; + tkt_CheckTimes; + tkt_DecodeTicket; ++ tkt_DeriveDesKey; + tkt_MakeTicket; + xdrrx_create; + hton_syserr_conv; diff -Nru openafs-1.6.1/debian/patches/0005-Move-akimpersonate-to-libauth.patch openafs-1.6.1/debian/patches/0005-Move-akimpersonate-to-libauth.patch --- openafs-1.6.1/debian/patches/0005-Move-akimpersonate-to-libauth.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/0005-Move-akimpersonate-to-libauth.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,971 @@ +From 15b77552b22e3ff3e7478008673775a45047f600 Mon Sep 17 00:00:00 2001 +From: Alexander Chernyakhovsky +Date: Tue, 14 May 2013 18:12:08 -0400 +Subject: [PATCH 05/12] Move akimpersonate to libauth + +Give it its own source file and header, install the header at +depinstall time, and have aklog get the akimpersonate functionality +from libauth. + +Keep the linux box copyright from aklog_main.c (but strip the trailing +whitespace), as that block was added with the akimpersonate code. + +Remove all calls to afs_com_err() as is fitting for library code, +to let it build. Do not bother removing curly braces which are +no longer needed; a future cleanup commit will catch that. +--- + src/aklog/aklog.c | 376 +---------------------------------- + src/auth/Makefile.in | 13 +- + src/auth/akimpersonate.c | 428 ++++++++++++++++++++++++++++++++++++++++ + src/auth/akimpersonate.h | 21 ++ + src/libafsauthent/Makefile.in | 5 +- + src/shlibafsauthent/Makefile.in | 5 +- + 6 files changed, 468 insertions(+), 380 deletions(-) + create mode 100644 src/auth/akimpersonate.c + create mode 100644 src/auth/akimpersonate.h + +--- a/src/aklog/aklog.c ++++ b/src/aklog/aklog.c +@@ -91,6 +91,7 @@ + #include + #include + #include ++#include + + #include "aklog.h" + #include "linked_list.h" +@@ -188,60 +189,6 @@ + #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 */ + #elif !defined(HAVE_KRB5_524_CONVERT_CREDS) && defined(HAVE_KRB524_CONVERT_CREDS_KDC) +@@ -1813,327 +1760,6 @@ + } + + 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) + { +--- a/src/auth/Makefile.in ++++ b/src/auth/Makefile.in +@@ -14,15 +14,15 @@ + 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 + 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 + + 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 + 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 @@ + + 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/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} $? $@ + +@@ -61,6 +65,9 @@ + 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@ ++ + userok.o: userok.c ${INCLS} + cellconfig.o: cellconfig.c ${INCLS} + copyauth.o: copyauth.c ${INCLS} AFS_component_version_number.o +--- /dev/null ++++ b/src/auth/akimpersonate.c +@@ -0,0 +1,428 @@ ++/* ++ * 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. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "akimpersonate.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 ++ ++#if !defined(HAVE_KRB5_ENCRYPT_TKT_PART) && defined(HAVE_ENCODE_KRB5_ENC_TKT_PART) && defined(HAVE_KRB5_C_ENCRYPT) ++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 ++ ++static const int any_enctype[2] = {0, 0}; ++static const krb5_data empty_string; ++ ++#define deref_enc_tkt_addrs(tkt) \ ++ tkt->caddr ++ ++#define deref_enc_length(enc) \ ++ ((enc)->cipher.length) ++ ++#define deref_enc_data(enc) \ ++ ((enc)->cipher.data) ++ ++#define krb5_free_keytab_entry_contents krb5_kt_free_entry ++ ++#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_length(enc) \ ++ ((enc)->ciphertext.length) ++ ++#define deref_enc_data(enc) \ ++ ((enc)->ciphertext.data) ++ ++#endif ++ ++#define deref_entry_enctype(entry) \ ++ deref_keyblock_enctype(&deref_entry_keyblock(entry)) ++ ++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]; ++#endif ++ krb5_data * temp; ++ 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) { ++ 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) { ++ 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))) { ++ 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))) { ++ code = i; ++ goto cleanup; ++ } ++ if (best < 0) { ++ 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))) { ++ 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))) { ++ 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) { ++ goto cleanup; ++ } ++ ++ if(buf_len != 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) { ++ 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))) { ++ goto cleanup; ++ } ++ ticket_reply->enc_part.kvno = entry->vno; ++#endif ++ ++ /* Construct Creds */ ++ ++ if ((code = krb5_copy_principal(context, service_principal, ++ &creds->server))) { ++ goto cleanup; ++ } ++ if ((code = krb5_copy_principal(context, client_principal, ++ &creds->client))) { ++ goto cleanup; ++ } ++ if ((code = krb5_copy_keyblock_contents(context, session_key, ++ &deref_session_key(creds)))) { ++ 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))) { ++ 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) { ++ goto cleanup; ++ } ++ } ++#else ++ if ((code = encode_krb5_ticket(ticket_reply, &temp))) { ++ 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); ++out: ++ return code; ++#else ++ return -1; ++#endif ++} +--- /dev/null ++++ b/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, int *, int *, krb5_creds**); ++ ++#endif +--- a/src/libafsauthent/Makefile.in ++++ b/src/libafsauthent/Makefile.in +@@ -36,7 +36,7 @@ + writeconfig.o \ + authcon.o \ + ktc_errors.o \ +- acfg_errors.o ++ acfg_errors.o @MAKE_KRB5@ akimpersonate.o + + KAUTHOBJS = \ + kauth.xdr.o \ +@@ -133,6 +133,9 @@ + authcon.o: ${AUTH}/authcon.c + ${CCRULE} -I../auth @KRB5_CPPFLAGS@ + ++akimpersonate.o: ${AUTH}/akimpersonate.c ++ ${CCRULE} -I../auth @KRB5_CPPFLAGS@ ++ + ktc_errors.o: ${AUTH}/ktc_errors.c + ${CCRULE} + +--- a/src/shlibafsauthent/Makefile.in ++++ b/src/shlibafsauthent/Makefile.in +@@ -41,7 +41,7 @@ + writeconfig.o \ + authcon.o \ + ktc_errors.o \ +- acfg_errors.o ++ acfg_errors.o @MAKE_KRB5@ akimpersonate.o + + KAUTHOBJS = \ + kauth.xdr.o \ +@@ -164,6 +164,9 @@ + authcon.o: ${AUTH}/authcon.c + ${CCRULE} @KRB5_CPPFLAGS@ + ++akimpersonate.o: ${AUTH}/akimpersonate.c ++ ${CCRULE} @KRB5_CPPFLAGS@ ++ + ktc_errors.o: ${AUTH}/ktc_errors.c + ${CCRULE} + diff -Nru openafs-1.6.1/debian/patches/0006-Clean-up-akimpersonate-and-use-for-server-to-server.patch openafs-1.6.1/debian/patches/0006-Clean-up-akimpersonate-and-use-for-server-to-server.patch --- openafs-1.6.1/debian/patches/0006-Clean-up-akimpersonate-and-use-for-server-to-server.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/0006-Clean-up-akimpersonate-and-use-for-server-to-server.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,1478 @@ +From 95d57c74476c5a02ce6d9ca913dcbf88ac5c1143 Mon Sep 17 00:00:00 2001 +From: Ben Kaduk +Date: Tue, 14 May 2013 19:37:59 -0400 +Subject: [PATCH 06/12] Clean up akimpersonate and use for server-to-server + +Since a6d7cacfd, aklog has been able to print a krb5 ticket to +itself for an arbitrary client principal, allowing a user with +access to the cell's krb5 key to get tokens as an arbitrary user. + +Now that it is possible to use native krb5 tickets with non-DES +enctypes for authentication, and akimpersonate is available from libauth, +use printed native krb5 tickets for server-to-server communication (as well +as the -localauth versions of the client utilities). + +Remove the early call to afsconf_GetLatestKey() in +afsconf_PickClientSecObj() so that we do not end up picking an old DES +key before we try to find a better key to use. + +Before doing so, refactor the akimpersonate code to be more usable +and readable, and eliminate some dead code. For example, we always printed +addressless tickets, so that code could be removed. Other code had excessive +stack usage for a library routine, which is eliminated. Use a start time +of 0 instead of 300 so that the printed ticket will always be +detected as infinite-lifetime. + +In order to ensure usability on all platforms (in particular Solaris), +provide a couple more compat shims to implement routines which are not +always available from the krb5 library, in particular encode_krb5_ticket +and encode_krb5_enc_tkt_part. Thanks to Andrew Deason for implementing +these compatability routines. + +UKERNEL doesn't need this stuff. +--- + src/aklog/aklog.c | 9 +- + src/auth/Makefile.in | 9 +- + src/auth/akimpersonate.c | 839 ++++++++++++++++++++++++++++------------ + src/auth/akimpersonate.h | 2 +- + src/auth/akimpersonate_v5gen.c | 175 +++++++++ + src/auth/akimpersonate_v5gen.h | 30 ++ + src/auth/authcon.c | 88 ++++- + src/libafsauthent/Makefile.in | 5 +- + src/rxkad/Makefile.in | 2 +- + src/shlibafsauthent/Makefile.in | 5 +- + src/shlibafsrpc/libafsrpc.map | 4 + + 11 files changed, 903 insertions(+), 265 deletions(-) + create mode 100644 src/auth/akimpersonate_v5gen.c + create mode 100644 src/auth/akimpersonate_v5gen.h + +--- a/src/aklog/aklog.c ++++ b/src/aklog/aklog.c +@@ -1803,17 +1803,12 @@ + 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); +--- a/src/auth/Makefile.in ++++ b/src/auth/Makefile.in +@@ -14,15 +14,15 @@ + INSTALL_SCRIPT = @INSTALL_SCRIPT@ + + OBJS= cellconfig.o ktc.o userok.o writeconfig.o authcon.o \ +- acfg_errors.o ktc_errors.o @MAKE_KRB5@ akimpersonate.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 @MAKE_KRB5@ akimpersonate.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 akimpersonate.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 +@@ -68,6 +68,9 @@ + 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 +--- a/src/auth/akimpersonate.c ++++ b/src/auth/akimpersonate.c +@@ -27,6 +27,36 @@ + * 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 + #include +@@ -38,6 +68,7 @@ + #include + + #include "akimpersonate.h" ++#include "akimpersonate_v5gen.h" + + #ifdef HAVE_KRB5_CREDS_KEYBLOCK + #define USING_MIT 1 +@@ -47,16 +78,178 @@ + #endif + + #if USING_HEIMDAL +-#define deref_keyblock_enctype(kb) \ +- ((kb)->keytype) ++#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; ++ } + +-#define deref_entry_keyblock(entry) \ +- entry->keyblock ++ 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; + +-#define deref_session_key(creds) \ +- creds->session ++ 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; + +-#if !defined(HAVE_KRB5_ENCRYPT_TKT_PART) && defined(HAVE_ENCODE_KRB5_ENC_TKT_PART) && defined(HAVE_KRB5_C_ENCRYPT) ++ 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, +@@ -89,286 +282,356 @@ + } + return code; + } +-#endif ++# 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; + +-#define deref_enc_tkt_addrs(tkt) \ +- tkt->caddr +- +-#define deref_enc_length(enc) \ +- ((enc)->cipher.length) ++/* ++ * 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; + +-#define deref_enc_data(enc) \ +- ((enc)->cipher.data) ++ return 0; ++} ++#else ++static int ++alloc_ticket(krb5_ticket **out) ++{ ++ *out = calloc(1, sizeof(krb5_ticket)); ++ if (*out == NULL) ++ return ENOMEM; + +-#define krb5_free_keytab_entry_contents krb5_kt_free_entry ++ return 0; ++} ++#endif + ++static void ++free_ticket(void *in) ++{ ++#if USING_HEIMDAL ++ Ticket *ticket_reply; + #else +-#define deref_keyblock_enctype(kb) \ +- ((kb)->enctype) +- +-#define deref_entry_keyblock(entry) \ +- entry->key ++ krb5_ticket *ticket_reply; ++#endif + +-#define deref_session_key(creds) \ +- creds->keyblock ++ /* requisite aliasing for MIT/Heimdal support. */ ++ ticket_reply = in; ++ if (ticket_reply == NULL) ++ return; + +-#define deref_enc_tkt_addrs(tkt) \ +- tkt->caddrs ++#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); ++} + +-#define deref_enc_length(enc) \ +- ((enc)->ciphertext.length) ++/* ++ * 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; + +-#define deref_enc_data(enc) \ +- ((enc)->ciphertext.data) ++ 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 + +-#define deref_entry_enctype(entry) \ +- deref_keyblock_enctype(&deref_entry_keyblock(entry)) ++ /* Aliasing for MIT/Heimdal support. */ ++ enc_tkt_reply = in; ++ if (enc_tkt_reply == NULL) ++ return; + +-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]; ++ if (enc_tkt_reply->starttime != NULL) ++ free(enc_tkt_reply->starttime); ++#else ++ /* No allocations needed for MIT's krb5_enc_tkt_part structure. */ + #endif +- krb5_data * temp; +- 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; ++ free(enc_tkt_reply); ++} + +- 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) { +- goto cleanup; ++/* ++ * 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; ++} + +- 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) { ++/* ++ * 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; +- } +- } else { +- krb5_keytab_entry new[1]; +- int best = -1; +- memset(new, 0, sizeof *new); +- if ((code == krb5_kt_start_seq_get(context, kt, cursor))) { +- 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))) { +- code = i; +- goto cleanup; +- } +- if (best < 0) { +- goto cleanup; +- } +- deref_keyblock_enctype(session_key) = deref_entry_enctype(entry); ++ } + } + +- /* Make Ticket */ ++ /* 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 +- if ((code = krb5_generate_random_keyblock(context, +- deref_keyblock_enctype(session_key), 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->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))) { +- 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->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 +- } ++/* ++ * 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 +- faddr->len = i; ++ Ticket *ticket_reply; ++ EncTicketPart *enc_tkt_reply; ++ krb5_crypto crypto = 0; ++ unsigned char *buf = 0; ++ size_t buf_size, buf_len; + #else +- faddr[i] = 0; ++ 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; + +- { /* 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) { +- goto cleanup; +- } +- +- if(buf_len != 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) { +- goto cleanup; +- } +- } /* crypto block */ ++ 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 = 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))) { ++ 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 + +- /* Construct Creds */ ++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; + +- if ((code = krb5_copy_principal(context, service_principal, +- &creds->server))) { ++ code = krb5_copy_principal(context, service_principal, &creds->server); ++ if (code != 0) + goto cleanup; +- } +- if ((code = krb5_copy_principal(context, client_principal, +- &creds->client))) { ++ code = krb5_copy_principal(context, client_principal, &creds->client); ++ if (code != 0) + goto cleanup; +- } +- if ((code = krb5_copy_keyblock_contents(context, session_key, +- &deref_session_key(creds)))) { ++ 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; +@@ -380,49 +643,133 @@ + 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))) { +- 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) { +- goto cleanup; +- } +- } ++ ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, ++ ticket_reply, &dummy, code); ++ if (code != 0 || dummy != creds->ticket.length) ++ goto cleanup; + #else +- if ((code = encode_krb5_ticket(ticket_reply, &temp))) { ++ 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 = 0; ++ creds = NULL; + cleanup: +- if (deref_enc_data(&ticket_reply->enc_part)) ++ 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) ++ if (client_principal != NULL) + krb5_free_principal(context, client_principal); +- if (service_principal) ++ if (service_principal != NULL) + krb5_free_principal(context, service_principal); +- if (cc) +- krb5_cc_close(context, cc); +- if (kt) ++ if (kt != NULL) + krb5_kt_close(context, kt); +- if (creds) krb5_free_creds(context, creds); ++ if (creds != NULL) ++ krb5_free_creds(context, creds); + krb5_free_keyblock_contents(context, session_key); +-out: ++ free_ticket(ticket_reply); ++ free_enc_tkt_part(enc_tkt_reply); + return code; +-#else +- return -1; +-#endif + } +--- a/src/auth/akimpersonate.h ++++ b/src/auth/akimpersonate.h +@@ -16,6 +16,6 @@ + /* 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, int *, int *, krb5_creds**); ++ time_t, time_t, const int *, krb5_creds**); + + #endif +--- /dev/null ++++ b/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 ++#include ++ ++/* 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 ++ ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++ ++# 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 ++++ b/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 +--- a/src/auth/authcon.c ++++ b/src/auth/authcon.c +@@ -26,14 +26,19 @@ + #include + #include + #include +-#ifdef USE_RXKAD_KEYTAB ++#if defined(USE_RXKAD_KEYTAB) && !defined(UKERNEL) + #include ++#include + #endif + #include ++#include + #include + #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 +@@ -88,6 +93,76 @@ + } + #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, +@@ -101,6 +176,13 @@ + 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) { +@@ -347,10 +429,6 @@ + return AFSCONF_NOCELLDB; + + if (flags & AFSCONF_SECOPTS_LOCALAUTH) { +- code = afsconf_GetLatestKey(dir, 0, 0); +- if (code) +- goto out; +- + if (flags & AFSCONF_SECOPTS_ALWAYSENCRYPT) + code = afsconf_ClientAuthSecure(dir, sc, scIndex); + else +--- a/src/libafsauthent/Makefile.in ++++ b/src/libafsauthent/Makefile.in +@@ -36,7 +36,7 @@ + writeconfig.o \ + authcon.o \ + ktc_errors.o \ +- acfg_errors.o @MAKE_KRB5@ akimpersonate.o ++ acfg_errors.o @MAKE_KRB5@ akimpersonate.o akimpersonate_v5gen.o + + KAUTHOBJS = \ + kauth.xdr.o \ +@@ -136,6 +136,9 @@ + 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} + +--- a/src/rxkad/Makefile.in ++++ b/src/rxkad/Makefile.in +@@ -93,7 +93,7 @@ + crypt_conn.o: crypt_conn.c fcrypt.h private_data.h ${INCLS} + + ticket5_keytab.o: ticket5_keytab.c ${INCLS} +- ${CCOBJ} ${CFLAGS} -c ${srcdir}/ticket5_keytab.c @KRB5_CPPFLAGS@ ++ ${CC} ${CFLAGS} -c ${srcdir}/ticket5_keytab.c @KRB5_CPPFLAGS@ + + tcrypt.o: tcrypt.c AFS_component_version_number.o + +--- a/src/shlibafsauthent/Makefile.in ++++ b/src/shlibafsauthent/Makefile.in +@@ -41,7 +41,7 @@ + writeconfig.o \ + authcon.o \ + ktc_errors.o \ +- acfg_errors.o @MAKE_KRB5@ akimpersonate.o ++ acfg_errors.o @MAKE_KRB5@ akimpersonate.o akimpersonate_v5gen.o + + KAUTHOBJS = \ + kauth.xdr.o \ +@@ -167,6 +167,9 @@ + 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} + +--- a/src/shlibafsrpc/libafsrpc.map ++++ b/src/shlibafsrpc/libafsrpc.map +@@ -148,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: + *; + }; diff -Nru openafs-1.6.1/debian/patches/0007-auth-Do-not-always-fallback-to-noauth.patch openafs-1.6.1/debian/patches/0007-auth-Do-not-always-fallback-to-noauth.patch --- openafs-1.6.1/debian/patches/0007-auth-Do-not-always-fallback-to-noauth.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/0007-auth-Do-not-always-fallback-to-noauth.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,100 @@ +From d4788f6e283b79a1b974dda1e8fae213efd34930 Mon Sep 17 00:00:00 2001 +From: Andrew Deason +Date: Mon, 10 Jun 2013 17:15:27 -0500 +Subject: [PATCH 07/12] auth: Do not always fallback to noauth + +Make afsconf_PickClientSecObj error out if we can't construct +localauth tokens (unless the caller explicitly requested rxnull +fallback). afsconf_ClientAuth{,Secure} still falls back, as always. +--- + src/auth/authcon.c | 29 +++++++++++++++++++++-------- + 1 file changed, 21 insertions(+), 8 deletions(-) + +--- a/src/auth/authcon.c ++++ b/src/auth/authcon.c +@@ -167,7 +167,8 @@ + 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; +@@ -186,14 +187,14 @@ + /* 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 */ +@@ -206,7 +207,7 @@ + * 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. +@@ -219,6 +220,12 @@ + *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 +@@ -232,7 +239,7 @@ + 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; + } +@@ -250,7 +257,7 @@ + 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; + } +@@ -429,10 +436,16 @@ + return AFSCONF_NOCELLDB; + + if (flags & AFSCONF_SECOPTS_LOCALAUTH) { ++ 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; diff -Nru openafs-1.6.1/debian/patches/0008-Avoid-calling-afsconf_GetLatestKey-directly.patch openafs-1.6.1/debian/patches/0008-Avoid-calling-afsconf_GetLatestKey-directly.patch --- openafs-1.6.1/debian/patches/0008-Avoid-calling-afsconf_GetLatestKey-directly.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/0008-Avoid-calling-afsconf_GetLatestKey-directly.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,90 @@ +From d2024c158e3a879305ff17cf726d3958f20677f4 Mon Sep 17 00:00:00 2001 +From: Andrew Deason +Date: Mon, 10 Jun 2013 17:49:12 -0500 +Subject: [PATCH 08/12] Avoid calling afsconf_GetLatestKey directly + +Don't call afsconf_GetLatestKey to determine whether we can print our +own local tokens, since we may have keytab 'local' keys, but no DES +keys. Just try to construct them and see if it fails, using +afsconf_PickClientSecObj or afsconf_ClientAuth{,Secure} as +appropriate. +--- + src/ptserver/ptserver.c | 11 ----------- + src/ptserver/ptuser.c | 11 ++++------- + src/viced/host.c | 15 ++++++--------- + 3 files changed, 10 insertions(+), 27 deletions(-) + +--- a/src/ptserver/ptserver.c ++++ b/src/ptserver/ptserver.c +@@ -210,7 +210,6 @@ + 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 @@ + 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; +--- a/src/ptserver/ptuser.c ++++ b/src/ptserver/ptuser.c +@@ -292,16 +292,13 @@ + * 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) +--- a/src/viced/host.c ++++ b/src/viced/host.c +@@ -305,15 +305,12 @@ + /* 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) diff -Nru openafs-1.6.1/debian/patches/0009-Reload-rxkad.keytab-on-CellServDB-modification.patch openafs-1.6.1/debian/patches/0009-Reload-rxkad.keytab-on-CellServDB-modification.patch --- openafs-1.6.1/debian/patches/0009-Reload-rxkad.keytab-on-CellServDB-modification.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/0009-Reload-rxkad.keytab-on-CellServDB-modification.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,203 @@ +From 4b7553600a7659d117df0bde7b1c1dfde031deb8 Mon Sep 17 00:00:00 2001 +From: Andrew Deason +Date: Wed, 10 Jul 2013 12:52:28 -0500 +Subject: [PATCH 09/12] Reload rxkad.keytab on CellServDB modification + +Make the reloading of rxkad.keytab keys occur in the same way that +KeyFile keys are reloaded. That is, we only try to reload them if the +CellServDB mtime has changed. This is intended to have exactly the +same reloading behavior as KeyFile reloads. + +I would have triggered this from afsconf_Check, but that approach +has annoyances. (Calling ticket5_keytab functions directly from +cellconfig pulls in libkrb5 dependencies for everything that uses +cellconfig, and we'd have to trigger an afsconf_Check call by calling +some other cellconfig function.) + +9102f49a3bdc67ed74e254349eb55b529472f45c +--- + src/auth/authcon.c | 26 ++++++++++++++++++------ + src/rxkad/rxkad_prototypes.h | 2 +- + src/rxkad/ticket5_keytab.c | 47 ++++++++++++++++++++++++++++---------------- + 3 files changed, 51 insertions(+), 24 deletions(-) + +--- a/src/auth/authcon.c ++++ b/src/auth/authcon.c +@@ -62,17 +62,24 @@ + 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 (keytab_name != NULL) { ++ 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(keytab_name) == 0) ++ if (rxkad_InitKeytabDecrypt(csdb_name, keytab_name) == 0) + keytab_enable = 1; +- free(keytab_name); + } ++ free(csdb_name); ++ free(keytab_name); + #endif + LOCK_GLOBAL_MUTEX; + tclass = (struct rx_securityClass *) +@@ -343,17 +350,24 @@ + { + #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 (keytab_name != NULL) { ++ 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(keytab_name) == 0) ++ if (rxkad_InitKeytabDecrypt(csdb_name, keytab_name) == 0) + keytab_enable = 1; +- free(keytab_name); + } ++ free(csdb_name); ++ free(keytab_name); + #endif + if (flags & AFSCONF_SEC_OBJS_RXKAD_CRYPT) + *numClasses = 4; +--- a/src/rxkad/rxkad_prototypes.h ++++ b/src/rxkad/rxkad_prototypes.h +@@ -170,7 +170,7 @@ + extern int tkt_DeriveDesKey(int enctype, void *keydata, size_t keylen, struct ktc_encryptionKey + *output); + /* ticket5_keytab.c */ +-extern int rxkad_InitKeytabDecrypt(const char *); ++extern int rxkad_InitKeytabDecrypt(const char *, const char *); + extern int rxkad_BindKeytabDecrypt(struct rx_securityClass *); + + #if !defined(NO_DES_H_INCLUDE) +--- a/src/rxkad/ticket5_keytab.c ++++ b/src/rxkad/ticket5_keytab.c +@@ -31,6 +31,7 @@ + + #include + #include ++#include + + #include + +@@ -39,6 +40,7 @@ + #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; + +@@ -95,8 +97,22 @@ + 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; ++ } + +- time(&last_reload); + if (keytab_name != NULL) + ret = krb5_kt_resolve(k5ctx, keytab_name, &fkeytab); + else +@@ -219,21 +235,15 @@ + krb5_enc_data ind; + #endif + krb5_data outd; +- int retried, i, foundkey; ++ int i, foundkey; + MUTEX_ENTER(&krb5_lock); ++ reload_keys(); + if (have_keytab_keys == 0) { +- if (time(NULL) - last_reload > 600) { +- reload_keys(); +- } +- if (have_keytab_keys == 0) { +- MUTEX_EXIT(&krb5_lock); +- return RXKADUNKNOWNKEY; +- } ++ MUTEX_EXIT(&krb5_lock); ++ return RXKADUNKNOWNKEY; + } + foundkey = 0; + code = -1; +- retried = 0; +-retry: + for (i = 0; i < nkeys; i++) { + /* foundkey determines what error code we return for failure */ + if (ktent[i].vno == kvno) +@@ -283,11 +293,6 @@ + #endif + } + } +- if (code != 0 && time(NULL) - last_reload > 600 && !retried) { +- reload_keys(); +- retried = 1; +- goto retry; +- } + MUTEX_EXIT(&krb5_lock); + if (code == 0) + return 0; +@@ -309,7 +314,7 @@ + #define INIT_PTHREAD_LOCKS + #endif + int +-rxkad_InitKeytabDecrypt(const char *ktname) ++rxkad_InitKeytabDecrypt(const char *csdb, const char *ktname) + { + int code; + static int keytab_init; +@@ -319,6 +324,11 @@ + 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); +@@ -336,6 +346,9 @@ + MUTEX_EXIT(&krb5_lock); + return 0; + cleanup: ++ if (checkfile_path != NULL) { ++ free(checkfile_path); ++ } + if (keytab_name != NULL) { + free(keytab_name); + } diff -Nru openafs-1.6.1/debian/patches/0010-Add-support-for-deriving-DES-keys-to-klog.krb5.patch openafs-1.6.1/debian/patches/0010-Add-support-for-deriving-DES-keys-to-klog.krb5.patch --- openafs-1.6.1/debian/patches/0010-Add-support-for-deriving-DES-keys-to-klog.krb5.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/0010-Add-support-for-deriving-DES-keys-to-klog.krb5.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,56 @@ +From 9e1c24a583634e6102091388dedc47745efce78a Mon Sep 17 00:00:00 2001 +From: Ben Kaduk +Date: Sat, 13 Jul 2013 10:49:27 +0100 +Subject: [PATCH 10/12] Add support for deriving DES keys to klog.krb5 + +(cherry picked from commit e79102e7918ce5196e870a806879135743ec3abb) + +Change-Id: Ia7ebfdd10dcfd6cd164b10275016147630748bac +--- + src/aklog/klog.c | 21 +++++++++------------ + 1 file changed, 9 insertions(+), 12 deletions(-) + +--- a/src/aklog/klog.c ++++ b/src/aklog/klog.c +@@ -667,9 +667,6 @@ + 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 @@ + 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 @@ + } + 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); diff -Nru openafs-1.6.1/debian/patches/0012-ubik-Fix-encryption-selection-in-ugen.patch openafs-1.6.1/debian/patches/0012-ubik-Fix-encryption-selection-in-ugen.patch --- openafs-1.6.1/debian/patches/0012-ubik-Fix-encryption-selection-in-ugen.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/0012-ubik-Fix-encryption-selection-in-ugen.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,24 @@ +From 5f5b02a57102af1a85fb9bdaaec31b6094d0c9c4 Mon Sep 17 00:00:00 2001 +From: Michael Meffie +Date: Wed, 17 Jul 2013 23:10:42 +0100 +Subject: [PATCH 12/12] ubik: Fix encryption selection in ugen + +Make sure that we encrypt when requested to by the application + +Change-Id: If4c2ba2257bf060d3e9169ccdbcae54f54dfe5d7 +--- + src/ubik/uinit.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/src/ubik/uinit.c ++++ b/src/ubik/uinit.c +@@ -80,6 +80,9 @@ + secFlags |= AFSCONF_SECOPTS_NOAUTH; + } + ++ if (gen_rxkad_level == rxkad_crypt) ++ secFlags |= AFSCONF_SECOPTS_ALWAYSENCRYPT; ++ + tdir = afsconf_Open(confdir); + if (!tdir) { + fprintf(stderr, diff -Nru openafs-1.6.1/debian/patches/openafs-sa-2013-001.patch openafs-1.6.1/debian/patches/openafs-sa-2013-001.patch --- openafs-1.6.1/debian/patches/openafs-sa-2013-001.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/openafs-sa-2013-001.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,107 @@ +Description: Hardening against buffer overflows +Origin: http://www.openafs.org/pages/security/openafs-sa-2013-001.patch +Author: Nickolai Zeldovich +Forwarded: not-needed + +--- a/src/libacl/aclprocs.c ++++ b/src/libacl/aclprocs.c +@@ -23,13 +23,13 @@ + #else + #include + #endif ++#include + #include + #include + #include + #include + #include + #include "acl.h" +- + #ifdef AFS_PTHREAD_ENV + #include + #include +@@ -251,7 +251,7 @@ + + 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 @@ + 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 @@ + 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); +--- a/src/libadmin/client/afs_clientAdmin.c ++++ b/src/libadmin/client/afs_clientAdmin.c +@@ -1542,7 +1542,7 @@ + */ + + 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 @@ + */ + + 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 + */ +--- a/src/venus/fs.c ++++ b/src/venus/fs.c +@@ -561,7 +561,7 @@ + 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 @@ + 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 @@ + 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 @@ + 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); diff -Nru openafs-1.6.1/debian/patches/openafs-sa-2013-002.patch openafs-1.6.1/debian/patches/openafs-sa-2013-002.patch --- openafs-1.6.1/debian/patches/openafs-sa-2013-002.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/openafs-sa-2013-002.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,16 @@ +Description: Avoid potential integer overflow +Origin: http://www.openafs.org/pages/security/openafs-sa-2013-002.patch +Author: Nickolai Zeldovich +Forwarded: not-needed + +--- a/src/ptserver/ptprocs.c ++++ b/src/ptserver/ptprocs.c +@@ -679,7 +679,7 @@ + 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; diff -Nru openafs-1.6.1/debian/patches/series openafs-1.6.1/debian/patches/series --- openafs-1.6.1/debian/patches/series 2012-03-29 00:32:49.000000000 +0000 +++ openafs-1.6.1/debian/patches/series 2013-07-24 02:34:20.000000000 +0000 @@ -1 +1,15 @@ debian-changes +openafs-sa-2013-001.patch +openafs-sa-2013-002.patch +0001-Add-rxkad-server-hook-function-to-decrypt-more-types.patch +0002-New-optional-rxkad-functionality-for-decypting-krb5-.patch +0003-Integrate-keytab-based-decryption-into-afsconf_Build.patch +0004-Derive-DES-fcrypt-session-key-from-other-key-types.patch +0005-Move-akimpersonate-to-libauth.patch +0006-Clean-up-akimpersonate-and-use-for-server-to-server.patch +0007-auth-Do-not-always-fallback-to-noauth.patch +0008-Avoid-calling-afsconf_GetLatestKey-directly.patch +0009-Reload-rxkad.keytab-on-CellServDB-modification.patch +0010-Add-support-for-deriving-DES-keys-to-klog.krb5.patch +0012-ubik-Fix-encryption-selection-in-ugen.patch +swap-libs.patch diff -Nru openafs-1.6.1/debian/patches/swap-libs.patch openafs-1.6.1/debian/patches/swap-libs.patch --- openafs-1.6.1/debian/patches/swap-libs.patch 1970-01-01 00:00:00.000000000 +0000 +++ openafs-1.6.1/debian/patches/swap-libs.patch 2013-07-24 02:34:20.000000000 +0000 @@ -0,0 +1,24 @@ +Author: Anders Kaseorg +Last-Updated: 2013-07-23 +Description: Reorder libs to resolve FTBFS +Forwarded: yes + +--- a/src/aklog/Makefile.in ++++ b/src/aklog/Makefile.in +@@ -24,13 +24,13 @@ + all: aklog asetkey klog + + aklog: ${OBJS} ${AFSLIBS} +- ${CC} -o $@ ${CFLAGS} ${OBJS} ${AKLIBS} ${AFSLIBS} ${XLIBS} ++ ${CC} -o $@ ${CFLAGS} ${OBJS} ${AFSLIBS} ${AKLIBS} ${XLIBS} + + asetkey: asetkey.o ${AFSLIBS} +- ${CC} -o $@ ${CFLAGS} asetkey.o ${AKLIBS} ${AFSLIBS} ${XLIBS} ++ ${CC} -o $@ ${CFLAGS} asetkey.o ${AFSLIBS} ${AKLIBS} ${XLIBS} + + klog: klog.o skipwrap.o ${AFSLIBS} +- ${CC} -o $@ ${CFLAGS} klog.o skipwrap.o ${AKLIBS} ${AFSLIBS} ${XLIBS} ++ ${CC} -o $@ ${CFLAGS} klog.o skipwrap.o ${AFSLIBS} ${AKLIBS} ${XLIBS} + + # + # Installation targets