From: Theodore Tso Date: Sat, 7 Jun 1997 02:16:37 +0000 (+0000) Subject: accept_sec_context.c (krb5_gss_accept_sec_context): Reorganized error X-Git-Tag: krb5-1.1-beta1~1130 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=1de492a5b3685625f80befef393b2169b658c5cf;p=krb5.git accept_sec_context.c (krb5_gss_accept_sec_context): Reorganized error handling code to be more compact (and correct!). If an error occurs while we are doing mutual authentication, send an KRB_ERROR message back to the client, so that it knows what is going on. (This is specified by RFC 1964; we just weren't implementing this previously.) delete_sec_context.c (krb5_gss_delete_sec_context): Check to make sure pointers in the context are non-zero before freeing them. init_sec_context.c (krb5_gss_init_sec_context): If the server sends a KRB_ERROR message, decode it and return an appropriate minor status error code. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@10094 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/gssapi/krb5/ChangeLog b/src/lib/gssapi/krb5/ChangeLog index dd76dad6d..3718b8509 100644 --- a/src/lib/gssapi/krb5/ChangeLog +++ b/src/lib/gssapi/krb5/ChangeLog @@ -1,3 +1,20 @@ +Fri Jun 6 15:26:27 1997 Theodore Y. Ts'o + + * accept_sec_context.c (krb5_gss_accept_sec_context): Reorganized + error handling code to be more compact (and correct!). If + an error occurs while we are doing mutual authentication, + send an KRB_ERROR message back to the client, so that it + knows what is going on. (This is specified by RFC 1964; + we just weren't implementing this previously.) + + * delete_sec_context.c (krb5_gss_delete_sec_context): Check to + make sure pointers in the context are non-zero before + freeing them. + + * init_sec_context.c (krb5_gss_init_sec_context): If the server + sends a KRB_ERROR message, decode it and return an + appropriate minor status error code. + Mon Mar 31 21:22:19 1997 Theodore Y. Ts'o * krb5_gss_glue.c: Add GSSAPI V2 calls to the glue layer. diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c index 158983557..d54e49672 100644 --- a/src/lib/gssapi/krb5/accept_sec_context.c +++ b/src/lib/gssapi/krb5/accept_sec_context.c @@ -20,6 +20,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include "k5-int.h" #include "gssapiP_krb5.h" #include @@ -114,10 +115,11 @@ krb5_gss_accept_sec_context(minor_status, context_handle, int i; krb5_error_code code; krb5_address addr, *paddr; - krb5_authenticator *authdat; + krb5_authenticator *authdat = 0; krb5_checksum md5; - krb5_principal name; - int gss_flags; + krb5_principal name = NULL; + int gss_flags = 0; + int decode_req_message = 0; krb5_gss_ctx_id_rec *ctx; krb5_enctype enctype; krb5_timestamp now; @@ -129,7 +131,9 @@ krb5_gss_accept_sec_context(minor_status, context_handle, krb5_data option; krb5_auth_context auth_context_cred = NULL; const gss_OID_desc *mech_used = NULL; - + OM_uint32 major_status = GSS_S_FAILURE; + krb5_error krb_error_data; + krb5_data scratch; if (GSS_ERROR(kg_get_context(minor_status, &context))) return(GSS_S_FAILURE); @@ -140,6 +144,9 @@ krb5_gss_accept_sec_context(minor_status, context_handle, *src_name = (gss_name_t) NULL; output_token->length = 0; output_token->value = NULL; + token.value = 0; + md5.contents = 0; + if (mech_type) *mech_type = GSS_C_NULL_OID; /* return a bogus cred handle */ @@ -182,9 +189,9 @@ krb5_gss_accept_sec_context(minor_status, context_handle, ptr = (unsigned char *) input_token->value; - if (err = g_verify_token_header((gss_OID) gss_mech_krb5, &(ap_req.length), - &ptr, KG_TOK_CTX_AP_REQ, - input_token->length)) { + if ((err = g_verify_token_header((gss_OID) gss_mech_krb5, &(ap_req.length), + &ptr, KG_TOK_CTX_AP_REQ, + input_token->length))) { /* * Previous versions of this library used the old mech_id * and some broken behavior (wrong IV on checksum @@ -218,6 +225,7 @@ krb5_gss_accept_sec_context(minor_status, context_handle, sptr = (char *) ptr; TREAD_STR(sptr, ap_req.data, ap_req.length); + decode_req_message = 1; /* construct the sender_addr */ @@ -238,10 +246,8 @@ krb5_gss_accept_sec_context(minor_status, context_handle, /* decode the message */ if ((code = krb5_rd_req(context, &auth_context, &ap_req, cred->princ, - cred->keytab, NULL, &ticket))) { - *minor_status = code; - return(GSS_S_FAILURE); - } + cred->keytab, NULL, &ticket))) + goto fail; krb5_auth_con_getauthenticator(context, auth_context, &authdat); @@ -250,9 +256,8 @@ krb5_gss_accept_sec_context(minor_status, context_handle, if ((authdat->authenticator->subkey == NULL) || (authdat->ticket->enc_part2 == NULL)) { - krb5_free_tkt_authent(authdat); - *minor_status = KG_NO_SUBKEY; - return(GSS_S_FAILURE); + code = KG_NO_SUBKEY; + goto fail; } #endif @@ -267,9 +272,9 @@ krb5_gss_accept_sec_context(minor_status, context_handle, if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) || (authdat->checksum->length < 24)) { - krb5_free_authenticator(context, authdat); - *minor_status = 0; - return(GSS_S_BAD_BINDINGS); + code = 0; + major_status = GSS_S_BAD_BINDINGS; + goto fail; } /* @@ -293,33 +298,29 @@ krb5_gss_accept_sec_context(minor_status, context_handle, TREAD_INT(ptr, tmp, bigend); if (tmp != krb5_checksum_size(context, CKSUMTYPE_RSA_MD5)) { - xfree(md5.contents); - krb5_free_authenticator(context, authdat); - *minor_status = KG_BAD_LENGTH; - return(GSS_S_FAILURE); + code = KG_BAD_LENGTH; + goto fail; } } /* at this point, bigend is set according to the initiator's byte order */ if ((code = kg_checksum_channel_bindings(context, input_chan_bindings, &md5, - bigend))) { - krb5_free_authenticator(context, authdat); - *minor_status = code; - return(GSS_S_FAILURE); - } + bigend))) + goto fail; TREAD_STR(ptr, ptr2, md5.length); if (memcmp(ptr2, md5.contents, md5.length) != 0) { - xfree(md5.contents); - krb5_free_authenticator(context, authdat); - *minor_status = 0; - return(GSS_S_BAD_BINDINGS); + code = 0; + major_status = GSS_S_BAD_BINDINGS; + goto fail; } xfree(md5.contents); + md5.contents = 0; TREAD_INT(ptr, gss_flags, bigend); + decode_req_message = 0; /* if the checksum length > 24, there are options to process */ @@ -347,10 +348,8 @@ krb5_gss_accept_sec_context(minor_status, context_handle, call to rd_and_store_for_creds() and clear its flags */ if ((code = krb5_auth_con_init(context, - &auth_context_cred))) { - *minor_status = code; - return(GSS_S_FAILURE); - } + &auth_context_cred))) + goto fail; krb5_auth_con_setflags(context, auth_context_cred, 0); @@ -376,8 +375,8 @@ krb5_gss_accept_sec_context(minor_status, context_handle, if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec))) == NULL) { - *minor_status = ENOMEM; - return(GSS_S_FAILURE); + code = ENOMEM; + goto fail; } memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec)); @@ -388,55 +387,41 @@ krb5_gss_accept_sec_context(minor_status, context_handle, ctx->seed_init = 0; ctx->big_endian = bigend; - if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) { - xfree(ctx); - krb5_free_authenticator(context, authdat); - *minor_status = code; - return(GSS_S_FAILURE); + /* Intern the ctx pointer so that delete_sec_context works */ + if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) { + code = G_VALIDATE_FAILED; + xfree(ctx); + ctx = 0; + goto fail; } + + if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) + goto fail; - code = krb5_copy_principal(context, authdat->client, &ctx->there); + if ((code = krb5_copy_principal(context, authdat->client, &ctx->there))) + goto fail; /* done with authdat */ krb5_free_authenticator(context, authdat); - - if (code) { - krb5_free_principal(context, ctx->here); - xfree(ctx); - *minor_status = code; - return(GSS_S_FAILURE); - } + authdat = 0; if ((code = krb5_auth_con_getremotesubkey(context, auth_context, - &ctx->subkey))) { - krb5_free_principal(context, ctx->there); - krb5_free_principal(context, ctx->here); - xfree(ctx); - *minor_status = code; - return(GSS_S_FAILURE); - } + &ctx->subkey))) + goto fail; /* use the session key if the subkey isn't present */ if (ctx->subkey == NULL) { if ((code = krb5_auth_con_getkey(context, auth_context, - &ctx->subkey))) { - krb5_free_principal(context, ctx->there); - krb5_free_principal(context, ctx->here); - xfree(ctx); - *minor_status = code; - return(GSS_S_FAILURE); - } + &ctx->subkey))) + goto fail; } if (ctx->subkey == NULL) { - krb5_free_principal(context, ctx->there); - krb5_free_principal(context, ctx->here); - xfree(ctx); /* this isn't a very good error, but it's not clear to me this can actually happen */ - *minor_status = KRB5KDC_ERR_NULL_KEY; - return(GSS_S_FAILURE); + code = KRB5KDC_ERR_NULL_KEY; + goto fail; } switch(ctx->subkey->enctype) { @@ -456,7 +441,8 @@ krb5_gss_accept_sec_context(minor_status, context_handle, break; #endif default: - return GSS_S_FAILURE; + code = KRB5_BAD_ENCTYPE; + goto fail; } /* fill in the encryption descriptors */ @@ -464,26 +450,17 @@ krb5_gss_accept_sec_context(minor_status, context_handle, krb5_use_enctype(context, &ctx->enc.eblock, enctype); ctx->enc.processed = 0; - if (code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc.key)) { - krb5_free_principal(context, ctx->there); - krb5_free_principal(context, ctx->here); - xfree(ctx); - *minor_status = code; - return(GSS_S_FAILURE); - } + if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc.key))) + goto fail; + for (i=0; ienc.key->length; i++) /*SUPPRESS 113*/ ctx->enc.key->contents[i] ^= 0xf0; krb5_use_enctype(context, &ctx->seq.eblock, enctype); ctx->seq.processed = 0; - if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq.key))) { - krb5_free_principal(context, ctx->there); - krb5_free_principal(context, ctx->here); - xfree(ctx); - *minor_status = code; - return(GSS_S_FAILURE); - } + if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq.key))) + goto fail; ctx->endtime = ticket->enc_part2->times.endtime; ctx->krb_flags = ticket->enc_part2->flags; @@ -492,20 +469,13 @@ krb5_gss_accept_sec_context(minor_status, context_handle, krb5_auth_con_getremoteseqnumber(context, auth_context, &ctx->seq_recv); - if ((code = krb5_timeofday(context, &now))) { - krb5_free_principal(context, ctx->there); - krb5_free_principal(context, ctx->here); - xfree(ctx); - *minor_status = code; - return(GSS_S_FAILURE); - } + if ((code = krb5_timeofday(context, &now))) + goto fail; if (ctx->endtime < now) { - krb5_free_principal(context, ctx->there); - krb5_free_principal(context, ctx->here); - xfree(ctx); - *minor_status = 0; - return(GSS_S_CREDENTIALS_EXPIRED); + code = 0; + major_status = GSS_S_CREDENTIALS_EXPIRED; + goto fail; } g_order_init(&(ctx->seqstate), ctx->seq_recv, @@ -520,20 +490,15 @@ krb5_gss_accept_sec_context(minor_status, context_handle, if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) { krb5_data ap_rep; unsigned char * ptr; - if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) { - (void)krb5_gss_delete_sec_context(minor_status, - (gss_ctx_id_t *) &ctx, NULL); - *minor_status = code; - return(GSS_S_FAILURE); - } + if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) + goto fail; + krb5_auth_con_getlocalseqnumber(context, auth_context, &ctx->seq_send); token.length = g_token_size((gss_OID) mech_used, ap_rep.length); if ((token.value = (unsigned char *) xmalloc(token.length)) == NULL) { - (void)krb5_gss_delete_sec_context(minor_status, - (gss_ctx_id_t *) &ctx, NULL); - *minor_status = ENOMEM; - return(GSS_S_FAILURE); + code = ENOMEM; + goto fail; } ptr = token.value; g_make_token_header((gss_OID) mech_used, ap_rep.length, @@ -550,13 +515,12 @@ krb5_gss_accept_sec_context(minor_status, context_handle, /* set the return arguments */ if (src_name) { - if ((code = krb5_copy_principal(context, ctx->there, &name))) { - if (token.value) - xfree(token.value); - (void)krb5_gss_delete_sec_context(minor_status, - (gss_ctx_id_t *) &ctx, NULL); - *minor_status = code; - return(GSS_S_FAILURE); + if ((code = krb5_copy_principal(context, ctx->there, &name))) + goto fail; + /* intern the src_name */ + if (! kg_save_name((gss_name_t) name)) { + code = G_VALIDATE_FAILED; + goto fail; } } @@ -570,37 +534,7 @@ krb5_gss_accept_sec_context(minor_status, context_handle, *ret_flags = ctx->gss_flags; ctx->established = 1; - - /* intern the src_name */ - - if (src_name) - if (! kg_save_name((gss_name_t) name)) { - krb5_free_principal(context, name); - if (token.value) - xfree(token.value); - (void)krb5_gss_delete_sec_context(minor_status, - (gss_ctx_id_t *) &ctx, NULL); - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - return(GSS_S_FAILURE); - } - - /* intern the context handle */ - - if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) { - if (src_name) { - (void) kg_delete_name((gss_name_t) name); - krb5_free_principal(context, name); - } - if (token.value) - xfree(token.value); - (void)krb5_gss_delete_sec_context(minor_status, - (gss_ctx_id_t *) &ctx, NULL); - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - return(GSS_S_FAILURE); - } - *context_handle = ctx; - *output_token = token; if (src_name) @@ -610,4 +544,73 @@ krb5_gss_accept_sec_context(minor_status, context_handle, *minor_status = 0; return(GSS_S_COMPLETE); + +fail: + if (authdat) + krb5_free_authenticator(context, authdat); + if (ctx) + (void) krb5_gss_delete_sec_context(minor_status, + (gss_ctx_id_t *) &ctx, NULL); + if (token.value) + xfree(token.value); + if (name) { + (void) kg_delete_name((gss_name_t) name); + krb5_free_principal(context, name); + } + if (md5.contents) + xfree(md5.contents); + + *minor_status = code; + + /* + * If decode_req_message is set, then we need to decode the ap_req + * message to determine whether or not to send a response token. + * We need to do this because for some errors we won't be able to + * decode the authenticator to read out the gss_flags field. + */ + if (decode_req_message) { + krb5_ap_req * request; + + if (decode_krb5_ap_req(&ap_req, &request)) + return (major_status); + if (request->ap_options & AP_OPTS_MUTUAL_REQUIRED) + gss_flags |= GSS_C_MUTUAL_FLAG; + krb5_free_ap_req(context, request); + } + + if (gss_flags & GSS_C_MUTUAL_FLAG) { + /* + * The client is expecting a response, so we can send an + * error token back + */ + memset(&krb_error_data, 0, sizeof(krb_error_data)); + + code -= ERROR_TABLE_BASE_krb5; + if (code < 0 || code > 128) + code = 60 /* KRB_ERR_GENERIC */; + + krb_error_data.error = code; + (void) krb5_us_timeofday(context, &krb_error_data.stime, + &krb_error_data.susec); + krb_error_data.server = cred->princ; + + code = krb5_mk_error(context, &krb_error_data, &scratch); + if (code) + return (major_status); + + token.length = g_token_size((gss_OID) mech_used, scratch.length); + token.value = (unsigned char *) xmalloc(token.length); + if (!token.value) + return (major_status); + + ptr = token.value; + g_make_token_header((gss_OID) mech_used, scratch.length, + &ptr, KG_TOK_CTX_ERROR); + + TWRITE_STR(ptr, scratch.data, scratch.length); + xfree(scratch.data); + + *output_token = token; + } + return (major_status); } diff --git a/src/lib/gssapi/krb5/delete_sec_context.c b/src/lib/gssapi/krb5/delete_sec_context.c index b38dfbed5..9a9e07ce5 100644 --- a/src/lib/gssapi/krb5/delete_sec_context.c +++ b/src/lib/gssapi/krb5/delete_sec_context.c @@ -82,15 +82,20 @@ krb5_gss_delete_sec_context(minor_status, context_handle, output_token) if (ctx->enc.processed) krb5_finish_key(context, &ctx->enc.eblock); - krb5_free_keyblock(context, ctx->enc.key); + if (ctx->enc.key) + krb5_free_keyblock(context, ctx->enc.key); if (ctx->seq.processed) krb5_finish_key(context, &ctx->seq.eblock); - krb5_free_keyblock(context, ctx->seq.key); - - krb5_free_principal(context, ctx->here); - krb5_free_principal(context, ctx->there); - krb5_free_keyblock(context, ctx->subkey); + if (ctx->seq.key) + krb5_free_keyblock(context, ctx->seq.key); + + if (ctx->here) + krb5_free_principal(context, ctx->here); + if (ctx->there) + krb5_free_principal(context, ctx->there); + if (ctx->subkey) + krb5_free_keyblock(context, ctx->subkey); if (ctx->auth_context) krb5_auth_con_free(context, ctx->auth_context); diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c index 1c6d00a2c..ac6ffa232 100644 --- a/src/lib/gssapi/krb5/init_sec_context.c +++ b/src/lib/gssapi/krb5/init_sec_context.c @@ -207,6 +207,10 @@ cleanup: return (code); } +#define IS_KRB_ERROR(dat)\ + ((dat) && (dat)->length && ((dat)->data[0] == 0x7e ||\ + (dat)->data[0] == 0x5e)) + OM_uint32 krb5_gss_init_sec_context(minor_status, claimant_cred_handle, context_handle, target_name, mech_type, @@ -466,6 +470,7 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, char *sptr; krb5_data ap_rep; krb5_ap_rep_enc_part *ap_rep_data; + krb5_error *krb_error; /* validate the context handle */ /*SUPPRESS 29*/ @@ -511,29 +516,45 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, if ((err = g_verify_token_header((gss_OID) mech_type, &(ap_rep.length), &ptr, KG_TOK_CTX_AP_REP, input_token->length))) { - *minor_status = err; - return(GSS_S_DEFECTIVE_TOKEN); + if (g_verify_token_header((gss_OID) mech_type, &(ap_rep.length), + &ptr, KG_TOK_CTX_ERROR, + input_token->length) == 0) { + + /* Handle a KRB_ERROR message from the server */ + + 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 = err; + return(GSS_S_DEFECTIVE_TOKEN); + } } 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))) { - (void)krb5_gss_delete_sec_context(minor_status, - context_handle, NULL); - *minor_status = code; - return(GSS_S_FAILURE); - } - } + /* 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; + } /* store away the sequence number */ ctx->seq_recv = ap_rep_data->seq_number; @@ -550,12 +571,8 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, /* set returns */ if (time_rec) { - if ((code = krb5_timeofday(context, &now))) { - (void)krb5_gss_delete_sec_context(minor_status, - (gss_ctx_id_t) ctx, NULL); - *minor_status = code; - return(GSS_S_FAILURE); - } + if ((code = krb5_timeofday(context, &now))) + goto fail; *time_rec = ctx->endtime - now; } @@ -572,4 +589,10 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, } return(GSS_S_COMPLETE); + +fail: + (void)krb5_gss_delete_sec_context(minor_status, + (gss_ctx_id_t) ctx, NULL); + *minor_status = code; + return(GSS_S_FAILURE); }