From 24232fb5e0497300f36d85285d9b156bc936eb2d Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Thu, 17 Jul 2003 20:50:36 +0000 Subject: [PATCH] Remove kg_release_defcred and caching of default credential. Rewrite krb5_gss_init_sec_context() while we're at it to make defcred-related changes easier, and as a side effect, fix some error condition memory leaks. ticket: 1365 target_version: 1.3.1 tags: pullup git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@15694 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/gssapi/ChangeLog | 5 + src/lib/gssapi/gss_libinit.c | 3 - src/lib/gssapi/krb5/ChangeLog | 37 + src/lib/gssapi/krb5/gssapiP_krb5.h | 2 - src/lib/gssapi/krb5/gssapi_krb5.c | 36 +- src/lib/gssapi/krb5/init_sec_context.c | 988 ++++++++++++++----------- src/lib/gssapi/krb5/inq_cred.c | 25 +- src/lib/gssapi/krb5/rel_cred.c | 6 +- src/lib/gssapi/krb5/set_ccache.c | 2 - 9 files changed, 625 insertions(+), 479 deletions(-) diff --git a/src/lib/gssapi/ChangeLog b/src/lib/gssapi/ChangeLog index 26747104b..27fc2d9a9 100644 --- a/src/lib/gssapi/ChangeLog +++ b/src/lib/gssapi/ChangeLog @@ -1,3 +1,8 @@ +2003-07-17 Tom Yu + + * gss_libinit.c (gssint_initialize_library): Don't call + kg_release_defcred(); it doesn't exist any more. + 2003-03-08 Ken Raeburn * Makefile.in ($(BUILDTOP)/include/gssapi/gssapi.h, diff --git a/src/lib/gssapi/gss_libinit.c b/src/lib/gssapi/gss_libinit.c index 7906786e9..0568f2964 100644 --- a/src/lib/gssapi/gss_libinit.c +++ b/src/lib/gssapi/gss_libinit.c @@ -33,12 +33,9 @@ OM_uint32 gssint_initialize_library (void) void gssint_cleanup_library (void) { - OM_uint32 min_stat; assert (initialized); - (void) kg_release_defcred (&min_stat); - #if !USE_BUNDLE_ERROR_STRINGS remove_error_table(&et_k5g_error_table); remove_error_table(&et_ggss_error_table); diff --git a/src/lib/gssapi/krb5/ChangeLog b/src/lib/gssapi/krb5/ChangeLog index 88948c440..44ba4200e 100644 --- a/src/lib/gssapi/krb5/ChangeLog +++ b/src/lib/gssapi/krb5/ChangeLog @@ -1,3 +1,40 @@ +2003-07-17 Tom Yu + + * gssapiP_krb5.h: Delete kg_release_defcred(); it's no longer + used. + + * gssapi_krb5.c: Delete defcred; it's no longer cached. + (kg_get_defcred): Don't cache. + (kg_release_defcred): Delete; it's no longer used. + + * init_sec_context.c (krb5_gss_init_sec_context): Break into more + manageable pieces. Clean up a few error condition memory leaks + previously obscured by the sheer size of this function. + (setup_enc): New function; used to be part of + krb5_gss_init_sec_context() responsible for setting up enctypes, + keyblocks, related nastiness. + (get_requested_enctypes): New function; used to be part of + krb5_gss_init_sec_context() responsible for pruning the krb5 + library's default enctype list to the limited set of enctypes + usable with GSSAPI. + (new_connection): New function; used to be part of + krb5_gss_init_sec_context() responsible for initial gss_ctx setup + and creating the AP-REQ. + (mutual_auth): New function; used to be part of + krb5_gss_init_sec_context() responsible for reading the AP-REP if + mutual auth was requested. + + * inq_cred.c (krb5_gss_inquire_cred): Rearrange due to removal of + kg_release_defcred(), particularly to explicitly release the + defcred once it's obtained. + + * rel_cred.c (krb5_gss_release_cred): Remove call to + kg_release_defcred(), and always succeed in releasing the null + credential. + + * set_ccache.c (gss_krb5_ccache_name): Remove call to + kg_release_defcred(). + 2003-07-17 Ken Raeburn * Makefile.in (LIBNAME) [##WIN16##]: Don't define. diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h index f50653dbf..1215b1a9a 100644 --- a/src/lib/gssapi/krb5/gssapiP_krb5.h +++ b/src/lib/gssapi/krb5/gssapiP_krb5.h @@ -202,8 +202,6 @@ OM_uint32 kg_get_defcred (OM_uint32 *minor_status, gss_cred_id_t *cred); -OM_uint32 kg_release_defcred (OM_uint32 *minor_status); - krb5_error_code kg_checksum_channel_bindings (krb5_context context, gss_channel_bindings_t cb, krb5_checksum *cksum, diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c index db6eabd5d..2c7803bc5 100644 --- a/src/lib/gssapi/krb5/gssapi_krb5.c +++ b/src/lib/gssapi/krb5/gssapi_krb5.c @@ -128,10 +128,6 @@ void *kg_vdb = NULL; /** default credential support */ -/* default credentials */ - -static gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL; - /* * init_sec_context() will explicitly re-acquire default credentials, * so handling the expiration/invalidation condition here isn't needed. @@ -141,36 +137,18 @@ kg_get_defcred(minor_status, cred) OM_uint32 *minor_status; gss_cred_id_t *cred; { - if (defcred == GSS_C_NO_CREDENTIAL) { - OM_uint32 major; - - if ((major = krb5_gss_acquire_cred(minor_status, - (gss_name_t) NULL, GSS_C_INDEFINITE, - GSS_C_NULL_OID_SET, GSS_C_INITIATE, - &defcred, NULL, NULL)) && - GSS_ERROR(major)) { - defcred = GSS_C_NO_CREDENTIAL; - return(major); - } - } + OM_uint32 major; - *cred = defcred; + if ((major = krb5_gss_acquire_cred(minor_status, + (gss_name_t) NULL, GSS_C_INDEFINITE, + GSS_C_NULL_OID_SET, GSS_C_INITIATE, + cred, NULL, NULL)) && GSS_ERROR(major)) { + return(major); + } *minor_status = 0; return(GSS_S_COMPLETE); } -OM_uint32 -kg_release_defcred(minor_status) - OM_uint32 *minor_status; -{ - if (defcred == GSS_C_NO_CREDENTIAL) { - *minor_status = 0; - return(GSS_S_COMPLETE); - } - - return(krb5_gss_release_cred(minor_status, &defcred)); -} - OM_uint32 kg_get_context(minor_status, context) OM_uint32 *minor_status; diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c index 0d3ddc968..98102ce87 100644 --- a/src/lib/gssapi/krb5/init_sec_context.c +++ b/src/lib/gssapi/krb5/init_sec_context.c @@ -324,29 +324,21 @@ make_ap_req_v1(context, ctx, cred, k_cred, chan_bindings, mech_type, token) return (code); } -OM_uint32 -krb5_gss_init_sec_context(minor_status, claimant_cred_handle, - 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 *minor_status; - gss_cred_id_t claimant_cred_handle; - 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; +/* + * get_requested_enctypes + * + * Filter the krb5 library's default enctype list with the set of + * enctypes we support for GSSAPI. + */ +static krb5_error_code +get_requested_enctypes( + krb5_context context, + krb5_enctype **ret_enctypes) { - krb5_context context; - krb5_gss_cred_id_t cred; - krb5_creds *k_cred = 0; + krb5_error_code code; + int i, j, k; + int is_duplicate_enctype; + int is_wanted_enctype; static const krb5_enctype wanted_enctypes[] = { #if 1 ENCTYPE_DES3_CBC_SHA1, @@ -356,488 +348,614 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_MD4, }; #define N_WANTED_ENCTYPES (sizeof(wanted_enctypes)/sizeof(wanted_enctypes[0])) - krb5_enctype requested_enctypes[N_WANTED_ENCTYPES + 1]; krb5_enctype *default_enctypes = 0; - krb5_error_code code; - krb5_gss_ctx_id_rec *ctx, *ctx_free; - krb5_timestamp now; - gss_buffer_desc token; - int i, j, k, err; - int default_mech = 0; - OM_uint32 major_status; + krb5_enctype *requested_enctypes; - if (GSS_ERROR(kg_get_context(minor_status, &context))) - return(GSS_S_FAILURE); + *ret_enctypes = malloc((N_WANTED_ENCTYPES + 1) * sizeof(krb5_enctype)); + if (*ret_enctypes == NULL) + return ENOMEM; - /* set up return values so they can be "freed" successfully */ + code = krb5_get_tgs_ktypes (context, 0, &default_enctypes); + if (code) { + free(*ret_enctypes); + *ret_enctypes = NULL; + return code; + } + requested_enctypes = *ret_enctypes; + + /* "i" denotes *next* slot to fill. Don't forget to save room + for a trailing zero. */ + i = 0; + for (j = 0; + (default_enctypes[j] != 0 + /* This part should be redundant, but let's be paranoid. */ + && i < N_WANTED_ENCTYPES); + j++) { + + krb5_enctype e = default_enctypes[j]; + + /* Is this enctype one of the ones we want for GSSAPI? */ + is_wanted_enctype = 0; + for (k = 0; k < N_WANTED_ENCTYPES; k++) { + if (wanted_enctypes[k] == e) { + is_wanted_enctype = 1; + break; + } + } + /* If unwanted, go to the next one. */ + if (!is_wanted_enctype) + continue; + + /* Is this enctype already in the list of enctypes to + request? (Is it a duplicate?) */ + is_duplicate_enctype = 0; + for (k = 0; k < i; k++) { + if (requested_enctypes[k] == e) { + is_duplicate_enctype = 1; + break; + } + } + /* If it is not a duplicate, add it. */ + if (!is_duplicate_enctype) + requested_enctypes[i++] = e; + } + krb5_free_ktypes(context, default_enctypes); + requested_enctypes[i++] = 0; + return GSS_S_COMPLETE; +} - major_status = GSS_S_FAILURE; /* Default major code */ - output_token->length = 0; - output_token->value = NULL; - if (actual_mech_type) - *actual_mech_type = NULL; - token.value = 0; - ctx_free = 0; +/* + * setup_enc + * + * Fill in the encryption descriptors. Called after AP-REQ is made. + */ +static OM_uint32 +setup_enc( + OM_uint32 *minor_status, + krb5_gss_ctx_id_rec *ctx, + krb5_context context) +{ + krb5_error_code code; + int i; + + switch(ctx->subkey->enctype) { + case ENCTYPE_DES_CBC_MD5: + case ENCTYPE_DES_CBC_MD4: + case ENCTYPE_DES_CBC_CRC: + ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW; + ctx->signalg = SGN_ALG_DES_MAC_MD5; + ctx->cksum_size = 8; + ctx->sealalg = SEAL_ALG_DES; + + /* The encryption key is the session key XOR + 0xf0f0f0f0f0f0f0f0. */ + if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) + goto fail; - /* verify the credential, or use the default */ - /*SUPPRESS 29*/ - if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) { - OM_uint32 major; + for (i=0; ienc->length; i++) + /*SUPPRESS 113*/ + ctx->enc->contents[i] ^= 0xf0; - /* - * Release default cred prior to re-acquiring it, to notice when - * the ccache has changed. - */ - major = kg_release_defcred(minor_status); - if (GSS_ERROR(major)) - return major; - if ((major = kg_get_defcred(minor_status, &claimant_cred_handle)) && - GSS_ERROR(major)) { - return(major); + if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) + goto fail; + + break; + + case ENCTYPE_DES3_CBC_SHA1: + ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW; + ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD; + ctx->cksum_size = 20; + ctx->sealalg = SEAL_ALG_DES3KD; + + code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc); + if (code) + goto fail; + code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq); + if (code) { + krb5_free_keyblock (context, ctx->enc); + goto fail; } - } else { - OM_uint32 major; - - major = krb5_gss_validate_cred(minor_status, claimant_cred_handle); - if (GSS_ERROR(major)) - return(major); + break; + case ENCTYPE_ARCFOUR_HMAC: + ctx->signalg = SGN_ALG_HMAC_MD5 ; + ctx->cksum_size = 8; + ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ; + + code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc); + if (code) + goto fail; + code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq); + if (code) { + krb5_free_keyblock (context, ctx->enc); + goto fail; + } + break; +#if 0 + case ENCTYPE_DES3_CBC_MD5: + enctype = ENCTYPE_DES3_CBC_RAW; + ctx->signalg = 3; + ctx->cksum_size = 16; + ctx->sealalg = 1; + break; +#endif + default: + *minor_status = KRB5_BAD_ENCTYPE; + return GSS_S_FAILURE; } +fail: + *minor_status = code; + return GSS_S_FAILURE; +} - cred = (krb5_gss_cred_id_t) claimant_cred_handle; +/* + * new_connection + * + * Do the grunt work of setting up a new context. + */ +static OM_uint32 +new_connection( + OM_uint32 *minor_status, + krb5_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, + krb5_context context, + int default_mech) +{ + OM_uint32 major_status; + krb5_error_code code; + krb5_enctype *requested_enctypes; + krb5_creds *k_cred; + krb5_gss_ctx_id_rec *ctx, *ctx_free; + krb5_timestamp now; + gss_buffer_desc token; - /* verify the mech_type */ + major_status = GSS_S_FAILURE; + token.length = 0; + token.value = NULL; - err = 0; - if (mech_type == GSS_C_NULL_OID) { - default_mech = 1; - if (cred->rfc_mech) { - mech_type = (gss_OID) gss_mech_krb5; - } else if (cred->prerfc_mech) { - mech_type = (gss_OID) gss_mech_krb5_old; - } else { - err = 1; - } - } else if (g_OID_equal(mech_type, gss_mech_krb5)) { - if (!cred->rfc_mech) - err = 1; - } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) { - if (!cred->prerfc_mech) - err = 1; - } else { - err = 1; + /* make sure the cred is usable for init */ + + if ((cred->usage != GSS_C_INITIATE) && + (cred->usage != GSS_C_BOTH)) { + *minor_status = 0; + return(GSS_S_NO_CRED); } - - if (err) { + + /* complain if the input token is non-null */ + + if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) { *minor_status = 0; - return(GSS_S_BAD_MECH); + return(GSS_S_DEFECTIVE_TOKEN); } - /* verify that the target_name is valid and usable */ + /* create the ctx */ - if (! kg_validate_name(target_name)) { - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); + if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec))) + == NULL) { + *minor_status = ENOMEM; + return(GSS_S_FAILURE); } - /* is this a new connection or not? */ + /* fill in the ctx */ + memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec)); + ctx_free = ctx; + if ((code = krb5_auth_con_init(context, &ctx->auth_context))) + goto fail; + krb5_auth_con_setflags(context, ctx->auth_context, + KRB5_AUTH_CONTEXT_DO_SEQUENCE); + ctx->initiate = 1; + ctx->gss_flags = KG_IMPLFLAGS(req_flags); + ctx->seed_init = 0; + ctx->big_endian = 0; /* all initiators do little-endian, as per spec */ + ctx->seqstate = 0; + ctx->nctypes = 0; + ctx->ctypes = 0; + + if ((code = krb5_timeofday(context, &now))) + goto fail; + + if (time_req == 0 || time_req == GSS_C_INDEFINITE) { + ctx->endtime = 0; + } else { + ctx->endtime = now + time_req; + } - /*SUPPRESS 29*/ - if (*context_handle == GSS_C_NO_CONTEXT) { - /* make sure the cred is usable for init */ + if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) + goto fail; + + if ((code = krb5_copy_principal(context, (krb5_principal) target_name, + &ctx->there))) + goto fail; + + code = get_requested_enctypes(context, &requested_enctypes); + if (code) + goto fail; + + code = get_credentials(context, cred, ctx->there, now, + ctx->endtime, requested_enctypes, &k_cred); + free(requested_enctypes); + if (code) + goto fail; + + if (default_mech) { + mech_type = (gss_OID) gss_mech_krb5; + } - if ((cred->usage != GSS_C_INITIATE) && - (cred->usage != GSS_C_BOTH)) { - *minor_status = 0; - return(GSS_S_NO_CRED); + if (generic_gss_copy_oid(minor_status, mech_type, &ctx->mech_used) + != GSS_S_COMPLETE) { + code = *minor_status; + goto fail; + } + /* + * Now try to make it static if at all possible.... + */ + ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used); + + { + /* gsskrb5 v1 */ + if ((code = make_ap_req_v1(context, ctx, + cred, k_cred, input_chan_bindings, + mech_type, &token))) { + if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) || + (code == KG_EMPTY_CCACHE)) + major_status = GSS_S_NO_CRED; + if (code == KRB5KRB_AP_ERR_TKT_EXPIRED) + major_status = GSS_S_CREDENTIALS_EXPIRED; + goto fail; } - /* complain if the input token is non-null */ + krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, + &ctx->seq_send); + krb5_auth_con_getsendsubkey(context, ctx->auth_context, + &ctx->subkey); + } - if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) { - *minor_status = 0; - return(GSS_S_DEFECTIVE_TOKEN); - } + major_status = setup_enc(minor_status, ctx, context); - /* create the ctx */ + if (k_cred) { + krb5_free_creds(context, k_cred); + k_cred = 0; + } + + /* at this point, the context is constructed and valid, + hence, releaseable */ - if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec))) - == NULL) { - *minor_status = ENOMEM; - return(GSS_S_FAILURE); - } + /* intern the context handle */ - /* fill in the ctx */ - memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec)); - ctx_free = ctx; - if ((code = krb5_auth_con_init(context, &ctx->auth_context))) - goto fail; - krb5_auth_con_setflags(context, ctx->auth_context, - KRB5_AUTH_CONTEXT_DO_SEQUENCE); - ctx->initiate = 1; - ctx->gss_flags = KG_IMPLFLAGS(req_flags); - ctx->seed_init = 0; - ctx->big_endian = 0; /* all initiators do little-endian, as per spec */ - ctx->seqstate = 0; - ctx->nctypes = 0; - ctx->ctypes = 0; + if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) { + code = G_VALIDATE_FAILED; + goto fail; + } + *context_handle = (gss_ctx_id_t) ctx; + ctx_free = 0; + /* compute time_rec */ + if (time_rec) { if ((code = krb5_timeofday(context, &now))) - goto fail; + goto fail; + *time_rec = ctx->endtime - now; + } - if (time_req == 0 || time_req == GSS_C_INDEFINITE) { - ctx->endtime = 0; - } else { - ctx->endtime = now + time_req; - } + /* set the other returns */ + *output_token = token; - if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) - goto fail; - - if ((code = krb5_copy_principal(context, (krb5_principal) target_name, - &ctx->there))) - goto fail; + if (ret_flags) + *ret_flags = ctx->gss_flags; - code = krb5_get_tgs_ktypes (context, 0, &default_enctypes); - if (code) - goto fail; - /* "i" denotes *next* slot to fill. Don't forget to save room - for a trailing zero. */ - i = 0; - for (j = 0; - (default_enctypes[j] != 0 - /* This part should be redundant, but let's be paranoid. */ - && i < N_WANTED_ENCTYPES); - j++) { - - int is_duplicate_enctype; - int is_wanted_enctype; - - krb5_enctype e = default_enctypes[j]; - - /* Is this enctype one of the ones we want for GSSAPI? */ - is_wanted_enctype = 0; - for (k = 0; k < N_WANTED_ENCTYPES; k++) { - if (wanted_enctypes[k] == e) { - is_wanted_enctype = 1; - break; - } - } - /* If unwanted, go to the next one. */ - if (!is_wanted_enctype) - continue; - - /* Is this enctype already in the list of enctypes to - request? (Is it a duplicate?) */ - is_duplicate_enctype = 0; - for (k = 0; k < i; k++) { - if (requested_enctypes[k] == e) { - is_duplicate_enctype = 1; - break; - } - } - /* If it is not a duplicate, add it. */ - if (!is_duplicate_enctype) - requested_enctypes[i++] = e; - } - krb5_free_ktypes(context, default_enctypes); - requested_enctypes[i++] = 0; + if (actual_mech_type) + *actual_mech_type = mech_type; - if ((code = get_credentials(context, cred, ctx->there, now, - ctx->endtime, requested_enctypes, &k_cred))) - goto fail; + /* return successfully */ - if (default_mech) { - mech_type = (gss_OID) gss_mech_krb5; - } + *minor_status = 0; + if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) { + ctx->established = 0; + return(GSS_S_CONTINUE_NEEDED); + } else { + ctx->seq_recv = ctx->seq_send; + g_order_init(&(ctx->seqstate), ctx->seq_recv, + (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0, + (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0); + ctx->gss_flags |= GSS_C_PROT_READY_FLAG; + ctx->established = 1; + return(GSS_S_COMPLETE); + } - if (generic_gss_copy_oid(minor_status, mech_type, &ctx->mech_used) - != GSS_S_COMPLETE) { - code = *minor_status; - goto fail; - } - /* - * Now try to make it static if at all possible.... - */ - ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used); - - { - /* gsskrb5 v1 */ - if ((code = make_ap_req_v1(context, ctx, - cred, k_cred, input_chan_bindings, - mech_type, &token))) { - if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) || - (code == KG_EMPTY_CCACHE)) - major_status = GSS_S_NO_CRED; - if (code == KRB5KRB_AP_ERR_TKT_EXPIRED) - major_status = GSS_S_CREDENTIALS_EXPIRED; - goto fail; - } - - krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, - &ctx->seq_send); - krb5_auth_con_getsendsubkey(context, ctx->auth_context, - &ctx->subkey); - - /* fill in the encryption descriptors */ - - switch(ctx->subkey->enctype) { - case ENCTYPE_DES_CBC_MD5: - case ENCTYPE_DES_CBC_MD4: - case ENCTYPE_DES_CBC_CRC: - ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW; - ctx->signalg = SGN_ALG_DES_MAC_MD5; - ctx->cksum_size = 8; - ctx->sealalg = SEAL_ALG_DES; - - /* The encryption key is the session key XOR - 0xf0f0f0f0f0f0f0f0. */ - if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) - goto fail; - - for (i=0; ienc->length; i++) - /*SUPPRESS 113*/ - ctx->enc->contents[i] ^= 0xf0; - - if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) - goto fail; - - break; - - case ENCTYPE_DES3_CBC_SHA1: - ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW; - ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD; - ctx->cksum_size = 20; - ctx->sealalg = SEAL_ALG_DES3KD; - - code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc); - if (code) - goto fail; - code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq); - if (code) { - krb5_free_keyblock (context, ctx->enc); - goto fail; - } - break; - case ENCTYPE_ARCFOUR_HMAC: - ctx->signalg = SGN_ALG_HMAC_MD5 ; - ctx->cksum_size = 8; - ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ; - - code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc); - if (code) - goto fail; - code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq); - if (code) { - krb5_free_keyblock (context, ctx->enc); - goto fail; - } - break; -#if 0 - case ENCTYPE_DES3_CBC_MD5: - enctype = ENCTYPE_DES3_CBC_RAW; - ctx->signalg = 3; - ctx->cksum_size = 16; - ctx->sealalg = 1; - break; -#endif - default: - *minor_status = KRB5_BAD_ENCTYPE; - return GSS_S_FAILURE; - } +fail: + if (ctx_free) { + if (ctx_free->auth_context) + krb5_auth_con_free(context, ctx_free->auth_context); + if (ctx_free->here) + krb5_free_principal(context, ctx_free->here); + if (ctx_free->there) + krb5_free_principal(context, ctx_free->there); + if (ctx_free->subkey) + krb5_free_keyblock(context, ctx_free->subkey); + if (ctx_free->ctypes) + krb5_free_cksumtypes(context, ctx_free->ctypes); + xfree(ctx_free); + } else + (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); - } + *minor_status = code; + return (major_status); +} - if (k_cred) { - krb5_free_creds(context, k_cred); - k_cred = 0; - } - - /* at this point, the context is constructed and valid, - hence, releaseable */ +/* + * mutual_auth + * + * Handle the reply from the acceptor, if we're doing mutual auth. + */ +static OM_uint32 +mutual_auth( + OM_uint32 *minor_status, + krb5_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, + krb5_context context) +{ + OM_uint32 major_status; + unsigned char *ptr; + char *sptr; + krb5_data ap_rep; + krb5_ap_rep_enc_part *ap_rep_data; + krb5_timestamp now; + krb5_gss_ctx_id_rec *ctx; + krb5_error *krb_error; + krb5_error_code code; - /* intern the context handle */ + major_status = GSS_S_FAILURE; - if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) { - code = G_VALIDATE_FAILED; - goto fail; - } - *context_handle = (gss_ctx_id_t) ctx; - ctx_free = 0; - - /* compute time_rec */ - if (time_rec) { - if ((code = krb5_timeofday(context, &now))) - goto fail; - *time_rec = ctx->endtime - now; - } + /* validate the context handle */ + /*SUPPRESS 29*/ + if (! kg_validate_ctx_id(*context_handle)) { + *minor_status = (OM_uint32) G_VALIDATE_FAILED; + return(GSS_S_NO_CONTEXT); + } - /* set the other returns */ - *output_token = token; + ctx = (gss_ctx_id_t) *context_handle; - if (ret_flags) - *ret_flags = ctx->gss_flags; + /* make sure the context is non-established, and that certain + arguments are unchanged */ - if (actual_mech_type) - *actual_mech_type = mech_type; + if ((ctx->established) || + ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) { + code = KG_CONTEXT_ESTABLISHED; + goto fail; + } - /* return successfully */ + if (! krb5_principal_compare(context, ctx->there, + (krb5_principal) target_name)) { + (void)krb5_gss_delete_sec_context(minor_status, + context_handle, NULL); + code = 0; + major_status = GSS_S_BAD_NAME; + goto fail; + } - *minor_status = 0; - if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) { - ctx->established = 0; - return(GSS_S_CONTINUE_NEEDED); - } else { - ctx->seq_recv = ctx->seq_send; - g_order_init(&(ctx->seqstate), ctx->seq_recv, - (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0, - (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0); - ctx->gss_flags |= GSS_C_PROT_READY_FLAG; - ctx->established = 1; - /* fall through to GSS_S_COMPLETE */ - } - } else { - unsigned char *ptr; - char *sptr; - krb5_data ap_rep; - krb5_ap_rep_enc_part *ap_rep_data; - krb5_error *krb_error; - - /* validate the context handle */ - /*SUPPRESS 29*/ - if (! kg_validate_ctx_id(*context_handle)) { - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - return(GSS_S_NO_CONTEXT); - } + /* verify the token and leave the AP_REP message in ap_rep */ - ctx = (gss_ctx_id_t) *context_handle; + if (input_token == GSS_C_NO_BUFFER) { + (void)krb5_gss_delete_sec_context(minor_status, + context_handle, NULL); + code = 0; + major_status = GSS_S_DEFECTIVE_TOKEN; + goto fail; + } - /* make sure the context is non-established, and that certain - arguments are unchanged */ + ptr = (unsigned char *) input_token->value; - if ((ctx->established) || - (((gss_cred_id_t) cred) != claimant_cred_handle) || - ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) { - code = KG_CONTEXT_ESTABLISHED; - goto fail; - } + if (g_verify_token_header((gss_OID) ctx->mech_used, + &(ap_rep.length), + &ptr, KG_TOK_CTX_AP_REP, + input_token->length)) { + if (g_verify_token_header((gss_OID) ctx->mech_used, + &(ap_rep.length), + &ptr, KG_TOK_CTX_ERROR, + input_token->length) == 0) { + + /* Handle a KRB_ERROR message from the server */ - if (! krb5_principal_compare(context, ctx->there, - (krb5_principal) target_name)) { - (void)krb5_gss_delete_sec_context(minor_status, - context_handle, NULL); - code = 0; - major_status = GSS_S_BAD_NAME; + sptr = (char *) ptr; /* PC compiler bug */ + TREAD_STR(sptr, ap_rep.data, ap_rep.length); + + code = krb5_rd_error(context, &ap_rep, &krb_error); + if (code) + goto fail; + if (krb_error->error) + code = krb_error->error + ERROR_TABLE_BASE_krb5; + else + code = 0; + krb5_free_error(context, krb_error); goto fail; + } else { + *minor_status = 0; + return(GSS_S_DEFECTIVE_TOKEN); } + } - /* verify the token and leave the AP_REP message in ap_rep */ + sptr = (char *) ptr; /* PC compiler bug */ + TREAD_STR(sptr, ap_rep.data, ap_rep.length); - if (input_token == GSS_C_NO_BUFFER) { - (void)krb5_gss_delete_sec_context(minor_status, - context_handle, NULL); - code = 0; - major_status = GSS_S_DEFECTIVE_TOKEN; + /* decode the ap_rep */ + if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep, + &ap_rep_data))) { + /* + * XXX A hack for backwards compatiblity. + * To be removed in 1999 -- proven + */ + krb5_auth_con_setuseruserkey(context, ctx->auth_context, + ctx->subkey); + if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep, + &ap_rep_data))) goto fail; - } + } - ptr = (unsigned char *) input_token->value; + /* store away the sequence number */ + ctx->seq_recv = ap_rep_data->seq_number; + g_order_init(&(ctx->seqstate), ctx->seq_recv, + (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0, + (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) !=0); - if ((err = g_verify_token_header((gss_OID) ctx->mech_used, - &(ap_rep.length), - &ptr, KG_TOK_CTX_AP_REP, - input_token->length))) { - if (g_verify_token_header((gss_OID) ctx->mech_used, - &(ap_rep.length), - &ptr, KG_TOK_CTX_ERROR, - input_token->length) == 0) { + /* free the ap_rep_data */ + krb5_free_ap_rep_enc_part(context, ap_rep_data); - /* Handle a KRB_ERROR message from the server */ + /* set established */ + ctx->established = 1; - sptr = (char *) ptr; /* PC compiler bug */ - TREAD_STR(sptr, ap_rep.data, ap_rep.length); - - code = krb5_rd_error(context, &ap_rep, &krb_error); - if (code) - goto fail; - if (krb_error->error) - code = krb_error->error + ERROR_TABLE_BASE_krb5; - else - code = 0; - krb5_free_error(context, krb_error); - goto fail; - } else { - *minor_status = 0; - return(GSS_S_DEFECTIVE_TOKEN); - } - } + /* set returns */ - sptr = (char *) ptr; /* PC compiler bug */ - TREAD_STR(sptr, ap_rep.data, ap_rep.length); - - /* decode the ap_rep */ - if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep, - &ap_rep_data))) { - /* - * XXX A hack for backwards compatiblity. - * To be removed in 1999 -- proven - */ - krb5_auth_con_setuseruserkey(context, ctx->auth_context, - ctx->subkey); - if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep, - &ap_rep_data))) - goto fail; - } + if (time_rec) { + if ((code = krb5_timeofday(context, &now))) + goto fail; + *time_rec = ctx->endtime - now; + } - /* store away the sequence number */ - ctx->seq_recv = ap_rep_data->seq_number; - g_order_init(&(ctx->seqstate), ctx->seq_recv, - (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0, - (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) !=0); + if (ret_flags) + *ret_flags = ctx->gss_flags; - /* free the ap_rep_data */ - krb5_free_ap_rep_enc_part(context, ap_rep_data); + if (actual_mech_type) + *actual_mech_type = mech_type; - /* set established */ - ctx->established = 1; + /* success */ - /* set returns */ + *minor_status = 0; + return GSS_S_COMPLETE; - if (time_rec) { - if ((code = krb5_timeofday(context, &now))) - goto fail; - *time_rec = ctx->endtime - now; - } +fail: + (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); - if (ret_flags) - *ret_flags = ctx->gss_flags; + *minor_status = code; + return (major_status); +} - if (actual_mech_type) - *actual_mech_type = mech_type; +OM_uint32 +krb5_gss_init_sec_context(minor_status, claimant_cred_handle, + 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 *minor_status; + gss_cred_id_t claimant_cred_handle; + 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; +{ + krb5_context context; + krb5_gss_cred_id_t cred; + int err; + int default_mech = 0; + OM_uint32 major_status; + OM_uint32 tmp_min_stat; + + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + + /* set up return values so they can be "freed" successfully */ + + major_status = GSS_S_FAILURE; /* Default major code */ + output_token->length = 0; + output_token->value = NULL; + if (actual_mech_type) + *actual_mech_type = NULL; - /* success */ + /* verify that the target_name is valid and usable */ + if (! kg_validate_name(target_name)) { + *minor_status = (OM_uint32) G_VALIDATE_FAILED; + return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); + } + + /* verify the credential, or use the default */ + /*SUPPRESS 29*/ + if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) { + major_status = kg_get_defcred(minor_status, &cred); + if (major_status && GSS_ERROR(major_status)) { + return(major_status); + } + } else { + major_status = krb5_gss_validate_cred(minor_status, claimant_cred_handle); + if (GSS_ERROR(major_status)) + return(major_status); + cred = (krb5_gss_cred_id_t) claimant_cred_handle; + } + + /* verify the mech_type */ + + err = 0; + if (mech_type == GSS_C_NULL_OID) { + default_mech = 1; + if (cred->rfc_mech) { + mech_type = (gss_OID) gss_mech_krb5; + } else if (cred->prerfc_mech) { + mech_type = (gss_OID) gss_mech_krb5_old; + } else { + err = 1; + } + } else if (g_OID_equal(mech_type, gss_mech_krb5)) { + if (!cred->rfc_mech) + err = 1; + } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) { + if (!cred->prerfc_mech) + err = 1; + } else { + err = 1; + } + + if (err) { + if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) + krb5_gss_release_cred(minor_status, (gss_cred_id_t)cred); *minor_status = 0; - /* fall through to GSS_S_COMPLETE */ + return(GSS_S_BAD_MECH); } - return(GSS_S_COMPLETE); + /* is this a new connection or not? */ -fail: - if (ctx_free) { - if (ctx_free->auth_context) - krb5_auth_con_free(context, ctx_free->auth_context); - if (ctx_free->here) - krb5_free_principal(context, ctx_free->here); - if (ctx_free->there) - krb5_free_principal(context, ctx_free->there); - if (ctx_free->subkey) - krb5_free_keyblock(context, ctx_free->subkey); - if (ctx_free->ctypes) - krb5_free_cksumtypes(context, ctx_free->ctypes); - xfree(ctx_free); - } else - (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); + /*SUPPRESS 29*/ + if (*context_handle == GSS_C_NO_CONTEXT) { + major_status = new_connection(minor_status, 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, + context, default_mech); + } else { + major_status = mutual_auth(minor_status, 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, + context); + } - *minor_status = code; - return (major_status); + if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) + krb5_gss_release_cred(&tmp_min_stat, (gss_cred_id_t)cred); + + return(major_status); } diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c index a79034d9e..83782162b 100644 --- a/src/lib/gssapi/krb5/inq_cred.c +++ b/src/lib/gssapi/krb5/inq_cred.c @@ -91,6 +91,8 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, gss_OID_set mechs; OM_uint32 ret; + ret = GSS_S_FAILURE; + if (GSS_ERROR(kg_get_context(minor_status, &context))) return(GSS_S_FAILURE); @@ -102,7 +104,7 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, if (cred_handle == GSS_C_NO_CREDENTIAL) { OM_uint32 major; - if ((major = kg_get_defcred(minor_status, &cred_handle)) && + if ((major = kg_get_defcred(minor_status, (gss_cred_id_t)&cred)) && GSS_ERROR(major)) { return(major); } @@ -112,13 +114,13 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, major = krb5_gss_validate_cred(minor_status, cred_handle); if (GSS_ERROR(major)) return(major); + cred = (krb5_gss_cred_id_t) cred_handle; } - cred = (krb5_gss_cred_id_t) cred_handle; - if ((code = krb5_timeofday(context, &now))) { *minor_status = code; - return(GSS_S_FAILURE); + ret = GSS_S_FAILURE; + goto fail; } if (cred->tgt_expire > 0) { @@ -132,7 +134,8 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, if (cred->princ && (code = krb5_copy_principal(context, cred->princ, &ret_name))) { *minor_status = code; - return(GSS_S_FAILURE); + ret = GSS_S_FAILURE; + goto fail; } } @@ -149,7 +152,7 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, &mechs)))) { krb5_free_principal(context, ret_name); /* *minor_status set above */ - return(ret); + goto fail; } } @@ -172,8 +175,18 @@ krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, if (mechanisms) *mechanisms = mechs; + if (cred_handle == GSS_C_NO_CREDENTIAL) + krb5_gss_release_cred(minor_status, (gss_cred_id_t)cred); + *minor_status = 0; return((lifetime == 0)?GSS_S_CREDENTIALS_EXPIRED:GSS_S_COMPLETE); +fail: + if (cred_handle == GSS_C_NO_CREDENTIAL) { + OM_uint32 tmp_min_stat; + + krb5_gss_release_cred(&tmp_min_stat, (gss_cred_id_t)cred); + } + return ret; } /* V2 interface */ diff --git a/src/lib/gssapi/krb5/rel_cred.c b/src/lib/gssapi/krb5/rel_cred.c index 0d81399af..43d5ca1c2 100644 --- a/src/lib/gssapi/krb5/rel_cred.c +++ b/src/lib/gssapi/krb5/rel_cred.c @@ -34,8 +34,10 @@ krb5_gss_release_cred(minor_status, cred_handle) if (GSS_ERROR(kg_get_context(minor_status, &context))) return(GSS_S_FAILURE); - if (*cred_handle == GSS_C_NO_CREDENTIAL) - return(kg_release_defcred(minor_status)); + if (*cred_handle == GSS_C_NO_CREDENTIAL) { + *minor_status = 0; + return(GSS_S_COMPLETE); + } if (! kg_delete_cred_id(*cred_handle)) { *minor_status = (OM_uint32) G_VALIDATE_FAILED; diff --git a/src/lib/gssapi/krb5/set_ccache.c b/src/lib/gssapi/krb5/set_ccache.c index 9a612201b..236a83aff 100644 --- a/src/lib/gssapi/krb5/set_ccache.c +++ b/src/lib/gssapi/krb5/set_ccache.c @@ -38,7 +38,6 @@ gss_krb5_ccache_name(minor_status, name, out_name) { krb5_context context; krb5_error_code retval; - OM_uint32 foo_stat; static char *oldname = NULL; const char *tmpname = NULL; @@ -66,6 +65,5 @@ gss_krb5_ccache_name(minor_status, name, out_name) *minor_status = retval; return GSS_S_FAILURE; } - kg_release_defcred(&foo_stat); return GSS_S_COMPLETE; } -- 2.26.2