Merge branch 'master' of ssh://moonshot.suchdamage.org:822/srv/git/moonshot
authorLuke Howard <lukeh@padl.com>
Sun, 2 Jan 2011 08:57:19 +0000 (19:57 +1100)
committerLuke Howard <lukeh@padl.com>
Sun, 2 Jan 2011 08:58:28 +0000 (19:58 +1100)
Reauth fixes

Conflicts:
shibboleth/opensaml2
shibboleth/sp

1  2 
cyrus-sasl
libradsec
mech_eap/release_oid.c
mech_eap/util.h
mech_eap/util_context.c
mech_eap/util_krb.c
mech_eap/util_mech.c
mech_eap/util_reauth.c

diff --cc cyrus-sasl
@@@ -1,1 -1,1 +1,1 @@@
--Subproject commit 2d5a0004454cee27bd0e4842404fd5d0f3e23ef2
++Subproject commit 755d9d20aadc1a140d01583b586f5a6d29c3a670
diff --cc libradsec
+++ b/libradsec
@@@ -1,1 -1,1 +1,1 @@@
--Subproject commit 88adb3a99af7ac04c5f07174acdd54fbf13fee01
++Subproject commit b07f9ade9bad2ec38d4dc9f6592f64dff2e1b120
index 947baa2,0000000..184dbab
mode 100644,000000..100644
--- /dev/null
@@@ -1,55 -1,0 +1,44 @@@
-     gss_OID internalizedOid = GSS_C_NO_OID;
-     *minor = 0;
-     if (gssEapInternalizeOid(*oid, &internalizedOid)) {
-         /* OID was internalized, so we can mark it as "freed" */
-         *oid = GSS_C_NO_OID;
-         return GSS_S_COMPLETE;
-     }
-     /* we don't know about this OID */
-     return GSS_S_CONTINUE_NEEDED;
 +/*
 + * Copyright (c) 2010, JANET(UK)
 + * 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.
 + *
 + * 3. Neither the name of JANET(UK) nor the names of its contributors
 + *    may be used to endorse or promote products derived from this software
 + *    without specific prior written permission.
 + *
 + * 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.
 + */
 +
 +/*
 + * Mark an internalized OID as not required to be released.
 + */
 +
 +#include "gssapiP_eap.h"
 +
 +OM_uint32
 +gss_internal_release_oid(OM_uint32 *minor,
 +                         gss_OID *oid)
 +{
++    return gssEapReleaseOid(minor, oid);
 +}
diff --cc mech_eap/util.h
index 7f2e7fe,0000000..49c7c91
mode 100644,000000..100644
--- /dev/null
@@@ -1,772 -1,0 +1,775 @@@
 +/*
 + * Copyright (c) 2010, JANET(UK)
 + * 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.
 + *
 + * 3. Neither the name of JANET(UK) nor the names of its contributors
 + *    may be used to endorse or promote products derived from this software
 + *    without specific prior written permission.
 + *
 + * 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.
 + */
 +/*
 + * Portions Copyright 2003-2010 Massachusetts Institute of Technology.
 + * All Rights Reserved.
 + *
 + * Export of this software from the United States of America may
 + *   require a specific license from the United States Government.
 + *   It is the responsibility of any person or organization contemplating
 + *   export to obtain such a license before exporting.
 + *
 + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 + * distribute this software and its documentation for any purpose and
 + * without fee is hereby granted, provided that the above copyright
 + * notice appear in all copies and that both that copyright notice and
 + * this permission notice appear in supporting documentation, and that
 + * the name of M.I.T. not be used in advertising or publicity pertaining
 + * to distribution of the software without specific, written prior
 + * permission.  Furthermore if you modify this software you must label
 + * your software as modified software and not distribute it in such a
 + * fashion that it might be confused with the original M.I.T. software.
 + * M.I.T. makes no representations about the suitability of
 + * this software for any purpose.  It is provided "as is" without express
 + * or implied warranty.
 + *
 + */
 +
 +/*
 + * Utility functions.
 + */
 +
 +#ifndef _UTIL_H_
 +#define _UTIL_H_ 1
 +
 +#include <sys/param.h>
 +#include <string.h>
 +#include <errno.h>
 +
 +#include <krb5.h>
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#ifndef MIN
 +#define MIN(_a,_b)  ((_a)<(_b)?(_a):(_b))
 +#endif
 +
 +/* util_buffer.c */
 +OM_uint32
 +makeStringBuffer(OM_uint32 *minor,
 +                 const char *string,
 +                 gss_buffer_t buffer);
 +
 +OM_uint32
 +bufferToString(OM_uint32 *minor,
 +               const gss_buffer_t buffer,
 +               char **pString);
 +
 +OM_uint32
 +duplicateBuffer(OM_uint32 *minor,
 +                const gss_buffer_t src,
 +                gss_buffer_t dst);
 +
 +static inline int
 +bufferEqual(const gss_buffer_t b1, const gss_buffer_t b2)
 +{
 +    return (b1->length == b2->length &&
 +            memcmp(b1->value, b2->value, b2->length) == 0);
 +}
 +
 +static inline int
 +bufferEqualString(const gss_buffer_t b1, const char *s)
 +{
 +    gss_buffer_desc b2;
 +
 +    b2.length = strlen(s);
 +    b2.value = (char *)s;
 +
 +    return bufferEqual(b1, &b2);
 +}
 +
 +/* util_cksum.c */
 +int
 +gssEapSign(krb5_context context,
 +           krb5_cksumtype type,
 +           size_t rrc,
 +#ifdef HAVE_HEIMDAL_VERSION
 +           krb5_crypto crypto,
 +#else
 +           krb5_keyblock *key,
 +#endif
 +           krb5_keyusage sign_usage,
 +           gss_iov_buffer_desc *iov,
 +           int iov_count);
 +
 +int
 +gssEapVerify(krb5_context context,
 +             krb5_cksumtype type,
 +             size_t rrc,
 +#ifdef HAVE_HEIMDAL_VERSION
 +             krb5_crypto crypto,
 +#else
 +             krb5_keyblock *key,
 +#endif
 +             krb5_keyusage sign_usage,
 +             gss_iov_buffer_desc *iov,
 +             int iov_count,
 +             int *valid);
 +
 +#if 0
 +OM_uint32
 +gssEapEncodeGssChannelBindings(OM_uint32 *minor,
 +                               gss_channel_bindings_t chanBindings,
 +                               gss_buffer_t encodedBindings);
 +#endif
 +
 +/* util_context.c */
 +#define EAP_EXPORT_CONTEXT_V1           1
 +
 +enum gss_eap_token_type {
 +    TOK_TYPE_NONE                    = 0x0000,  /* no token */
 +    TOK_TYPE_MIC                     = 0x0404,  /* RFC 4121 MIC token */
 +    TOK_TYPE_WRAP                    = 0x0504,  /* RFC 4121 wrap token */
 +    TOK_TYPE_EXPORT_NAME             = 0x0401,  /* RFC 2743 exported name */
 +    TOK_TYPE_EXPORT_NAME_COMPOSITE   = 0x0402,  /* exported composite name */
 +    TOK_TYPE_DELETE_CONTEXT          = 0x0405,  /* RFC 2743 delete context */
 +    TOK_TYPE_EAP_RESP                = 0x0601,  /* EAP response */
 +    TOK_TYPE_EAP_REQ                 = 0x0602,  /* EAP request */
 +    TOK_TYPE_EXT_REQ                 = 0x0603,  /* GSS EAP extensions request */
 +    TOK_TYPE_EXT_RESP                = 0x0604,  /* GSS EAP extensions response */
 +    TOK_TYPE_GSS_REAUTH              = 0x0605,  /* GSS EAP fast reauthentication token */
 +    TOK_TYPE_CONTEXT_ERR             = 0x0606,  /* context error */
 +};
 +
 +OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
 +OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
 +
 +OM_uint32
 +gssEapMakeToken(OM_uint32 *minor,
 +                gss_ctx_id_t ctx,
 +                const gss_buffer_t innerToken,
 +                enum gss_eap_token_type tokenType,
 +                gss_buffer_t outputToken);
 +
 +OM_uint32
 +gssEapVerifyToken(OM_uint32 *minor,
 +                  gss_ctx_id_t ctx,
 +                  const gss_buffer_t inputToken,
 +                  enum gss_eap_token_type *tokenType,
 +                  gss_buffer_t innerInputToken);
 +
 +OM_uint32
 +gssEapContextTime(OM_uint32 *minor,
 +                  gss_ctx_id_t context_handle,
 +                  OM_uint32 *time_rec);
 +
 +OM_uint32
 +gssEapDisplayName(OM_uint32 *minor,
 +                  gss_name_t name,
 +                  gss_buffer_t output_name_buffer,
 +                  gss_OID *output_name_type);
 +
 +/* util_cred.c */
 +OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred);
 +OM_uint32 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred);
 +
 +OM_uint32
 +gssEapAcquireCred(OM_uint32 *minor,
 +                  const gss_name_t desiredName,
 +                  const gss_buffer_t password,
 +                  OM_uint32 timeReq,
 +                  const gss_OID_set desiredMechs,
 +                  int cred_usage,
 +                  gss_cred_id_t *pCred,
 +                  gss_OID_set *pActualMechs,
 +                  OM_uint32 *timeRec);
 +
 +int gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech);
 +
 +/* util_crypt.c */
 +int
 +gssEapEncrypt(krb5_context context, int dce_style, size_t ec,
 +              size_t rrc,
 +#ifdef HAVE_HEIMDAL_VERSION
 +              krb5_crypto crypto,
 +#else
 +              krb5_keyblock *key,
 +#endif
 +              int usage,
 +              gss_iov_buffer_desc *iov, int iov_count);
 +
 +int
 +gssEapDecrypt(krb5_context context, int dce_style, size_t ec,
 +              size_t rrc,
 +#ifdef HAVE_HEIMDAL_VERSION
 +              krb5_crypto crypto,
 +#else
 +              krb5_keyblock *key,
 +#endif
 +              int usage,
 +              gss_iov_buffer_desc *iov, int iov_count);
 +
 +int
 +gssEapMapCryptoFlag(OM_uint32 type);
 +
 +gss_iov_buffer_t
 +gssEapLocateIov(gss_iov_buffer_desc *iov,
 +                int iov_count,
 +                OM_uint32 type);
 +
 +void
 +gssEapIovMessageLength(gss_iov_buffer_desc *iov,
 +                       int iov_count,
 +                       size_t *data_length,
 +                       size_t *assoc_data_length);
 +
 +void
 +gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count);
 +
 +int
 +gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count);
 +
 +int
 +gssEapAllocIov(gss_iov_buffer_t iov, size_t size);
 +
 +OM_uint32
 +gssEapDeriveRfc3961Key(OM_uint32 *minor,
 +                       const unsigned char *key,
 +                       size_t keyLength,
 +                       krb5_enctype enctype,
 +                       krb5_keyblock *pKey);
 +
 +/* util_exts.c */
 +#define EXT_FLAG_CRITICAL               0x80000000  /* critical, wire flag */
 +#define EXT_FLAG_VERIFIED               0x40000000  /* verified, API flag */
 +
 +#define EXT_TYPE_GSS_CHANNEL_BINDINGS   0x00000000
 +#define EXT_TYPE_REAUTH_CREDS           0x00000001
 +#define EXT_TYPE_MASK                   (~(EXT_FLAG_CRITICAL | EXT_FLAG_VERIFIED))
 +
 +struct gss_eap_extension_provider {
 +    OM_uint32 type;
 +    int critical; /* client */
 +    int required; /* server */
 +    OM_uint32 (*make)(OM_uint32 *,
 +                      gss_cred_id_t,
 +                      gss_ctx_id_t,
 +                      gss_channel_bindings_t,
 +                      gss_buffer_t);
 +    OM_uint32 (*verify)(OM_uint32 *,
 +                        gss_cred_id_t,
 +                        gss_ctx_id_t,
 +                        gss_channel_bindings_t,
 +                        const gss_buffer_t);
 +};
 +
 +OM_uint32
 +gssEapMakeExtensions(OM_uint32 *minor,
 +                     gss_cred_id_t cred,
 +                     gss_ctx_id_t ctx,
 +                     gss_channel_bindings_t chanBindings,
 +                     gss_buffer_t buffer);
 +
 +OM_uint32
 +gssEapVerifyExtensions(OM_uint32 *minor,
 +                       gss_cred_id_t cred,
 +                       gss_ctx_id_t ctx,
 +                       gss_channel_bindings_t chanBindings,
 +                       const gss_buffer_t buffer);
 +
 +/* util_krb.c */
 +#ifdef HAVE_HEIMDAL_VERSION
 +
 +#define KRB_TIME_FOREVER        ((time_t)~0L)
 +
 +#define KRB_KEY_TYPE(key)       ((key)->keytype)
 +#define KRB_KEY_DATA(key)       ((key)->keyvalue.data)
 +#define KRB_KEY_LENGTH(key)     ((key)->keyvalue.length)
 +
 +#define KRB_PRINC_LENGTH(princ) ((princ)->name.name_string.len)
 +#define KRB_PRINC_TYPE(princ)   ((princ)->name.name_type)
 +#define KRB_PRINC_NAME(princ)   ((princ)->name.name_string.val)
 +#define KRB_PRINC_REALM(princ)  ((princ)->realm)
 +
 +#define KRB_KT_ENT_KEYBLOCK(e)  (&(e)->keyblock)
 +#define KRB_KT_ENT_FREE(c, e)   krb5_kt_free_entry((c), (e))
 +
 +#define KRB_CRYPTO_CONTEXT(ctx) (krbCrypto)
 +
 +#else
 +
 +#define KRB_TIME_FOREVER        KRB5_INT32_MAX
 +
 +#define KRB_KEY_TYPE(key)       ((key)->enctype)
 +#define KRB_KEY_DATA(key)       ((key)->contents)
 +#define KRB_KEY_LENGTH(key)     ((key)->length)
 +
 +#define KRB_PRINC_LENGTH(princ) (krb5_princ_size(NULL, (princ)))
 +#define KRB_PRINC_TYPE(princ)   (krb5_princ_type(NULL, (princ)))
 +#define KRB_PRINC_NAME(princ)   (krb5_princ_name(NULL, (princ)))
 +#define KRB_PRINC_REALM(princ)  (krb5_princ_realm(NULL, (princ)))
 +
 +#define KRB_KT_ENT_KEYBLOCK(e)  (&(e)->key)
 +#define KRB_KT_ENT_FREE(c, e)   krb5_free_keytab_entry_contents((c), (e))
 +
 +#define KRB_CRYPTO_CONTEXT(ctx) (&(ctx)->rfc3961Key)
 +
 +#endif /* HAVE_HEIMDAL_VERSION */
 +
 +#define KRB_KEY_INIT(key)       do {        \
 +        KRB_KEY_TYPE(key) = ENCTYPE_NULL;   \
 +        KRB_KEY_DATA(key) = NULL;           \
 +        KRB_KEY_LENGTH(key) = 0;            \
 +    } while (0)
 +
 +#ifdef HAVE_HEIMDAL_VERSION
 +#define GSS_IOV_BUFFER_FLAG_ALLOCATE    GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE
 +#define GSS_IOV_BUFFER_FLAG_ALLOCATED   GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED
 +
 +#define GSS_S_CRED_UNAVAIL              GSS_S_FAILURE
 +#endif
 +
 +#define GSSEAP_KRB_INIT(ctx) do {                   \
 +        OM_uint32 tmpMajor;                         \
 +                                                    \
 +        tmpMajor  = gssEapKerberosInit(minor, ctx); \
 +        if (GSS_ERROR(tmpMajor)) {                  \
 +            return tmpMajor;                        \
 +        }                                           \
 +    } while (0)
 +
 +OM_uint32
 +gssEapKerberosInit(OM_uint32 *minor, krb5_context *context);
 +
 +OM_uint32
 +rfc3961ChecksumTypeForKey(OM_uint32 *minor,
 +                          krb5_keyblock *key,
 +                          krb5_cksumtype *cksumtype);
 +
 +krb5_const_principal
 +krbAnonymousPrincipal(void);
 +
 +krb5_error_code
 +krbCryptoLength(krb5_context krbContext,
 +#ifdef HAVE_HEIMDAL_VERSION
 +                krb5_crypto krbCrypto,
 +#else
 +                krb5_keyblock *key,
 +#endif
 +                int type,
 +                size_t *length);
 +
 +krb5_error_code
 +krbPaddingLength(krb5_context krbContext,
 +#ifdef HAVE_HEIMDAL_VERSION
 +                 krb5_crypto krbCrypto,
 +#else
 +                 krb5_keyblock *key,
 +#endif
 +                 size_t dataLength,
 +                 size_t *padLength);
 +
 +krb5_error_code
 +krbBlockSize(krb5_context krbContext,
 +#ifdef HAVE_HEIMDAL_VERSION
 +                 krb5_crypto krbCrypto,
 +#else
 +                 krb5_keyblock *key,
 +#endif
 +                 size_t *blockSize);
 +
 +krb5_error_code
 +krbEnctypeToString(krb5_context krbContext,
 +                   krb5_enctype enctype,
 +                   const char *prefix,
 +                   gss_buffer_t string);
 +
 +krb5_error_code
 +krbMakeAuthDataKdcIssued(krb5_context context,
 +                         const krb5_keyblock *key,
 +                         krb5_const_principal issuer,
 +#ifdef HAVE_HEIMDAL_VERSION
 +                         const AuthorizationData *authdata,
 +                         AuthorizationData *adKdcIssued
 +#else
 +                         krb5_authdata *const *authdata,
 +                         krb5_authdata ***adKdcIssued
 +#endif
 +                         );
 +
 +krb5_error_code
 +krbMakeCred(krb5_context context,
 +            krb5_auth_context authcontext,
 +            krb5_creds *creds,
 +            krb5_data *data);
 +
 +/* util_lucid.c */
 +OM_uint32
 +gssEapExportLucidSecContext(OM_uint32 *minor,
 +                            gss_ctx_id_t ctx,
 +                            const gss_OID desiredObject,
 +                            gss_buffer_set_t *data_set);
 +
 +/* util_mech.c */
 +extern gss_OID GSS_EAP_MECHANISM;
 +
 +int
 +gssEapInternalizeOid(const gss_OID oid,
 +                     gss_OID *const pInternalizedOid);
 +
 +OM_uint32
++gssEapReleaseOid(OM_uint32 *minor, gss_OID *oid);
++
++OM_uint32
 +gssEapDefaultMech(OM_uint32 *minor,
 +                  gss_OID *oid);
 +
 +OM_uint32
 +gssEapIndicateMechs(OM_uint32 *minor,
 +                    gss_OID_set *mechs);
 +
 +OM_uint32
 +gssEapEnctypeToOid(OM_uint32 *minor,
 +                   krb5_enctype enctype,
 +                   gss_OID *pOid);
 +
 +OM_uint32
 +gssEapOidToEnctype(OM_uint32 *minor,
 +                   const gss_OID oid,
 +                   krb5_enctype *enctype);
 +
 +int
 +gssEapIsMechanismOid(const gss_OID oid);
 +
 +int
 +gssEapIsConcreteMechanismOid(const gss_OID oid);
 +
 +OM_uint32
 +gssEapValidateMechs(OM_uint32 *minor,
 +                   const gss_OID_set mechs);
 +
 +gss_buffer_t
 +gssEapOidToSaslName(const gss_OID oid);
 +
 +gss_OID
 +gssEapSaslNameToOid(const gss_buffer_t name);
 +
 +/* util_name.c */
 +#define EXPORT_NAME_FLAG_OID        0x1
 +#define EXPORT_NAME_FLAG_COMPOSITE  0x2
 +
 +OM_uint32 gssEapAllocName(OM_uint32 *minor, gss_name_t *pName);
 +OM_uint32 gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName);
 +OM_uint32 gssEapExportName(OM_uint32 *minor,
 +                           const gss_name_t name,
 +                           gss_buffer_t exportedName);
 +OM_uint32 gssEapExportNameInternal(OM_uint32 *minor,
 +                                   const gss_name_t name,
 +                                   gss_buffer_t exportedName,
 +                                   unsigned int flags);
 +OM_uint32 gssEapImportName(OM_uint32 *minor,
 +                           const gss_buffer_t input_name_buffer,
 +                           gss_OID input_name_type,
 +                           gss_name_t *output_name);
 +OM_uint32 gssEapImportNameInternal(OM_uint32 *minor,
 +                                   const gss_buffer_t input_name_buffer,
 +                                   gss_name_t *output_name,
 +                                   unsigned int flags);
 +OM_uint32
 +gssEapDuplicateName(OM_uint32 *minor,
 +                    const gss_name_t input_name,
 +                    gss_name_t *dest_name);
 +
 +/* util_oid.c */
 +OM_uint32
 +composeOid(OM_uint32 *minor_status,
 +           const char *prefix,
 +           size_t prefix_len,
 +           int suffix,
 +           gss_OID_desc *oid);
 +
 +OM_uint32
 +decomposeOid(OM_uint32 *minor_status,
 +             const char *prefix,
 +             size_t prefix_len,
 +             gss_OID_desc *oid,
 +             int *suffix) ;
 +
 +OM_uint32
 +duplicateOid(OM_uint32 *minor_status,
 +             const gss_OID_desc * const oid,
 +             gss_OID *new_oid);
 +
 +OM_uint32
 +duplicateOidSet(OM_uint32 *minor,
 +                const gss_OID_set src,
 +                gss_OID_set *dst);
 +
 +static inline int
 +oidEqual(const gss_OID_desc *o1, const gss_OID_desc *o2)
 +{
 +    if (o1 == GSS_C_NO_OID)
 +        return (o2 == GSS_C_NO_OID);
 +    else if (o2 == GSS_C_NO_OID)
 +        return (o1 == GSS_C_NO_OID);
 +    else
 +        return (o1->length == o2->length &&
 +                memcmp(o1->elements, o2->elements, o1->length) == 0);
 +}
 +
 +/* util_ordering.c */
 +OM_uint32
 +sequenceInternalize(OM_uint32 *minor,
 +                    void **vqueue,
 +                    unsigned char **buf,
 +                    size_t *lenremain);
 +
 +OM_uint32
 +sequenceExternalize(OM_uint32 *minor,
 +                    void *vqueue,
 +                    unsigned char **buf,
 +                    size_t *lenremain);
 +
 +size_t
 +sequenceSize(void *vqueue);
 +
 +OM_uint32
 +sequenceFree(OM_uint32 *minor, void **vqueue);
 +
 +OM_uint32
 +sequenceCheck(OM_uint32 *minor, void **vqueue, uint64_t seqnum);
 +
 +OM_uint32
 +sequenceInit(OM_uint32 *minor, void **vqueue, uint64_t seqnum,
 +             int do_replay, int do_sequence, int wide_nums);
 +
 +/* util_token.c */
 +size_t
 +tokenSize(const gss_OID_desc *mech, size_t body_size);
 +
 +void
 +makeTokenHeader(const gss_OID_desc *mech,
 +                size_t body_size,
 +                unsigned char **buf,
 +                enum gss_eap_token_type tok_type);
 +
 +OM_uint32
 +verifyTokenHeader(OM_uint32 *minor,
 +                  gss_OID mech,
 +                  size_t *body_size,
 +                  unsigned char **buf_in,
 +                  size_t toksize_in,
 +                  enum gss_eap_token_type *ret_tok_type);
 +
 +/* Helper macros */
 +
 +#define GSSEAP_CALLOC                   calloc
 +#define GSSEAP_MALLOC                   malloc
 +#define GSSEAP_FREE                     free
 +#define GSSEAP_REALLOC                  realloc
 +
 +#define GSSEAP_NOT_IMPLEMENTED          do {            \
 +        assert(0 && "not implemented");                 \
 +        *minor = ENOSYS;                                \
 +        return GSS_S_FAILURE;                           \
 +    } while (0)
 +
 +#include <pthread.h>
 +
 +#define GSSEAP_MUTEX                    pthread_mutex_t
 +#define GSSEAP_MUTEX_INITIALIZER        PTHREAD_MUTEX_INITIALIZER
 +
 +#define GSSEAP_MUTEX_INIT(m)            pthread_mutex_init((m), NULL)
 +#define GSSEAP_MUTEX_DESTROY(m)         pthread_mutex_destroy((m))
 +#define GSSEAP_MUTEX_LOCK(m)            pthread_mutex_lock((m))
 +#define GSSEAP_MUTEX_UNLOCK(m)          pthread_mutex_unlock((m))
 +
 +#define GSSEAP_THREAD_KEY               pthread_key_t
 +#define GSSEAP_KEY_CREATE(k, d)         pthread_key_create((k), (d))
 +#define GSSEAP_GETSPECIFIC(k)           pthread_getspecific((k))
 +#define GSSEAP_SETSPECIFIC(k, d)        pthread_setspecific((k), (d))
 +
 +#define GSSEAP_THREAD_ONCE              pthread_once_t
 +#define GSSEAP_ONCE(o, i)               pthread_once((o), (i))
 +#define GSSEAP_ONCE_INITIALIZER         PTHREAD_ONCE_INIT
 +
 +/* Helper functions */
 +static inline void
 +store_uint16_be(uint16_t val, void *vp)
 +{
 +    unsigned char *p = (unsigned char *)vp;
 +
 +    p[0] = (val >>  8) & 0xff;
 +    p[1] = (val      ) & 0xff;
 +}
 +
 +static inline uint16_t
 +load_uint16_be(const void *cvp)
 +{
 +    const unsigned char *p = (const unsigned char *)cvp;
 +
 +    return (p[1] | (p[0] << 8));
 +}
 +
 +static inline void
 +store_uint32_be(uint32_t val, void *vp)
 +{
 +    unsigned char *p = (unsigned char *)vp;
 +
 +    p[0] = (val >> 24) & 0xff;
 +    p[1] = (val >> 16) & 0xff;
 +    p[2] = (val >>  8) & 0xff;
 +    p[3] = (val      ) & 0xff;
 +}
 +
 +static inline uint32_t
 +load_uint32_be(const void *cvp)
 +{
 +    const unsigned char *p = (const unsigned char *)cvp;
 +
 +    return (p[3] | (p[2] << 8)
 +            | ((uint32_t) p[1] << 16)
 +            | ((uint32_t) p[0] << 24));
 +}
 +
 +static inline void
 +store_uint64_be(uint64_t val, void *vp)
 +{
 +    unsigned char *p = (unsigned char *)vp;
 +
 +    p[0] = (unsigned char)((val >> 56) & 0xff);
 +    p[1] = (unsigned char)((val >> 48) & 0xff);
 +    p[2] = (unsigned char)((val >> 40) & 0xff);
 +    p[3] = (unsigned char)((val >> 32) & 0xff);
 +    p[4] = (unsigned char)((val >> 24) & 0xff);
 +    p[5] = (unsigned char)((val >> 16) & 0xff);
 +    p[6] = (unsigned char)((val >>  8) & 0xff);
 +    p[7] = (unsigned char)((val      ) & 0xff);
 +}
 +
 +static inline uint64_t
 +load_uint64_be(const void *cvp)
 +{
 +    const unsigned char *p = (const unsigned char *)cvp;
 +
 +    return ((uint64_t)load_uint32_be(p) << 32) | load_uint32_be(p + 4);
 +}
 +
 +static inline unsigned char *
 +store_buffer(gss_buffer_t buffer, void *vp, int wide_nums)
 +{
 +    unsigned char *p = (unsigned char *)vp;
 +
 +    if (wide_nums) {
 +        store_uint64_be(buffer->length, p);
 +        p += 8;
 +    } else {
 +        store_uint32_be(buffer->length, p);
 +        p += 4;
 +    }
 +
 +    if (buffer->value != NULL) {
 +        memcpy(p, buffer->value, buffer->length);
 +        p += buffer->length;
 +    }
 +
 +    return p;
 +}
 +
 +static inline unsigned char *
 +load_buffer(const void *cvp, size_t length, gss_buffer_t buffer)
 +{
 +    buffer->length = 0;
 +    buffer->value = GSSEAP_MALLOC(length);
 +    if (buffer->value == NULL)
 +        return NULL;
 +    buffer->length = length;
 +    memcpy(buffer->value, cvp, length);
 +    return (unsigned char *)cvp + length;
 +}
 +
 +static inline unsigned char *
 +store_oid(gss_OID oid, void *vp)
 +{
 +    gss_buffer_desc buf;
 +
 +    if (oid != GSS_C_NO_OID) {
 +        buf.length = oid->length;
 +        buf.value = oid->elements;
 +    } else {
 +        buf.length = 0;
 +        buf.value = NULL;
 +    }
 +
 +    return store_buffer(&buf, vp, FALSE);
 +}
 +
 +static inline void
 +krbDataToGssBuffer(krb5_data *data, gss_buffer_t buffer)
 +{
 +    buffer->value = (void *)data->data;
 +    buffer->length = data->length;
 +}
 +
 +static inline void
 +krbPrincComponentToGssBuffer(krb5_principal krbPrinc,
 +                             int index, gss_buffer_t buffer)
 +{
 +#ifdef HAVE_HEIMDAL_VERSION
 +    buffer->value = (void *)KRB_PRINC_NAME(krbPrinc)[index];
 +    buffer->length = strlen((char *)buffer->value);
 +#else
 +    buffer->value = (void *)krb5_princ_component(NULL, krbPrinc, index)->data;
 +    buffer->length = krb5_princ_component(NULL, krbPrinc, index)->length;
 +#endif /* HAVE_HEIMDAL_VERSION */
 +}
 +
 +static inline void
 +krbPrincRealmToGssBuffer(krb5_principal krbPrinc, gss_buffer_t buffer)
 +{
 +#ifdef HAVE_HEIMDAL_VERSION
 +    buffer->value = (void *)KRB_PRINC_REALM(krbPrinc);
 +    buffer->length = strlen((char *)buffer->value);
 +#else
 +    krbDataToGssBuffer(KRB_PRINC_REALM(krbPrinc), buffer);
 +#endif
 +}
 +
 +static inline void
 +gssBufferToKrbData(gss_buffer_t buffer, krb5_data *data)
 +{
 +    data->data = (char *)buffer->value;
 +    data->length = buffer->length;
 +}
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#include "util_attr.h"
 +#ifdef GSSEAP_ENABLE_REAUTH
 +#include "util_reauth.h"
 +#endif
 +
 +#endif /* _UTIL_H_ */
index e54203f,0000000..0020ef6
mode 100644,000000..100644
--- /dev/null
@@@ -1,234 -1,0 +1,234 @@@
-     gss_release_oid(&tmpMinor, &ctx->mechanismUsed);
 +/*
 + * Copyright (c) 2010, JANET(UK)
 + * 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.
 + *
 + * 3. Neither the name of JANET(UK) nor the names of its contributors
 + *    may be used to endorse or promote products derived from this software
 + *    without specific prior written permission.
 + *
 + * 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.
 + */
 +
 +/*
 + * Utility routines for context handles.
 + */
 +
 +#include "gssapiP_eap.h"
 +
 +OM_uint32
 +gssEapAllocContext(OM_uint32 *minor,
 +                   gss_ctx_id_t *pCtx)
 +{
 +    OM_uint32 tmpMinor;
 +    gss_ctx_id_t ctx;
 +
 +    assert(*pCtx == GSS_C_NO_CONTEXT);
 +
 +    ctx = (gss_ctx_id_t)GSSEAP_CALLOC(1, sizeof(*ctx));
 +    if (ctx == NULL) {
 +        *minor = ENOMEM;
 +        return GSS_S_FAILURE;
 +    }
 +
 +    if (GSSEAP_MUTEX_INIT(&ctx->mutex) != 0) {
 +        *minor = errno;
 +        gssEapReleaseContext(&tmpMinor, &ctx);
 +        return GSS_S_FAILURE;
 +    }
 +
 +    ctx->state = GSSEAP_STATE_IDENTITY;
 +
 +    /*
 +     * Integrity, confidentiality, sequencing and replay detection are
 +     * always available.  Regardless of what flags are requested in
 +     * GSS_Init_sec_context, implementations MUST set the flag corresponding
 +     * to these services in the output of GSS_Init_sec_context and
 +     * GSS_Accept_sec_context.
 +    */
 +    ctx->gssFlags = GSS_C_TRANS_FLAG    |   /* exporting contexts */
 +                    GSS_C_INTEG_FLAG    |   /* integrity */
 +                    GSS_C_CONF_FLAG     |   /* confidentiality */
 +                    GSS_C_SEQUENCE_FLAG |   /* sequencing */
 +                    GSS_C_REPLAY_FLAG;      /* replay detection */
 +
 +    *pCtx = ctx;
 +
 +    return GSS_S_COMPLETE;
 +}
 +
 +static void
 +releaseInitiatorContext(struct gss_eap_initiator_ctx *ctx)
 +{
 +    eap_peer_sm_deinit(ctx->eap);
 +}
 +
 +static void
 +releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx)
 +{
 +    OM_uint32 tmpMinor;
 +
 +    if (ctx->radConn != NULL)
 +        rs_conn_destroy(ctx->radConn);
 +    if (ctx->radContext != NULL)
 +        rs_context_destroy(ctx->radContext);
 +    if (ctx->radServer != NULL)
 +        GSSEAP_FREE(ctx->radServer);
 +    gss_release_buffer(&tmpMinor, &ctx->state);
 +    if (ctx->vps != NULL)
 +        gssEapRadiusFreeAvps(&tmpMinor, &ctx->vps);
 +}
 +
 +OM_uint32
 +gssEapReleaseContext(OM_uint32 *minor,
 +                     gss_ctx_id_t *pCtx)
 +{
 +    OM_uint32 tmpMinor;
 +    gss_ctx_id_t ctx = *pCtx;
 +    krb5_context krbContext = NULL;
 +
 +    if (ctx == GSS_C_NO_CONTEXT) {
 +        return GSS_S_COMPLETE;
 +    }
 +
 +    gssEapKerberosInit(&tmpMinor, &krbContext);
 +
 +#ifdef GSSEAP_ENABLE_REAUTH
 +    if (ctx->flags & CTX_FLAG_KRB_REAUTH) {
 +        gssDeleteSecContext(&tmpMinor, &ctx->kerberosCtx, GSS_C_NO_BUFFER);
 +    } else
 +#endif
 +    if (CTX_IS_INITIATOR(ctx)) {
 +        releaseInitiatorContext(&ctx->initiatorCtx);
 +    } else {
 +        releaseAcceptorContext(&ctx->acceptorCtx);
 +    }
 +
 +    krb5_free_keyblock_contents(krbContext, &ctx->rfc3961Key);
 +    gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
 +    gssEapReleaseName(&tmpMinor, &ctx->acceptorName);
++    gssEapReleaseOid(&tmpMinor, &ctx->mechanismUsed);
 +    sequenceFree(&tmpMinor, &ctx->seqState);
 +    gssEapReleaseCred(&tmpMinor, &ctx->defaultCred);
 +
 +    GSSEAP_MUTEX_DESTROY(&ctx->mutex);
 +
 +    memset(ctx, 0, sizeof(*ctx));
 +    GSSEAP_FREE(ctx);
 +    *pCtx = GSS_C_NO_CONTEXT;
 +
 +    *minor = 0;
 +    return GSS_S_COMPLETE;
 +}
 +
 +OM_uint32
 +gssEapMakeToken(OM_uint32 *minor,
 +                gss_ctx_id_t ctx,
 +                const gss_buffer_t innerToken,
 +                enum gss_eap_token_type tokenType,
 +                gss_buffer_t outputToken)
 +{
 +    unsigned char *p;
 +
 +    outputToken->length = tokenSize(ctx->mechanismUsed, innerToken->length);
 +    outputToken->value = GSSEAP_MALLOC(outputToken->length);
 +    if (outputToken->value == NULL) {
 +        *minor = ENOMEM;
 +        return GSS_S_FAILURE;
 +    }
 +
 +    p = (unsigned char *)outputToken->value;
 +    makeTokenHeader(ctx->mechanismUsed, innerToken->length, &p, tokenType);
 +    memcpy(p, innerToken->value, innerToken->length);
 +
 +    *minor = 0;
 +    return GSS_S_COMPLETE;
 +}
 +
 +OM_uint32
 +gssEapVerifyToken(OM_uint32 *minor,
 +                  gss_ctx_id_t ctx,
 +                  const gss_buffer_t inputToken,
 +                  enum gss_eap_token_type *actualToken,
 +                  gss_buffer_t innerInputToken)
 +{
 +    OM_uint32 major;
 +    size_t bodySize;
 +    unsigned char *p = (unsigned char *)inputToken->value;
 +    gss_OID_desc oidBuf;
 +    gss_OID oid;
 +
 +    if (ctx->mechanismUsed != GSS_C_NO_OID) {
 +        oid = ctx->mechanismUsed;
 +    } else {
 +        oidBuf.elements = NULL;
 +        oidBuf.length = 0;
 +        oid = &oidBuf;
 +    }
 +
 +    major = verifyTokenHeader(minor, oid, &bodySize, &p,
 +                              inputToken->length, actualToken);
 +    if (GSS_ERROR(major))
 +        return major;
 +
 +    if (ctx->mechanismUsed == GSS_C_NO_OID) {
 +        if (!gssEapIsConcreteMechanismOid(oid)) {
 +            *minor = GSSEAP_WRONG_MECH;
 +            return GSS_S_BAD_MECH;
 +        }
 +
 +        if (!gssEapInternalizeOid(oid, &ctx->mechanismUsed)) {
 +            major = duplicateOid(minor, oid, &ctx->mechanismUsed);
 +            if (GSS_ERROR(major))
 +                return major;
 +        }
 +    }
 +
 +    innerInputToken->length = bodySize;
 +    innerInputToken->value = p;
 +
 +    *minor = 0;
 +    return GSS_S_COMPLETE;
 +}
 +
 +OM_uint32
 +gssEapContextTime(OM_uint32 *minor,
 +                  gss_ctx_id_t context_handle,
 +                  OM_uint32 *time_rec)
 +{
 +    if (context_handle->expiryTime == 0) {
 +        *time_rec = GSS_C_INDEFINITE;
 +    } else {
 +        time_t now, lifetime;
 +
 +        time(&now);
 +        lifetime = context_handle->expiryTime - now;
 +        if (lifetime <= 0) {
 +            *time_rec = 0;
 +            return GSS_S_CONTEXT_EXPIRED;
 +        }
 +        *time_rec = lifetime;
 +    }
 +
 +    return GSS_S_COMPLETE;
 +}
index e96f5e6,0000000..7143685
mode 100644,000000..100644
--- /dev/null
@@@ -1,585 -1,0 +1,583 @@@
-     unsigned char *buf = NULL;
-     size_t buf_size, len;
 +/*
 + * Copyright (c) 2010, JANET(UK)
 + * 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.
 + *
 + * 3. Neither the name of JANET(UK) nor the names of its contributors
 + *    may be used to endorse or promote products derived from this software
 + *    without specific prior written permission.
 + *
 + * 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.
 + */
 +
 +/*
 + * Kerberos 5 helpers.
 + */
 +
 +#include "gssapiP_eap.h"
 +
 +static GSSEAP_THREAD_ONCE krbContextKeyOnce = GSSEAP_ONCE_INITIALIZER;
 +static GSSEAP_THREAD_KEY krbContextKey;
 +
 +static void
 +destroyKrbContext(void *arg)
 +{
 +    krb5_context context = (krb5_context)arg;
 +
 +    if (context != NULL)
 +        krb5_free_context(context);
 +}
 +
 +static void
 +createKrbContextKey(void)
 +{
 +    GSSEAP_KEY_CREATE(&krbContextKey, destroyKrbContext);
 +}
 +
 +OM_uint32
 +gssEapKerberosInit(OM_uint32 *minor, krb5_context *context)
 +{
 +    *minor = 0;
 +
 +    GSSEAP_ONCE(&krbContextKeyOnce, createKrbContextKey);
 +
 +    *context = GSSEAP_GETSPECIFIC(krbContextKey);
 +    if (*context == NULL) {
 +        *minor = krb5_init_context(context);
 +        if (*minor == 0) {
 +            if (GSSEAP_SETSPECIFIC(krbContextKey, *context) != 0) {
 +                *minor = errno;
 +                krb5_free_context(*context);
 +                *context = NULL;
 +            }
 +        }
 +    }
 +
 +    return *minor == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
 +}
 +
 +/*
 + * Derive a key K for RFC 4121 use by using the following
 + * derivation function (based on RFC 4402);
 + *
 + * KMSK = random-to-key(MSK)
 + * Tn = pseudo-random(KMSK, n || "rfc4121-gss-eap")
 + * L = output key size
 + * K = truncate(L, T1 || T2 || .. || Tn)
 + */
 +OM_uint32
 +gssEapDeriveRfc3961Key(OM_uint32 *minor,
 +                       const unsigned char *inputKey,
 +                       size_t inputKeyLength,
 +                       krb5_enctype encryptionType,
 +                       krb5_keyblock *pKey)
 +{
 +    krb5_context krbContext;
 +#ifndef HAVE_HEIMDAL_VERSION
 +    krb5_data data;
 +#endif
 +    krb5_data ns, t, prfOut;
 +    krb5_keyblock kd;
 +    krb5_error_code code;
 +    size_t randomLength, keyLength, prfLength;
 +    unsigned char constant[4 + sizeof("rfc4121-gss-eap") - 1], *p;
 +    ssize_t i, remain;
 +
 +    assert(encryptionType != ENCTYPE_NULL);
 +
 +    memset(pKey, 0, sizeof(*pKey));
 +
 +    GSSEAP_KRB_INIT(&krbContext);
 +
 +    KRB_KEY_INIT(&kd);
 +    KRB_KEY_TYPE(&kd) = encryptionType;
 +
 +    t.data = NULL;
 +    t.length = 0;
 +
 +    prfOut.data = NULL;
 +    prfOut.length = 0;
 +
 +    code = krb5_c_keylengths(krbContext, encryptionType,
 +                             &randomLength, &keyLength);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    KRB_KEY_DATA(&kd) = GSSEAP_MALLOC(keyLength);
 +    if (KRB_KEY_DATA(&kd) == NULL) {
 +        code = ENOMEM;
 +        goto cleanup;
 +    }
 +    KRB_KEY_LENGTH(&kd) = keyLength;
 +
 +    /* Convert MSK into a Kerberos key */
 +#ifdef HAVE_HEIMDAL_VERSION
 +    code = krb5_random_to_key(krbContext, encryptionType, inputKey,
 +                              MIN(inputKeyLength, randomLength), &kd);
 +#else
 +    data.length = MIN(inputKeyLength, randomLength);
 +    data.data = (char *)inputKey;
 +
 +    code = krb5_c_random_to_key(krbContext, encryptionType, &data, &kd);
 +#endif
 +    if (code != 0)
 +        goto cleanup;
 +
 +    memset(&constant[0], 0, 4);
 +    memcpy(&constant[4], "rfc4121-gss-eap", sizeof("rfc4121-gss-eap") - 1);
 +
 +    ns.length = sizeof(constant);
 +    ns.data = (char *)constant;
 +
 +    /* Plug derivation constant and key into PRF */
 +    code = krb5_c_prf_length(krbContext, encryptionType, &prfLength);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    t.length = prfLength;
 +    t.data = GSSEAP_MALLOC(t.length);
 +    if (t.data == NULL) {
 +        code = ENOMEM;
 +        goto cleanup;
 +    }
 +
 +    prfOut.length = randomLength;
 +    prfOut.data = GSSEAP_MALLOC(prfOut.length);
 +    if (prfOut.data == NULL) {
 +        code = ENOMEM;
 +        goto cleanup;
 +    }
 +
 +    for (i = 0, p = (unsigned char *)prfOut.data, remain = randomLength;
 +         remain > 0;
 +         p += t.length, remain -= t.length, i++)
 +    {
 +        store_uint32_be(i, ns.data);
 +
 +        code = krb5_c_prf(krbContext, &kd, &ns, &t);
 +        if (code != 0)
 +            goto cleanup;
 +
 +        memcpy(p, t.data, MIN(t.length, remain));
 +     }
 +
 +    /* Finally, convert PRF output into a new key which we will return */
 +#ifdef HAVE_HEIMDAL_VERSION
 +    code = krb5_random_to_key(krbContext, encryptionType,
 +                              prfOut.data, prfOut.length, &kd);
 +#else
 +    code = krb5_c_random_to_key(krbContext, encryptionType, &prfOut, &kd);
 +#endif
 +    if (code != 0)
 +        goto cleanup;
 +
 +    *pKey = kd;
 +    KRB_KEY_DATA(&kd) = NULL;
 +
 +cleanup:
 +    if (KRB_KEY_DATA(&kd) != NULL) {
 +        memset(KRB_KEY_DATA(&kd), 0, KRB_KEY_LENGTH(&kd));
 +        GSSEAP_FREE(KRB_KEY_DATA(&kd));
 +    }
 +    if (t.data != NULL) {
 +        memset(t.data, 0, t.length);
 +        GSSEAP_FREE(t.data);
 +    }
 +    if (prfOut.data != NULL) {
 +        memset(prfOut.data, 0, prfOut.length);
 +        GSSEAP_FREE(prfOut.data);
 +    }
 +    *minor = code;
 +    return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
 +}
 +
 +#ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
 +extern krb5_error_code
 +krb5int_c_mandatory_cksumtype(krb5_context, krb5_enctype, krb5_cksumtype *);
 +#endif
 +
 +OM_uint32
 +rfc3961ChecksumTypeForKey(OM_uint32 *minor,
 +                          krb5_keyblock *key,
 +                          krb5_cksumtype *cksumtype)
 +{
 +    krb5_context krbContext;
 +#ifndef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
 +    krb5_data data;
 +    krb5_checksum cksum;
 +#endif
 +
 +    GSSEAP_KRB_INIT(&krbContext);
 +
 +#ifdef HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE
 +    *minor = krb5int_c_mandatory_cksumtype(krbContext, KRB_KEY_TYPE(key),
 +                                           cksumtype);
 +    if (*minor != 0)
 +        return GSS_S_FAILURE;
 +#else
 +    data.length = 0;
 +    data.data = NULL;
 +
 +    memset(&cksum, 0, sizeof(cksum));
 +
 +    /*
 +     * This is a complete hack but it's the only way to work with
 +     * MIT Kerberos pre-1.9 without using private API, as it does
 +     * not support passing in zero as the checksum type.
 +     */
 +    *minor = krb5_c_make_checksum(krbContext, 0, key, 0, &data, &cksum);
 +    if (*minor != 0)
 +        return GSS_S_FAILURE;
 +
 +#ifdef HAVE_HEIMDAL_VERSION
 +    *cksumtype = cksum.cksumtype;
 +#else
 +    *cksumtype = cksum.checksum_type;
 +#endif
 +
 +    krb5_free_checksum_contents(krbContext, &cksum);
 +#endif /* HAVE_KRB5INT_C_MANDATORY_CKSUMTYPE */
 +
 +    if (!krb5_c_is_keyed_cksum(*cksumtype)) {
 +        *minor = KRB5KRB_AP_ERR_INAPP_CKSUM;
 +        return GSS_S_FAILURE;
 +    }
 +
 +    return GSS_S_COMPLETE;
 +}
 +
 +#ifdef HAVE_HEIMDAL_VERSION
 +static heim_general_string krbAnonymousPrincipalComponents[] =
 +    { KRB5_WELLKNOWN_NAME, KRB5_ANON_NAME };
 +
 +static const Principal krbAnonymousPrincipalData = {
 +    { KRB5_NT_WELLKNOWN, { 2, krbAnonymousPrincipalComponents } },
 +    "WELLKNOWN:ANONYMOUS"
 +};
 +#endif
 +
 +krb5_const_principal
 +krbAnonymousPrincipal(void)
 +{
 +#ifdef HAVE_HEIMDAL_VERSION
 +    return &krbAnonymousPrincipalData;
 +#else
 +    return krb5_anonymous_principal();
 +#endif
 +}
 +
 +krb5_error_code
 +krbCryptoLength(krb5_context krbContext,
 +#ifdef HAVE_HEIMDAL_VERSION
 +                krb5_crypto krbCrypto,
 +#else
 +                krb5_keyblock *key,
 +#endif
 +                int type,
 +                size_t *length)
 +{
 +#ifdef HAVE_HEIMDAL_VERSION
 +    return krb5_crypto_length(krbContext, krbCrypto, type, length);
 +#else
 +    unsigned int len;
 +    krb5_error_code code;
 +
 +    code = krb5_c_crypto_length(krbContext, KRB_KEY_TYPE(key), type, &len);
 +    if (code == 0)
 +        *length = (size_t)len;
 +
 +    return code;
 +#endif
 +}
 +
 +krb5_error_code
 +krbPaddingLength(krb5_context krbContext,
 +#ifdef HAVE_HEIMDAL_VERSION
 +                 krb5_crypto krbCrypto,
 +#else
 +                 krb5_keyblock *key,
 +#endif
 +                 size_t dataLength,
 +                 size_t *padLength)
 +{
 +    krb5_error_code code;
 +#ifdef HAVE_HEIMDAL_VERSION
 +    size_t headerLength, paddingLength;
 +
 +    code = krbCryptoLength(krbContext, krbCrypto,
 +                           KRB5_CRYPTO_TYPE_HEADER, &headerLength);
 +    if (code != 0)
 +        return code;
 +
 +    dataLength += headerLength;
 +
 +    code = krb5_crypto_length(krbContext, krbCrypto,
 +                              KRB5_CRYPTO_TYPE_PADDING, &paddingLength);
 +    if (code != 0)
 +        return code;
 +
 +    if (paddingLength != 0 && (dataLength % paddingLength) != 0)
 +        *padLength = paddingLength - (dataLength % paddingLength);
 +    else
 +        *padLength = 0;
 +
 +    return 0;
 +#else
 +    unsigned int pad;
 +
 +    code = krb5_c_padding_length(krbContext, KRB_KEY_TYPE(key), dataLength, &pad);
 +    if (code == 0)
 +        *padLength = (size_t)pad;
 +
 +    return code;
 +#endif /* HAVE_HEIMDAL_VERSION */
 +}
 +
 +krb5_error_code
 +krbBlockSize(krb5_context krbContext,
 +#ifdef HAVE_HEIMDAL_VERSION
 +                 krb5_crypto krbCrypto,
 +#else
 +                 krb5_keyblock *key,
 +#endif
 +                 size_t *blockSize)
 +{
 +#ifdef HAVE_HEIMDAL_VERSION
 +    return krb5_crypto_getblocksize(krbContext, krbCrypto, blockSize);
 +#else
 +    return krb5_c_block_size(krbContext, KRB_KEY_TYPE(key), blockSize);
 +#endif
 +}
 +
 +krb5_error_code
 +krbEnctypeToString(krb5_context krbContext,
 +                   krb5_enctype enctype,
 +                   const char *prefix,
 +                   gss_buffer_t string)
 +{
 +    krb5_error_code code;
 +#ifdef HAVE_HEIMDAL_VERSION
 +    char *enctypeBuf = NULL;
 +#else
 +    char enctypeBuf[128];
 +#endif
 +    size_t prefixLength, enctypeLength;
 +
 +#ifdef HAVE_HEIMDAL_VERSION
 +    code = krb5_enctype_to_string(krbContext, enctype, &enctypeBuf);
 +#else
 +    code = krb5_enctype_to_name(enctype, 0, enctypeBuf, sizeof(enctypeBuf));
 +#endif
 +    if (code != 0)
 +        return code;
 +
 +    prefixLength = (prefix != NULL) ? strlen(prefix) : 0;
 +    enctypeLength = strlen(enctypeBuf);
 +
 +    string->value = GSSEAP_MALLOC(prefixLength + enctypeLength + 1);
 +    if (string->value == NULL) {
 +#ifdef HAVE_HEIMDAL_VERSION
 +        krb5_xfree(enctypeBuf);
 +#endif
 +        return ENOMEM;
 +    }
 +
 +    if (prefixLength != 0)
 +        memcpy(string->value, prefix, prefixLength);
 +    memcpy((char *)string->value + prefixLength, enctypeBuf, enctypeLength);
 +
 +    string->length = prefixLength + enctypeLength;
 +    ((char *)string->value)[string->length] = '\0';
 +
 +#ifdef HAVE_HEIMDAL_VERSION
 +    krb5_xfree(enctypeBuf);
 +#endif
 +
 +    return 0;
 +}
 +
 +krb5_error_code
 +krbMakeAuthDataKdcIssued(krb5_context context,
 +                         const krb5_keyblock *key,
 +                         krb5_const_principal issuer,
 +#ifdef HAVE_HEIMDAL_VERSION
 +                         const AuthorizationData *authdata,
 +                         AuthorizationData *adKdcIssued
 +#else
 +                         krb5_authdata *const *authdata,
 +                         krb5_authdata ***adKdcIssued
 +#endif
 +                         )
 +{
 +#ifdef HAVE_HEIMDAL_VERSION
 +    krb5_error_code code;
 +    AD_KDCIssued kdcIssued;
 +    AuthorizationDataElement adDatum;
 +    unsigned char *buf;
 +    size_t buf_size, len;
 +    krb5_crypto crypto = NULL;
 +
 +    memset(&kdcIssued, 0, sizeof(kdcIssued));
 +    memset(adKdcIssued, 0, sizeof(*adKdcIssued));
 +
 +    kdcIssued.i_realm = issuer->realm != NULL ? (Realm *)&issuer->realm : NULL;
 +    kdcIssued.i_sname = (PrincipalName *)&issuer->name;
 +    kdcIssued.elements = *authdata;
 +
 +    ASN1_MALLOC_ENCODE(AuthorizationData, buf, buf_size, authdata, &len, code);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = krb5_crypto_init(context, key, 0, &crypto);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = krb5_create_checksum(context, crypto, KRB5_KU_AD_KDC_ISSUED,
 +                                0, buf, buf_size, &kdcIssued.ad_checksum);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    GSSEAP_FREE(buf);
 +    buf = NULL;
 +
 +    ASN1_MALLOC_ENCODE(AD_KDCIssued, buf, buf_size, &kdcIssued, &len, code);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    adDatum.ad_type = KRB5_AUTHDATA_KDC_ISSUED;
 +    adDatum.ad_data.length = buf_size;
 +    adDatum.ad_data.data = buf;
 +
 +    code = add_AuthorizationData(adKdcIssued, &adDatum);
 +    if (code != 0)
 +        goto cleanup;
 +
 +cleanup:
 +    if (buf != NULL)
 +        GSSEAP_FREE(buf);
 +    if (crypto != NULL)
 +        krb5_crypto_destroy(context, crypto);
 +    free_Checksum(&kdcIssued.ad_checksum);
 +
 +    return code;
 +#else
 +    return krb5_make_authdata_kdc_issued(context, key, issuer, authdata,
 +                                         adKdcIssued);
 +#endif /* HAVE_HEIMDAL_VERSION */
 +}
 +
 +krb5_error_code
 +krbMakeCred(krb5_context krbContext,
 +            krb5_auth_context authContext,
 +            krb5_creds *creds,
 +            krb5_data *data)
 +{
 +    krb5_error_code code;
 +#ifdef HAVE_HEIMDAL_VERSION
 +    KRB_CRED krbCred;
 +    KrbCredInfo krbCredInfo;
 +    krb5_keyblock *key;
 +    krb5_crypto krbCrypto = NULL;
-     ASN1_MALLOC_ENCODE(KrbCredInfo, buf, buf_size, &krbCredInfo, &len, code);
++    krb5_data credInfoData = { 0 };
++    size_t len;
 +#else
 +    krb5_data *d = NULL;
 +#endif
 +
 +    memset(data, 0, sizeof(*data));
 +#ifdef HAVE_HEIMDAL_VERSION
 +    memset(&krbCred, 0, sizeof(krbCred));
 +    memset(&krbCredInfo, 0, sizeof(krbCredInfo));
 +
 +    key = (authContext->local_subkey != NULL)
 +          ? authContext->local_subkey
 +          : authContext->keyblock;
 +
 +    krbCred.pvno = 5;
 +    krbCred.msg_type = krb_cred;
 +    krbCred.tickets.val = (Ticket *)GSSEAP_CALLOC(1, sizeof(Ticket));
 +    if (krbCred.tickets.val == NULL) {
 +        code = ENOMEM;
 +        goto cleanup;
 +    }
 +    krbCred.tickets.len = 1;
 +
 +    code = decode_Ticket(creds->ticket.data,
 +                         creds->ticket.length,
 +                         krbCred.tickets.val, &len);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    krbCredInfo.key         = creds->session;
 +    krbCredInfo.prealm      = &creds->client->realm;
 +    krbCredInfo.pname       = &creds->client->name;
 +    krbCredInfo.flags       = &creds->flags.b;
 +    krbCredInfo.authtime    = &creds->times.authtime;
 +    krbCredInfo.starttime   = &creds->times.starttime;
 +    krbCredInfo.endtime     = &creds->times.endtime;
 +    krbCredInfo.renew_till  = &creds->times.renew_till;
 +    krbCredInfo.srealm      = &creds->server->realm;
 +    krbCredInfo.sname       = &creds->server->name;
 +    krbCredInfo.caddr       = creds->addresses.len ? &creds->addresses : NULL;
 +
-                                       buf,
-                                       len,
++    ASN1_MALLOC_ENCODE(KrbCredInfo, credInfoData.data, credInfoData.length,
++                       &krbCredInfo, &len, code);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = krb5_crypto_init(krbContext, key, 0, &krbCrypto);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = krb5_encrypt_EncryptedData(krbContext,
 +                                      krbCrypto,
 +                                      KRB5_KU_KRB_CRED,
-     GSSEAP_FREE(buf);
-     buf = NULL;
-     ASN1_MALLOC_ENCODE(KRB_CRED, buf, buf_size, &krbCred, &len, code);
++                                      credInfoData.data,
++                                      credInfoData.length,
 +                                      0,
 +                                      &krbCred.enc_part);
 +    if (code != 0)
 +        goto cleanup;
 +
-     if (buf != NULL)
-         GSSEAP_FREE(buf);
++    ASN1_MALLOC_ENCODE(KRB_CRED, data->data, data->length,
++                       &krbCred, &len, code);
 +    if (code != 0)
 +        goto cleanup;
 +
 +cleanup:
 +    if (krbCrypto != NULL)
 +        krb5_crypto_destroy(krbContext, krbCrypto);
 +    free_KRB_CRED(&krbCred);
++    krb5_data_free(&credInfoData);
 +
 +    return code;
 +#else
 +    code = krb5_mk_1cred(krbContext, authContext, creds, &d, NULL);
 +    if (code == 0) {
 +        *data = *d;
 +        GSSEAP_FREE(d);
 +    }
 +
 +    return code;
 +#endif /* HAVE_HEIMDAL_VERSION */
 +}
index 81a6163,0000000..7343b31
mode 100644,000000..100644
--- /dev/null
@@@ -1,315 -1,0 +1,332 @@@
 +/*
 + * Copyright (c) 2010, JANET(UK)
 + * 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.
 + *
 + * 3. Neither the name of JANET(UK) nor the names of its contributors
 + *    may be used to endorse or promote products derived from this software
 + *    without specific prior written permission.
 + *
 + * 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.
 + */
 +
 +/*
 + * General mechanism utility routines.
 + */
 +
 +#include "gssapiP_eap.h"
 +
 +/*
 + * 1.3.6.1.4.1.5322(padl)
 + *      gssEap(22)
 + *       mechanisms(1)
 + *        eap-aes128-cts-hmac-sha1-96(17)
 + *        eap-aes256-cts-hmac-sha1-96(18)
 + *       nameTypes(2)
 + *       apiExtensions(3)
 + *        inquireSecContextByOid(1)
 + *        inquireCredByOid(2)
 + *        setSecContextOption(3)
 + *        setCredOption(4)
 + *        mechInvoke(5)
 + */
 +
 +/*
 + * Note: the enctype-less OID is used as the mechanism OID in exported
 + * names. There is no public symbol for it. This is consistent with
 + * the krb5 mechanism which, whilst known by many OIDs, always uses a
 + * canonical OID for exported names. (This OID is also returned by
 + * gss_inquire_name.)
 + */
 +static gss_OID_desc gssEapMechOids[] = {
 +    /* 1.3.6.1.4.1.5322.22.1  */
 +    { 9, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01" },
 +    /* 1.3.6.1.4.1.5322.22.1.17 */
 +    { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x11" },
 +    /* 1.3.6.1.4.1.5322.22.1.18 */
 +    { 10, "\x2B\x06\x01\x04\x01\xA9\x4A\x16\x01\x12" }
 +};
 +
 +gss_OID GSS_EAP_MECHANISM                            = &gssEapMechOids[0];
 +gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM    = &gssEapMechOids[1];
 +gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM    = &gssEapMechOids[2];
 +
 +/*
 + * Returns TRUE is the OID is a concrete mechanism OID, that is, one
 + * with a Kerberos enctype as the last element.
 + */
 +int
 +gssEapIsConcreteMechanismOid(const gss_OID oid)
 +{
 +    return oid->length > GSS_EAP_MECHANISM->length &&
 +           memcmp(oid->elements, GSS_EAP_MECHANISM->elements,
 +                  GSS_EAP_MECHANISM->length) == 0;
 +}
 +
 +int
 +gssEapIsMechanismOid(const gss_OID oid)
 +{
 +    return oid == GSS_C_NO_OID ||
 +           oidEqual(oid, GSS_EAP_MECHANISM) ||
 +           gssEapIsConcreteMechanismOid(oid);
 +}
 +
 +/*
 + * Validate that all elements are concrete mechanism OIDs.
 + */
 +OM_uint32
 +gssEapValidateMechs(OM_uint32 *minor,
 +                    const gss_OID_set mechs)
 +{
 +    int i;
 +
 +    *minor = 0;
 +
 +    if (mechs == GSS_C_NO_OID_SET) {
 +        return GSS_S_COMPLETE;
 +    }
 +
 +    for (i = 0; i < mechs->count; i++) {
 +        gss_OID oid = &mechs->elements[i];
 +
 +        if (!gssEapIsConcreteMechanismOid(oid)) {
 +            *minor = GSSEAP_WRONG_MECH;
 +            return GSS_S_BAD_MECH;
 +        }
 +    }
 +
 +    return GSS_S_COMPLETE;
 +}
 +
 +OM_uint32
 +gssEapOidToEnctype(OM_uint32 *minor,
 +                   const gss_OID oid,
 +                   krb5_enctype *enctype)
 +{
 +    OM_uint32 major;
 +    int suffix;
 +
 +    major = decomposeOid(minor,
 +                         GSS_EAP_MECHANISM->elements,
 +                         GSS_EAP_MECHANISM->length,
 +                         oid,
 +                         &suffix);
 +    if (major == GSS_S_COMPLETE)
 +        *enctype = suffix;
 +
 +    return major;
 +}
 +
 +OM_uint32
 +gssEapEnctypeToOid(OM_uint32 *minor,
 +                   krb5_enctype enctype,
 +                   gss_OID *pOid)
 +{
 +    OM_uint32 major;
 +    gss_OID oid;
 +
 +    *pOid = NULL;
 +
 +    oid = (gss_OID)GSSEAP_MALLOC(sizeof(*oid));
 +    if (oid == NULL) {
 +        *minor = ENOMEM;
 +        return GSS_S_FAILURE;
 +    }
 +
 +    oid->length = GSS_EAP_MECHANISM->length + 1;
 +    oid->elements = GSSEAP_MALLOC(oid->length);
 +    if (oid->elements == NULL) {
 +        *minor = ENOMEM;
 +        GSSEAP_FREE(oid);
 +        return GSS_S_FAILURE;
 +    }
 +
 +    major = composeOid(minor,
 +                       GSS_EAP_MECHANISM->elements,
 +                       GSS_EAP_MECHANISM->length,
 +                       enctype,
 +                       oid);
 +    if (major == GSS_S_COMPLETE) {
 +        gssEapInternalizeOid(oid, pOid);
 +        *pOid = oid;
 +    } else {
 +        GSSEAP_FREE(oid->elements);
 +        GSSEAP_FREE(oid);
 +    }
 +
 +    return major;
 +}
 +
 +OM_uint32
 +gssEapIndicateMechs(OM_uint32 *minor,
 +                    gss_OID_set *mechs)
 +{
 +    krb5_context krbContext;
 +    OM_uint32 major, tmpMinor;
 +    krb5_enctype *etypes;
 +    int i;
 +
 +    GSSEAP_KRB_INIT(&krbContext);
 +
 +    *minor = krb5_get_permitted_enctypes(krbContext, &etypes);
 +    if (*minor != 0) {
 +        return GSS_S_FAILURE;
 +    }
 +
 +    major = gss_create_empty_oid_set(minor, mechs);
 +    if (GSS_ERROR(major)) {
 +        GSSEAP_FREE(etypes);
 +        return major;
 +    }
 +
 +    for (i = 0; etypes[i] != ENCTYPE_NULL; i++) {
 +        gss_OID mechOid;
 +
 +        /* XXX currently we aren't equipped to encode these enctypes */
 +        if (etypes[i] < 0 || etypes[i] > 127)
 +            continue;
 +
 +        major = gssEapEnctypeToOid(minor, etypes[i], &mechOid);
 +        if (GSS_ERROR(major))
 +            break;
 +
 +        major = gss_add_oid_set_member(minor, mechOid, mechs);
 +        if (GSS_ERROR(major))
 +            break;
 +
 +        gss_release_oid(&tmpMinor, &mechOid);
 +    }
 +
 +    GSSEAP_FREE(etypes);
 +
 +    *minor = 0;
 +    return major;
 +}
 +
 +OM_uint32
 +gssEapDefaultMech(OM_uint32 *minor,
 +                  gss_OID *oid)
 +{
 +    gss_OID_set mechs;
 +    OM_uint32 major, tmpMinor;
 +
 +    major = gssEapIndicateMechs(minor, &mechs);
 +    if (GSS_ERROR(major)) {
 +        return major;
 +    }
 +
 +    if (mechs->count == 0) {
 +        gss_release_oid_set(&tmpMinor, &mechs);
 +        return GSS_S_BAD_MECH;
 +    }
 +
 +    if (!gssEapInternalizeOid(&mechs->elements[0], oid)) {
 +        /* don't double-free if we didn't internalize it */
 +        mechs->elements[0].length = 0;
 +        mechs->elements[0].elements = NULL;
 +    }
 +
 +    gss_release_oid_set(&tmpMinor, &mechs);
 +
 +    *minor = 0;
 +    return GSS_S_COMPLETE;
 +}
 +
 +int
 +gssEapInternalizeOid(const gss_OID oid,
 +                     gss_OID *const pInternalizedOid)
 +{
 +    int i;
 +
 +    *pInternalizedOid = GSS_C_NO_OID;
 +
 +    for (i = 0;
 +         i < sizeof(gssEapMechOids) / sizeof(gssEapMechOids[0]);
 +         i++) {
 +        if (oidEqual(oid, &gssEapMechOids[i])) {
 +            *pInternalizedOid = (const gss_OID)&gssEapMechOids[i];
 +            break;
 +        }
 +    }
 +
 +    if (*pInternalizedOid == GSS_C_NO_OID) {
 +        if (oidEqual(oid, GSS_EAP_NT_PRINCIPAL_NAME))
 +            *pInternalizedOid = (const gss_OID)GSS_EAP_NT_PRINCIPAL_NAME;
 +    }
 +
 +    if (*pInternalizedOid == GSS_C_NO_OID) {
 +        *pInternalizedOid = oid;
 +        return 0;
 +    }
 +
 +    return 1;
 +}
 +
++OM_uint32
++gssEapReleaseOid(OM_uint32 *minor, gss_OID *oid)
++{
++    gss_OID internalizedOid = GSS_C_NO_OID;
++
++    *minor = 0;
++
++    if (gssEapInternalizeOid(*oid, &internalizedOid)) {
++        /* OID was internalized, so we can mark it as "freed" */
++        *oid = GSS_C_NO_OID;
++        return GSS_S_COMPLETE;
++    }
++
++    /* we don't know about this OID */
++    return GSS_S_CONTINUE_NEEDED;
++}
++
 +static gss_buffer_desc gssEapSaslMechs[] = {
 +    { sizeof("EAP") - 1,        "EAP",       }, /* not used */
 +    { sizeof("EAP-AES128") - 1, "EAP-AES128" },
 +    { sizeof("EAP-AES256") - 1, "EAP-AES256" },
 +};
 +
 +gss_buffer_t
 +gssEapOidToSaslName(const gss_OID oid)
 +{
 +    size_t i;
 +
 +    for (i = 1; i < sizeof(gssEapMechOids)/sizeof(gssEapMechOids[0]); i++) {
 +        if (oidEqual(&gssEapMechOids[i], oid))
 +            return &gssEapSaslMechs[i];
 +    }
 +
 +    return GSS_C_NO_BUFFER;
 +}
 +
 +gss_OID
 +gssEapSaslNameToOid(const gss_buffer_t name)
 +{
 +    size_t i;
 +
 +    for (i = 1; i < sizeof(gssEapSaslMechs)/sizeof(gssEapSaslMechs[0]); i++) {
 +        if (bufferEqual(&gssEapSaslMechs[i], name))
 +            return &gssEapMechOids[i];
 +    }
 +
 +    return GSS_C_NO_OID;
 +}
index 28dd133,0000000..8b853cb
mode 100644,000000..100644
--- /dev/null
@@@ -1,1176 -1,0 +1,1184 @@@
-     unsigned char *buf = NULL;
-     size_t buf_size, len;
 +/*
 + * Copyright (c) 2010, JANET(UK)
 + * 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.
 + *
 + * 3. Neither the name of JANET(UK) nor the names of its contributors
 + *    may be used to endorse or promote products derived from this software
 + *    without specific prior written permission.
 + *
 + * 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.
 + */
 +
 +/*
 + * Fast reauthentication support.
 + */
 +
 +#include "gssapiP_eap.h"
 +
 +#include <dlfcn.h>
 +
 +/*
 + * Fast reauthentication support for EAP GSS.
 + */
 +
 +krb5_error_code
 +krb5_encrypt_tkt_part(krb5_context, const krb5_keyblock *, krb5_ticket *);
 +
 +krb5_error_code
 +encode_krb5_ticket(const krb5_ticket *rep, krb5_data **code);
 +
 +static OM_uint32
 +gssDisplayName(OM_uint32 *minor,
 +               gss_name_t name,
 +               gss_buffer_t buffer,
 +               gss_OID *name_type);
 +
 +static OM_uint32
 +gssImportName(OM_uint32 *minor,
 +              gss_buffer_t buffer,
 +              gss_OID name_type,
 +              gss_name_t *name);
 +
 +static krb5_error_code
 +getAcceptorKey(krb5_context krbContext,
 +               gss_ctx_id_t ctx,
 +               gss_cred_id_t cred,
 +               krb5_principal *princ,
 +               krb5_keyblock *key)
 +{
 +    krb5_error_code code;
 +    krb5_keytab keytab = NULL;
 +    krb5_keytab_entry ktent = { 0 };
 +    krb5_kt_cursor cursor;
 +
 +    *princ = NULL;
 +    memset(key, 0, sizeof(*key));
 +    memset(&cursor, 0, sizeof(cursor));
 +
 +    code = krb5_kt_default(krbContext, &keytab);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    if (cred != GSS_C_NO_CREDENTIAL && cred->name != GSS_C_NO_NAME) {
 +        code = krb5_kt_get_entry(krbContext, keytab,
 +                                 cred->name->krbPrincipal, 0,
 +                                 ctx->encryptionType, &ktent);
 +        if (code != 0)
 +            goto cleanup;
 +    } else {
 +        /*
 +         * It's not clear that looking encrypting the ticket in the
 +         * requested EAP enctype provides any value.
 +         */
 +        code = krb5_kt_start_seq_get(krbContext, keytab, &cursor);
 +        if (code != 0)
 +            goto cleanup;
 +
 +        while ((code = krb5_kt_next_entry(krbContext, keytab,
 +                                          &ktent, &cursor)) == 0) {
 +            if (KRB_KEY_TYPE(KRB_KT_ENT_KEYBLOCK(&ktent)) == ctx->encryptionType)
 +                break;
 +            else
 +                KRB_KT_ENT_FREE(krbContext, &ktent);
 +        }
 +    }
 +
 +    if (code == 0) {
 +        *princ = ktent.principal;
 +        *key = *KRB_KT_ENT_KEYBLOCK(&ktent);
 +    }
 +
 +cleanup:
 +    if (cred == GSS_C_NO_CREDENTIAL || cred->name == GSS_C_NO_NAME)
 +        krb5_kt_end_seq_get(krbContext, keytab, &cursor);
 +    krb5_kt_close(krbContext, keytab);
 +    if (code != 0)
 +        KRB_KT_ENT_FREE(krbContext, &ktent);
 +
 +    return code;
 +}
 +
 +static OM_uint32
 +freezeAttrContext(OM_uint32 *minor,
 +                  gss_name_t initiatorName,
 +                  krb5_const_principal acceptorPrinc,
 +                  krb5_keyblock *session,
 +#ifdef HAVE_HEIMDAL_VERSION
 +                  krb5_authdata *kdcIssuedAuthData
 +#else
 +                  krb5_authdata ***kdcIssuedAuthData
 +#endif
 +                  )
 +{
 +    OM_uint32 major, tmpMinor;
 +    krb5_error_code code;
 +    krb5_context krbContext;
 +    gss_buffer_desc attrBuf = GSS_C_EMPTY_BUFFER;
 +#ifdef HAVE_HEIMDAL_VERSION
 +    krb5_authdata authDataBuf, *authData = &authDataBuf;
 +    AuthorizationDataElement authDatum = { 0 };
 +#else
 +    krb5_authdata *authData[2], authDatum = { 0 };
 +#endif
 +
 +    memset(kdcIssuedAuthData, 0, sizeof(*kdcIssuedAuthData));
 +
 +    GSSEAP_KRB_INIT(&krbContext);
 +
 +    major = gssEapExportAttrContext(minor, initiatorName, &attrBuf);
 +    if (GSS_ERROR(major))
 +        return major;
 +
 +    authDatum.ad_type = KRB5_AUTHDATA_RADIUS_AVP;
 +#ifdef HAVE_HEIMDAL_VERSION
 +    authDatum.ad_data.length = attrBuf.length;
 +    authDatum.ad_data.data = attrBuf.value;
 +    authData->len = 1;
 +    authData->val = &authDatum;
 +#else
 +    authDatum.length = attrBuf.length;
 +    authDatum.contents = attrBuf.value;
 +    authData[0] = &authDatum;
 +    authData[1] = NULL;
 +#endif
 +
 +    code = krbMakeAuthDataKdcIssued(krbContext, session, acceptorPrinc,
 +                                    authData, kdcIssuedAuthData);
 +    if (code != 0) {
 +        major = GSS_S_FAILURE;
 +        *minor = code;
 +    } else {
 +        major = GSS_S_COMPLETE;
 +    }
 +
 +    gss_release_buffer(&tmpMinor, &attrBuf);
 +
 +    return major;
 +}
 +
 +/*
 + * Fabricate a ticket to ourselves given a GSS EAP context.
 + */
 +OM_uint32
 +gssEapMakeReauthCreds(OM_uint32 *minor,
 +                      gss_ctx_id_t ctx,
 +                      gss_cred_id_t cred,
 +                      gss_buffer_t credBuf)
 +{
 +    OM_uint32 major = GSS_S_COMPLETE;
 +    krb5_error_code code;
 +    krb5_context krbContext = NULL;
 +    krb5_keyblock session = { 0 }, acceptorKey = { 0 };
 +    krb5_principal server = NULL;
 +#ifdef HAVE_HEIMDAL_VERSION
 +    Ticket ticket;
 +    EncTicketPart enc_part;
 +    AuthorizationData authData = { 0 };
 +    krb5_crypto krbCrypto = NULL;
-     krb5_data *ticketData = NULL, credsData = { 0 };
++    krb5_data ticketData = { 0 };
++    krb5_data encPartData = { 0 };
++    size_t len;
 +#else
 +    krb5_ticket ticket;
 +    krb5_enc_tkt_part enc_part;
++    krb5_data *ticketData = NULL;
 +#endif
-     code = krb5_c_make_random_key(krbContext, ctx->encryptionType,
-                                   &session);
++    krb5_data credsData = { 0 };
 +    krb5_creds creds = { 0 };
 +    krb5_auth_context authContext = NULL;
 +
 +    memset(&ticket, 0, sizeof(ticket));
 +    memset(&enc_part, 0, sizeof(enc_part));
 +
 +    credBuf->length = 0;
 +    credBuf->value = NULL;
 +
 +    GSSEAP_KRB_INIT(&krbContext);
 +
 +    code = getAcceptorKey(krbContext, ctx, cred, &server, &acceptorKey);
 +    if (code == KRB5_KT_NOTFOUND) {
 +        *minor = code;
 +        return GSS_S_UNAVAILABLE;
 +    } else if (code != 0)
 +        goto cleanup;
 +
 +#ifdef HAVE_HEIMDAL_VERSION
 +    ticket.realm = server->realm;
 +    ticket.sname = server->name;
 +#else
 +    ticket.server = server;
 +#endif
 +
 +    /*
 +     * Generate a random session key to place in the ticket and
 +     * sign the "KDC-Issued" authorization data element.
 +     */
- #ifdef HAVE_HEIMDAL_VERSION
++#ifdef HAVE_HEIMDAL_VERSION
++    code = krb5_generate_random_keyblock(krbContext, ctx->encryptionType,
++                                         &session);
 +    if (code != 0)
 +        goto cleanup;
 +
-     ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size, &enc_part, &len, code);
 +    enc_part.flags.initial = 1;
 +    enc_part.key = session;
 +    enc_part.crealm = ctx->initiatorName->krbPrincipal->realm;
 +    enc_part.cname = ctx->initiatorName->krbPrincipal->name;
 +    enc_part.authtime = time(NULL);
 +    enc_part.starttime = &enc_part.authtime;
 +    enc_part.endtime = (ctx->expiryTime != 0)
 +                       ? ctx->expiryTime : KRB_TIME_FOREVER;
 +    enc_part.renew_till = NULL;
 +    enc_part.authorization_data = &authData;
 +
 +    major = freezeAttrContext(minor, ctx->initiatorName, server,
 +                              &session, &authData);
 +    if (GSS_ERROR(major))
 +        goto cleanup;
 +
-                                       buf,
-                                       len,
++    ASN1_MALLOC_ENCODE(EncTicketPart, encPartData.data, encPartData.length,
++                       &enc_part, &len, code);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = krb5_crypto_init(krbContext, &acceptorKey, 0, &krbCrypto);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = krb5_encrypt_EncryptedData(krbContext,
 +                                      krbCrypto,
 +                                      KRB5_KU_TICKET,
-     GSSEAP_FREE(buf);
-     buf = NULL;
-     ASN1_MALLOC_ENCODE(Ticket, buf, buf_size, &ticket, &len, code);
++                                      encPartData.data,
++                                      encPartData.length,
 +                                      0,
 +                                      &ticket.enc_part);
 +    if (code != 0)
 +        goto cleanup;
 +
-     creds.ticket = *ticketData;
++    ASN1_MALLOC_ENCODE(Ticket, ticketData.data, ticketData.length,
++                       &ticket, &len, code);
 +    if (code != 0)
 +        goto cleanup;
 +#else
++    code = krb5_c_make_random_key(krbContext, ctx->encryptionType,
++                                  &session);
++    if (code != 0)
++        goto cleanup;
++
 +    enc_part.flags = TKT_FLG_INITIAL;
 +    enc_part.session = &session;
 +    enc_part.client = ctx->initiatorName->krbPrincipal;
 +    enc_part.times.authtime = time(NULL);
 +    enc_part.times.starttime = enc_part.times.authtime;
 +    enc_part.times.endtime = (ctx->expiryTime != 0)
 +                             ? ctx->expiryTime
 +                             : KRB_TIME_FOREVER;
 +    enc_part.times.renew_till = 0;
 +
 +    major = freezeAttrContext(minor, ctx->initiatorName, server,
 +                              &session, &enc_part.authorization_data);
 +    if (GSS_ERROR(major))
 +        goto cleanup;
 +
 +    ticket.enc_part2 = &enc_part;
 +
 +    code = krb5_encrypt_tkt_part(krbContext, &acceptorKey, &ticket);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = encode_krb5_ticket(&ticket, &ticketData);
 +    if (code != 0)
 +        goto cleanup;
 +#endif /* HAVE_HEIMDAL_VERSION */
 +
 +    creds.client = ctx->initiatorName->krbPrincipal;
 +    creds.server = server;
 +#ifdef HAVE_HEIMDAL_VERSION
 +    creds.session = session;
 +    creds.times.authtime = enc_part.authtime;
 +    creds.times.starttime = *enc_part.starttime;
 +    creds.times.endtime = enc_part.endtime;
 +    creds.times.renew_till = 0;
 +    creds.flags.b = enc_part.flags;
-     if (buf != NULL)
-         GSSEAP_FREE(buf);
++    creds.ticket = ticketData;
 +    creds.authdata = authData;
 +#else
 +    creds.keyblock = session;
 +    creds.times = enc_part.times;
 +    creds.ticket_flags = enc_part.flags;
 +    creds.ticket = *ticketData;
 +    creds.authdata = enc_part.authorization_data;
 +#endif
 +
 +    code = krb5_auth_con_init(krbContext, &authContext);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = krb5_auth_con_setflags(krbContext, authContext, 0);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = krb5_auth_con_setsendsubkey(krbContext, authContext,
 +                                       &ctx->rfc3961Key);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = krbMakeCred(krbContext, authContext, &creds, &credsData);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    krbDataToGssBuffer(&credsData, credBuf);
 +
 +cleanup:
 +#ifdef HAVE_HEIMDAL_VERSION
 +    if (krbCrypto != NULL)
 +        krb5_crypto_destroy(krbContext, krbCrypto);
-     krb5_free_data(krbContext, ticketData);
 +    free_AuthorizationData(&authData);
 +    free_EncryptedData(&ticket.enc_part);
++    krb5_data_free(&ticketData);
++    krb5_data_free(&encPartData);
 +#else
 +    krb5_free_authdata(krbContext, enc_part.authorization_data);
 +    if (ticket.enc_part.ciphertext.data != NULL)
 +        GSSEAP_FREE(ticket.enc_part.ciphertext.data);
++    krb5_free_data(krbContext, ticketData);
 +#endif
 +    krb5_free_keyblock_contents(krbContext, &session);
 +    krb5_free_principal(krbContext, server);
 +    krb5_free_keyblock_contents(krbContext, &acceptorKey);
 +    krb5_auth_con_free(krbContext, authContext);
 +
 +    if (major == GSS_S_COMPLETE) {
 +        *minor = code;
 +        major = (code != 0) ? GSS_S_FAILURE : GSS_S_COMPLETE;
 +    }
 +
 +    return major;
 +}
 +
 +static int
 +isTicketGrantingServiceP(krb5_context krbContext,
 +                         krb5_const_principal principal)
 +{
 +    if (KRB_PRINC_LENGTH(principal) == 2 &&
 +#ifdef HAVE_HEIMDAL_VERSION
 +        strcmp(KRB_PRINC_NAME(principal)[0], "krbtgt") == 0
 +#else
 +        krb5_princ_component(krbContext, principal, 0)->length == 6 &&
 +        memcmp(krb5_princ_component(krbContext,
 +                                    principal, 0)->data, "krbtgt", 6) == 0
 +#endif
 +        )
 +        return TRUE;
 +
 +    return FALSE;
 +}
 +
 +/*
 + * Returns TRUE if the configuration variable reauth_use_ccache is
 + * set in krb5.conf for the eap_gss application and the client realm.
 + */
 +static int
 +reauthUseCredsCache(krb5_context krbContext,
 +                    krb5_principal principal)
 +{
 +    int reauthUseCCache;
 +
 +    /* if reauth_use_ccache, use default credentials cache if ticket is for us */
 +    krb5_appdefault_boolean(krbContext, "eap_gss",
 +                            KRB_PRINC_REALM(principal),
 +                            "reauth_use_ccache", 0, &reauthUseCCache);
 +
 +    return reauthUseCCache;
 +}
 +
 +/*
 + * Look in default credentials cache for reauthentication credentials,
 + * if policy allows.
 + */
 +static OM_uint32
 +getDefaultReauthCredentials(OM_uint32 *minor,
 +                            gss_cred_id_t cred,
 +                            gss_name_t target,
 +                            time_t now,
 +                            OM_uint32 timeReq)
 +{
 +    OM_uint32 major = GSS_S_CRED_UNAVAIL;
 +    krb5_context krbContext = NULL;
 +    krb5_error_code code = 0;
 +    krb5_ccache ccache = NULL;
 +    krb5_creds match = { 0 };
 +    krb5_creds creds = { 0 };
 +
 +    GSSEAP_KRB_INIT(&krbContext);
 +
 +    assert(cred != GSS_C_NO_CREDENTIAL);
 +    assert(target != GSS_C_NO_NAME);
 +
 +    if (cred->name == GSS_C_NO_NAME ||
 +        !reauthUseCredsCache(krbContext, cred->name->krbPrincipal))
 +        goto cleanup;
 +
 +    match.client = cred->name->krbPrincipal;
 +    match.server = target->krbPrincipal;
 +    if (timeReq != 0 && timeReq != GSS_C_INDEFINITE)
 +        match.times.endtime = now + timeReq;
 +
 +    code = krb5_cc_default(krbContext, &ccache);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = krb5_cc_retrieve_cred(krbContext, ccache, 0, &match, &creds);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    cred->flags |= CRED_FLAG_DEFAULT_CCACHE;
 +    cred->krbCredCache = ccache;
 +    ccache = NULL;
 +
 +    major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL,
 +                                 &cred->krbCred);
 +
 +cleanup:
 +    if (major == GSS_S_CRED_UNAVAIL)
 +        *minor = code;
 +
 +    if (ccache != NULL)
 +        krb5_cc_close(krbContext, ccache);
 +    krb5_free_cred_contents(krbContext, &creds);
 +
 +    return major;
 +}
 +
 +/*
 + * Returns TRUE if the credential handle's reauth credentials are
 + * valid or if we can use the default credentials cache. Credentials
 + * handle must be locked.
 + */
 +int
 +gssEapCanReauthP(gss_cred_id_t cred,
 +                 gss_name_t target,
 +                 OM_uint32 timeReq)
 +{
 +    time_t now, expiryReq;
 +    OM_uint32 minor;
 +
 +    assert(cred != GSS_C_NO_CREDENTIAL);
 +
 +    now = time(NULL);
 +    expiryReq = now;
 +    if (timeReq != GSS_C_INDEFINITE)
 +        expiryReq += timeReq;
 +
 +    if (cred->krbCredCache != NULL && cred->expiryTime > expiryReq)
 +        return TRUE;
 +
 +    if (getDefaultReauthCredentials(&minor, cred, target,
 +                                    now, timeReq) == GSS_S_COMPLETE)
 +        return TRUE;
 +
 +    return FALSE;
 +}
 +
 +/*
 + * Store re-authentication (Kerberos) credentials in a credential handle.
 + * Credentials handle must be locked.
 + */
 +OM_uint32
 +gssEapStoreReauthCreds(OM_uint32 *minor,
 +                       gss_ctx_id_t ctx,
 +                       gss_cred_id_t cred,
 +                       gss_buffer_t credBuf)
 +{
 +    OM_uint32 major = GSS_S_COMPLETE;
 +    krb5_error_code code;
 +    krb5_context krbContext = NULL;
 +    krb5_auth_context authContext = NULL;
 +    krb5_data credData = { 0 };
 +    krb5_creds **creds = NULL;
 +    krb5_principal canonPrinc;
 +    krb5_principal ccPrinc = NULL;
 +    int i;
 +
 +    if (credBuf->length == 0 || cred == GSS_C_NO_CREDENTIAL)
 +        return GSS_S_COMPLETE;
 +
 +    GSSEAP_KRB_INIT(&krbContext);
 +
 +    code = krb5_auth_con_init(krbContext, &authContext);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = krb5_auth_con_setflags(krbContext, authContext, 0);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    code = krb5_auth_con_setrecvsubkey(krbContext, authContext,
 +                                       &ctx->rfc3961Key);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    gssBufferToKrbData(credBuf, &credData);
 +
 +    code = krb5_rd_cred(krbContext, authContext, &credData, &creds, NULL);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    if (creds == NULL || creds[0] == NULL)
 +        goto cleanup;
 +
 +    code = krb5_copy_principal(krbContext, creds[0]->client, &canonPrinc);
 +    if (code != 0)
 +        goto cleanup;
 +
 +    krb5_free_principal(krbContext, cred->name->krbPrincipal);
 +    cred->name->krbPrincipal = canonPrinc;
 +
 +    if (creds[0]->times.endtime == KRB_TIME_FOREVER)
 +        cred->expiryTime = 0;
 +    else
 +        cred->expiryTime = creds[0]->times.endtime;
 +
 +    if (cred->krbCredCache == NULL) {
 +        if (reauthUseCredsCache(krbContext, creds[0]->client) &&
 +            krb5_cc_default(krbContext, &cred->krbCredCache) == 0)
 +            cred->flags |= CRED_FLAG_DEFAULT_CCACHE;
 +    } else {
 +        /*
 +         * If we already have an associated credentials cache, possibly from
 +         * the last time we stored a reauthentication credential, then we
 +         * need to clear it out and release the associated GSS credential.
 +         */
 +        if (cred->flags & CRED_FLAG_DEFAULT_CCACHE) {
 +            krb5_cc_remove_cred(krbContext, cred->krbCredCache, 0, creds[0]);
 +        } else {
 +            krb5_cc_destroy(krbContext, cred->krbCredCache);
 +            cred->krbCredCache = NULL;
 +        }
 +        gssReleaseCred(minor, &cred->krbCred);
 +    }
 +
 +    if (cred->krbCredCache == NULL) {
 +        code = krb5_cc_new_unique(krbContext, "MEMORY", NULL, &cred->krbCredCache);
 +        if (code != 0)
 +            goto cleanup;
 +    }
 +
 +    if ((cred->flags & CRED_FLAG_DEFAULT_CCACHE) == 0 ||
 +        krb5_cc_get_principal(krbContext, cred->krbCredCache, &ccPrinc) != 0) {
 +        code = krb5_cc_initialize(krbContext, cred->krbCredCache,
 +                                  creds[0]->client);
 +        if (code != 0)
 +            goto cleanup;
 +    }
 +
 +    for (i = 0; creds[i] != NULL; i++) {
 +        krb5_creds kcred = *(creds[i]);
 +
 +        /*
 +         * Swap in the acceptor name the client asked for so
 +         * get_credentials() works. We're making the assumption that
 +         * any service tickets returned are for us. We'll need to
 +         * reflect some more on whether that is a safe assumption.
 +         */
 +        if (!isTicketGrantingServiceP(krbContext, kcred.server))
 +            kcred.server = ctx->acceptorName->krbPrincipal;
 +
 +        code = krb5_cc_store_cred(krbContext, cred->krbCredCache, &kcred);
 +        if (code != 0)
 +            goto cleanup;
 +    }
 +
 +    major = gss_krb5_import_cred(minor, cred->krbCredCache, NULL, NULL,
 +                                 &cred->krbCred);
 +    if (GSS_ERROR(major))
 +        goto cleanup;
 +
 +cleanup:
 +    *minor = code;
 +
 +    krb5_free_principal(krbContext, ccPrinc);
 +    krb5_auth_con_free(krbContext, authContext);
 +    if (creds != NULL) {
 +        for (i = 0; creds[i] != NULL; i++)
 +            krb5_free_creds(krbContext, creds[i]);
 +        GSSEAP_FREE(creds);
 +    }
 +    if (major == GSS_S_COMPLETE)
 +        major = *minor ? GSS_S_FAILURE : GSS_S_COMPLETE;
 +
 +    return major;
 +}
 +
 +#ifndef HAVE_HEIMDAL_VERSION
 +static gss_buffer_desc radiusAvpKrbAttr = {
 +    sizeof("urn:authdata-radius-avp") - 1, "urn:authdata-radius-avp"
 +};
 +#endif
 +
 +/*
 + * Unfortunately extracting an AD-KDCIssued authorization data element
 + * is pretty implementation-dependent. It's not possible to verify the
 + * signature ourselves because the ticket session key is not exposed
 + * outside GSS. In an ideal world, all AD-KDCIssued elements would be
 + * verified by the Kerberos library and authentication would fail if
 + * verification failed. We're not quite there yet and as a result have
 + * to go through some hoops to get this to work. The alternative would
 + * be to sign the authorization data with our long-term key, but it
 + * seems a pity to compromise the design because of current implementation
 + * limitations.
 + *
 + * (Specifically, the hoops involve a libkrb5 authorisation data plugin
 + * that exposes the verified and serialised attribute context through
 + * the Kerberos GSS mechanism's naming extensions API.)
 + */
 +static OM_uint32
 +defrostAttrContext(OM_uint32 *minor,
 +                   gss_ctx_id_t glueContext,
 +                   gss_name_t glueName,
 +                   gss_name_t mechName)
 +{
 +    OM_uint32 major, tmpMinor;
 +#ifdef HAVE_HEIMDAL_VERSION
 +    gss_OID_desc oid = { 0 };
 +    gss_buffer_set_t authData = GSS_C_NO_BUFFER_SET;
 +#else
 +    gss_buffer_desc authData = GSS_C_EMPTY_BUFFER;
 +    gss_buffer_desc authDataDisplay = GSS_C_EMPTY_BUFFER;
 +    int more = -1;
 +    int authenticated, complete;
 +#endif
 +
 +#ifdef HAVE_HEIMDAL_VERSION
 +    major = composeOid(minor,
 +                       GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,
 +                       GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,
 +                       KRB5_AUTHDATA_RADIUS_AVP, &oid);
 +    if (GSS_ERROR(major))
 +        return major;
 +
 +    /* XXX we are assuming that this verifies AD-KDCIssued signature */
 +    major = gssInquireSecContextByOid(minor, glueContext,
 +                                      &oid, &authData);
 +    if (major == GSS_S_COMPLETE) {
 +        if (authData == GSS_C_NO_BUFFER_SET || authData->count != 1)
 +            major = GSS_S_FAILURE;
 +        else
 +            major = gssEapImportAttrContext(minor, authData->elements, mechName);
 +    } else if (major == GSS_S_FAILURE && *minor == ENOENT) {
 +        /* This is the equivalent of GSS_S_UNAVAILABLE for MIT attr APIs */
 +        *minor = 0;
 +        major = GSS_S_COMPLETE;
 +    }
 +
 +    gss_release_buffer_set(&tmpMinor, &authData);
 +    GSSEAP_FREE(oid.elements);
 +#else
 +    major = gssGetNameAttribute(minor, glueName, &radiusAvpKrbAttr,
 +                                &authenticated, &complete,
 +                                &authData, &authDataDisplay, &more);
 +    if (major == GSS_S_COMPLETE) {
 +        if (authenticated == 0)
 +            major = GSS_S_BAD_NAME;
 +        else
 +            major = gssEapImportAttrContext(minor, &authData, mechName);
 +    } else if (major == GSS_S_UNAVAILABLE) {
 +        major = GSS_S_COMPLETE;
 +    }
 +
 +    gss_release_buffer(&tmpMinor, &authData);
 +    gss_release_buffer(&tmpMinor, &authDataDisplay);
 +#endif /* HAVE_HEIMDAL_VERSION */
 +
 +    return major;
 +}
 +
 +/*
 + * Convert a mechanism glue to an EAP mechanism name by displaying and
 + * importing it. This also handles the RADIUS attributes.
 + */
 +OM_uint32
 +gssEapGlueToMechName(OM_uint32 *minor,
 +                     gss_ctx_id_t glueContext,
 +                     gss_name_t glueName,
 +                     gss_name_t *pMechName)
 +{
 +    OM_uint32 major, tmpMinor;
 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
 +
 +    *pMechName = GSS_C_NO_NAME;
 +
 +    major = gssDisplayName(minor, glueName, &nameBuf, NULL);
 +    if (GSS_ERROR(major))
 +        goto cleanup;
 +
 +    major = gssEapImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
 +                             pMechName);
 +    if (GSS_ERROR(major))
 +        goto cleanup;
 +
 +    major = defrostAttrContext(minor, glueContext, glueName, *pMechName);
 +    if (GSS_ERROR(major))
 +        goto cleanup;
 +
 +cleanup:
 +    if (GSS_ERROR(major)) {
 +        gssReleaseName(&tmpMinor, pMechName);
 +        *pMechName = GSS_C_NO_NAME;
 +    }
 +
 +    gss_release_buffer(&tmpMinor, &nameBuf);
 +
 +    return major;
 +}
 +
 +/*
 + * Convert an EAP mechanism name to a mechanism glue name by displaying
 + * and importing it.
 + */
 +OM_uint32
 +gssEapMechToGlueName(OM_uint32 *minor,
 +                     gss_name_t mechName,
 +                     gss_name_t *pGlueName)
 +{
 +    OM_uint32 major, tmpMinor;
 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
 +
 +    *pGlueName = GSS_C_NO_NAME;
 +
 +    major = gssEapDisplayName(minor, mechName, &nameBuf, NULL);
 +    if (GSS_ERROR(major))
 +        goto cleanup;
 +
 +    major = gssImportName(minor, &nameBuf, GSS_C_NT_USER_NAME,
 +                          pGlueName);
 +    if (GSS_ERROR(major))
 +        goto cleanup;
 +
 +cleanup:
 +    gss_release_buffer(&tmpMinor, &nameBuf);
 +
 +    return major;
 +}
 +
 +/*
 + * Suck out the analgous elements of a Kerberos GSS context into an EAP
 + * one so that the application doesn't know the difference.
 + */
 +OM_uint32
 +gssEapReauthComplete(OM_uint32 *minor,
 +                    gss_ctx_id_t ctx,
 +                    gss_cred_id_t cred,
 +                    const gss_OID mech,
 +                    OM_uint32 timeRec)
 +{
 +    OM_uint32 major, tmpMinor;
 +    gss_buffer_set_t keyData = GSS_C_NO_BUFFER_SET;
 +    krb5_context krbContext = NULL;
 +#ifdef HAVE_HEIMDAL_VERSION
 +    krb5_storage *sp = NULL;
 +#endif
 +
 +    GSSEAP_KRB_INIT(&krbContext);
 +
 +    if (!oidEqual(mech, gss_mech_krb5)) {
 +        major = GSS_S_BAD_MECH;
 +        goto cleanup;
 +    }
 +
 +    /* Get the raw subsession key and encryption type */
 +#ifdef HAVE_HEIMDAL_VERSION
 +#define KRB_GSS_SUBKEY_COUNT    1 /* encoded session key */
 +    major = gssInquireSecContextByOid(minor, ctx->kerberosCtx,
 +                                      GSS_KRB5_GET_SUBKEY_X, &keyData);
 +#else
 +#define KRB_GSS_SUBKEY_COUNT    2 /* raw session key, enctype OID */
 +    major = gssInquireSecContextByOid(minor, ctx->kerberosCtx,
 +                                      GSS_C_INQ_SSPI_SESSION_KEY, &keyData);
 +#endif
 +    if (GSS_ERROR(major))
 +        goto cleanup;
 +
 +    if (keyData == GSS_C_NO_BUFFER_SET || keyData->count < KRB_GSS_SUBKEY_COUNT) {
 +        *minor = GSSEAP_KEY_UNAVAILABLE;
 +        major = GSS_S_FAILURE;
 +        goto cleanup;
 +    }
 +
 +#ifdef HAVE_HEIMDAL_VERSION
 +    sp = krb5_storage_from_mem(keyData->elements[0].value,
 +                               keyData->elements[0].length);
 +    if (sp == NULL) {
 +        *minor = ENOMEM;
 +        major = GSS_S_FAILURE;
 +        goto cleanup;
 +    }
 +
 +    *minor = krb5_ret_keyblock(sp, &ctx->rfc3961Key);
 +    if (*minor != 0) {
 +        major = GSS_S_FAILURE;
 +        goto cleanup;
 +    }
 +#else
 +    {
 +        gss_OID_desc oid;
 +        int suffix;
 +
 +        oid.length = keyData->elements[1].length;
 +        oid.elements = keyData->elements[1].value;
 +
 +        /* GSS_KRB5_SESSION_KEY_ENCTYPE_OID */
 +        major = decomposeOid(minor,
 +                             "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04",
 +                             10, &oid, &suffix);
 +        if (GSS_ERROR(major))
 +            goto cleanup;
 +
 +        ctx->encryptionType = suffix;
 +    }
 +
 +    {
 +        krb5_keyblock key;
 +
 +        KRB_KEY_LENGTH(&key) = keyData->elements[0].length;
 +        KRB_KEY_DATA(&key)   = keyData->elements[0].value;
 +        KRB_KEY_TYPE(&key)   = ctx->encryptionType;
 +
 +        *minor = krb5_copy_keyblock_contents(krbContext,
 +                                             &key, &ctx->rfc3961Key);
 +        if (*minor != 0) {
 +            major = GSS_S_FAILURE;
 +            goto cleanup;
 +        }
 +    }
 +#endif /* HAVE_HEIMDAL_VERSION */
 +
 +    major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
 +                                      &ctx->checksumType);
 +    if (GSS_ERROR(major))
 +        goto cleanup;
 +
 +    if (timeRec != GSS_C_INDEFINITE)
 +        ctx->expiryTime = time(NULL) + timeRec;
 +
 +    /* Initialize our sequence state */
 +    major = sequenceInit(minor,
 +                         &ctx->seqState, ctx->recvSeq,
 +                         ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
 +                         ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
 +                         TRUE);
 +    if (GSS_ERROR(major))
 +        goto cleanup;
 +
 +    major = GSS_S_COMPLETE;
 +
 +cleanup:
 +#ifdef HAVE_HEIMDAL_VERSION
 +    if (sp != NULL)
 +        krb5_storage_free(sp);
 +#endif
 +    gss_release_buffer_set(&tmpMinor, &keyData);
 +
 +    return major;
 +}
 +
 +/*
 + * The remainder of this file consists of wrappers so we can call into the
 + * mechanism glue without calling ourselves.
 + */
 +static OM_uint32
 +(*gssInitSecContextNext)(OM_uint32 *,
 +                         gss_cred_id_t,
 +                         gss_ctx_id_t *,
 +                         gss_name_t,
 +                         gss_OID,
 +                         OM_uint32,
 +                         OM_uint32,
 +                         gss_channel_bindings_t,
 +                         gss_buffer_t,
 +                         gss_OID *,
 +                         gss_buffer_t,
 +                         OM_uint32 *,
 +                         OM_uint32 *);
 +
 +static OM_uint32
 +(*gssAcceptSecContextNext)(OM_uint32 *,
 +                           gss_ctx_id_t *,
 +                           gss_cred_id_t,
 +                           gss_buffer_t,
 +                           gss_channel_bindings_t,
 +                           gss_name_t *,
 +                           gss_OID *,
 +                           gss_buffer_t,
 +                           OM_uint32 *,
 +                           OM_uint32 *,
 +                           gss_cred_id_t *);
 +
 +static OM_uint32
 +(*gssReleaseCredNext)(OM_uint32 *, gss_cred_id_t *);
 +
 +static OM_uint32
 +(*gssReleaseNameNext)(OM_uint32 *, gss_name_t *);
 +
 +static OM_uint32
 +(*gssInquireSecContextByOidNext)(OM_uint32 *,
 +                                 const gss_ctx_id_t,
 +                                 const gss_OID,
 +                                 gss_buffer_set_t *);
 +
 +static OM_uint32
 +(*gssDeleteSecContextNext)(OM_uint32 *,
 +                          gss_ctx_id_t *,
 +                          gss_buffer_t);
 +
 +static OM_uint32
 +(*gssDisplayNameNext)(OM_uint32 *,
 +                      gss_name_t,
 +                      gss_buffer_t,
 +                      gss_OID *);
 +
 +static OM_uint32
 +(*gssImportNameNext)(OM_uint32 *,
 +                     gss_buffer_t,
 +                     gss_OID,
 +                     gss_name_t *);
 +
 +static OM_uint32
 +(*gssStoreCredNext)(OM_uint32 *,
 +                    const gss_cred_id_t,
 +                    gss_cred_usage_t,
 +                    const gss_OID,
 +                    OM_uint32,
 +                    OM_uint32,
 +                    gss_OID_set *,
 +                    gss_cred_usage_t *);
 +
 +static OM_uint32
 +(*gssGetNameAttributeNext)(OM_uint32 *,
 +                          gss_name_t,
 +                          gss_buffer_t,
 +                          int *,
 +                          int *,
 +                          gss_buffer_t,
 +                          gss_buffer_t,
 +                          int *);
 +
 +#define NEXT_SYMBOL(local, global)  do {        \
 +        ((local) = dlsym(RTLD_NEXT, (global))); \
 +        if ((local) == NULL) {                  \
 +            *minor = GSSEAP_NO_MECHGLUE_SYMBOL; \
 +            major = GSS_S_UNAVAILABLE;          \
 +            /* but continue */                  \
 +        }                                       \
 +    } while (0)
 +
 +OM_uint32
 +gssEapReauthInitialize(OM_uint32 *minor)
 +{
 +    OM_uint32 major = GSS_S_COMPLETE;
 +
 +    NEXT_SYMBOL(gssInitSecContextNext,         "gss_init_sec_context");
 +    NEXT_SYMBOL(gssAcceptSecContextNext,       "gss_accept_sec_context");
 +    NEXT_SYMBOL(gssReleaseCredNext,            "gss_release_cred");
 +    NEXT_SYMBOL(gssReleaseNameNext,            "gss_release_name");
 +    NEXT_SYMBOL(gssInquireSecContextByOidNext, "gss_inquire_sec_context_by_oid");
 +    NEXT_SYMBOL(gssDeleteSecContextNext,       "gss_delete_sec_context");
 +    NEXT_SYMBOL(gssDisplayNameNext,            "gss_display_name");
 +    NEXT_SYMBOL(gssImportNameNext,             "gss_import_name");
 +    NEXT_SYMBOL(gssStoreCredNext,              "gss_store_cred");
++#ifndef HAVE_HEIMDAL_VERSION
 +    NEXT_SYMBOL(gssGetNameAttributeNext,       "gss_get_name_attribute");
++#endif
 +
 +    return major;
 +}
 +
 +OM_uint32
 +gssInitSecContext(OM_uint32 *minor,
 +                  gss_cred_id_t cred,
 +                  gss_ctx_id_t *context_handle,
 +                  gss_name_t target_name,
 +                  gss_OID mech_type,
 +                  OM_uint32 req_flags,
 +                  OM_uint32 time_req,
 +                  gss_channel_bindings_t input_chan_bindings,
 +                  gss_buffer_t input_token,
 +                  gss_OID *actual_mech_type,
 +                  gss_buffer_t output_token,
 +                  OM_uint32 *ret_flags,
 +                  OM_uint32 *time_rec)
 +{
 +    if (gssInitSecContextNext == NULL) {
 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
 +        return GSS_S_UNAVAILABLE;
 +    }
 +
 +    return gssInitSecContextNext(minor, cred, context_handle,
 +                                 target_name, mech_type, req_flags,
 +                                 time_req, input_chan_bindings,
 +                                 input_token, actual_mech_type,
 +                                 output_token, ret_flags, time_rec);
 +}
 +
 +OM_uint32
 +gssAcceptSecContext(OM_uint32 *minor,
 +                    gss_ctx_id_t *context_handle,
 +                    gss_cred_id_t cred,
 +                    gss_buffer_t input_token,
 +                    gss_channel_bindings_t input_chan_bindings,
 +                    gss_name_t *src_name,
 +                    gss_OID *mech_type,
 +                    gss_buffer_t output_token,
 +                    OM_uint32 *ret_flags,
 +                    OM_uint32 *time_rec,
 +                    gss_cred_id_t *delegated_cred_handle)
 +{
 +    if (gssAcceptSecContextNext == NULL) {
 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
 +        return GSS_S_UNAVAILABLE;
 +    }
 +
 +    return gssAcceptSecContextNext(minor, context_handle, cred,
 +                                   input_token, input_chan_bindings,
 +                                   src_name, mech_type, output_token,
 +                                   ret_flags, time_rec, delegated_cred_handle);
 +}
 +
 +OM_uint32
 +gssReleaseCred(OM_uint32 *minor,
 +               gss_cred_id_t *cred_handle)
 +{
 +    if (gssReleaseCredNext == NULL) {
 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
 +        return GSS_S_UNAVAILABLE;
 +    }
 +
 +    return gssReleaseCredNext(minor, cred_handle);
 +}
 +
 +OM_uint32
 +gssReleaseName(OM_uint32 *minor,
 +               gss_name_t *name)
 +{
 +    if (gssReleaseName == NULL) {
 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
 +        return GSS_S_UNAVAILABLE;
 +    }
 +
 +    return gssReleaseNameNext(minor, name);
 +}
 +
 +OM_uint32
 +gssDeleteSecContext(OM_uint32 *minor,
 +                    gss_ctx_id_t *context_handle,
 +                    gss_buffer_t output_token)
 +{
 +    if (gssDeleteSecContextNext == NULL) {
 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
 +        return GSS_S_UNAVAILABLE;
 +    }
 +
 +    return gssDeleteSecContextNext(minor, context_handle, output_token);
 +}
 +
 +static OM_uint32
 +gssDisplayName(OM_uint32 *minor,
 +               gss_name_t name,
 +               gss_buffer_t buffer,
 +               gss_OID *name_type)
 +{
 +    if (gssDisplayNameNext == NULL) {
 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
 +        return GSS_S_UNAVAILABLE;
 +    }
 +
 +    return gssDisplayNameNext(minor, name, buffer, name_type);
 +}
 +
 +static OM_uint32
 +gssImportName(OM_uint32 *minor,
 +              gss_buffer_t buffer,
 +              gss_OID name_type,
 +              gss_name_t *name)
 +{
 +    if (gssImportNameNext == NULL) {
 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
 +        return GSS_S_UNAVAILABLE;
 +    }
 +
 +    return gssImportNameNext(minor, buffer, name_type, name);
 +}
 +
 +OM_uint32
 +gssInquireSecContextByOid(OM_uint32 *minor,
 +                          const gss_ctx_id_t context_handle,
 +                          const gss_OID desired_object,
 +                          gss_buffer_set_t *data_set)
 +{
 +    if (gssInquireSecContextByOidNext == NULL) {
 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
 +        return GSS_S_UNAVAILABLE;
 +    }
 +
 +    return gssInquireSecContextByOidNext(minor, context_handle,
 +                                         desired_object, data_set);
 +}
 +
 +OM_uint32
 +gssStoreCred(OM_uint32 *minor,
 +             const gss_cred_id_t input_cred_handle,
 +             gss_cred_usage_t input_usage,
 +             const gss_OID desired_mech,
 +             OM_uint32 overwrite_cred,
 +             OM_uint32 default_cred,
 +             gss_OID_set *elements_stored,
 +             gss_cred_usage_t *cred_usage_stored)
 +{
 +    if (gssStoreCredNext == NULL) {
 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
 +        return GSS_S_UNAVAILABLE;
 +    }
 +
 +    return gssStoreCredNext(minor, input_cred_handle, input_usage,
 +                            desired_mech, overwrite_cred, default_cred,
 +                            elements_stored, cred_usage_stored);
 +}
 +
 +OM_uint32
 +gssGetNameAttribute(OM_uint32 *minor,
 +                    gss_name_t name,
 +                    gss_buffer_t attr,
 +                    int *authenticated,
 +                    int *complete,
 +                    gss_buffer_t value,
 +                    gss_buffer_t display_value,
 +                    int *more)
 +{
 +    if (gssGetNameAttributeNext == NULL) {
 +        *minor = GSSEAP_NO_MECHGLUE_SYMBOL;
 +        return GSS_S_UNAVAILABLE;
 +    }
 +
 +    return gssGetNameAttributeNext(minor, name, attr, authenticated, complete,
 +                                   value, display_value, more);
 +}