CVE-2017-11462: Double Free (CWE-415)
value: Double free vulnerability in MIT Kerberos 5 (aka krb5) allows attackers to have unspecified impact via vectors involving automatic deletion of security contexts on error.
CWE description: The product calls free() twice on the same memory address, potentially leading to modification of unexpected memory locations.
CVSS v3 base score: 9.8
Published: 2017-09-13T16:29Z
Repository: https://github.com/krb5/krb5
Language: C
Files changed: src/lib/gssapi/mechglue/g_accept_sec_context.c, src/lib/gssapi/mechglue/g_complete_auth_token.c, src/lib/gssapi/mechglue/g_context_time.c, src/lib/gssapi/mechglue/g_delete_sec_context.c, src/lib/gssapi/mechglue/g_exp_sec_context.c, src/lib/gssapi/mechglue/g_init_sec_context.c, src/lib/gssapi/mechglue/g_inq_context.c, src/lib/gssapi/mechglue/g_prf.c, src/lib/gssapi/mechglue/g_process_context.c, src/lib/gssapi/mechglue/g_seal.c, src/lib/gssapi/mechglue/g_sign.c, src/lib/gssapi/mechglue/g_unseal.c, src/lib/gssapi/mechglue/g_unwrap_aead.c, src/lib/gssapi/mechglue/g_unwrap_iov.c, src/lib/gssapi/mechglue/g_verify.c, src/lib/gssapi/mechglue/g_wrap_aead.c, src/lib/gssapi/mechglue/g_wrap_iov.c
Commit date: 2017-08-28 11:50:30 -0400
Commit message: Preserve GSS context on init/accept failure

After gss_init_sec_context() or gss_accept_sec_context() has created a
context, don't delete the mechglue context on failures from subsequent
calls, even if the mechanism deletes the mech-specific context (which
is allowed by RFC 2744 but not preferred).  Check for union contexts
with no mechanism context in each GSS function which accepts a
gss_ctx_id_t.

CVE-2017-11462:

RFC 2744 permits a GSS-API implementation to delete an existing
security context on a second or subsequent call to
gss_init_sec_context() or gss_accept_sec_context() if the call results
in an error.  This API behavior has been found to be dangerous,
leading to the possibility of memory errors in some callers.  For
safety, GSS-API implementations should instead preserve existing
security contexts on error until the caller deletes them.

All versions of MIT krb5 prior to this change may delete acceptor
contexts on error.  Versions 1.13.4 through 1.13.7, 1.14.1 through
1.14.5, and 1.15 through 1.15.1 may also delete initiator contexts on
error.

ticket: 8598 (new)
target_version: 1.15-next
target_version: 1.14-next
tags: pullup

Diff: diff --git a/src/lib/gssapi/mechglue/g_accept_sec_context.c b/src/lib/gssapi/mechglue/g_accept_sec_context.c
index ddaf87412e9..f28e2b14a90 100644
--- a/src/lib/gssapi/mechglue/g_accept_sec_context.c
+++ b/src/lib/gssapi/mechglue/g_accept_sec_context.c
@@ -214,10 +214,12 @@ gss_cred_id_t *		d_cred;
 	}
 
     } else {
 	union_ctx_id = (gss_union_ctx_id_t)*context_handle;
 	selected_mech = union_ctx_id->mech_type;
+	if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT)
+	    return (GSS_S_NO_CONTEXT);
     }
 
     /* Now create a new context if we didn't get one. */
     if (*context_handle == GSS_C_NO_CONTEXT) {
 	status = GSS_S_FAILURE;
@@ -232,13 +234,10 @@ gss_cred_id_t *		d_cred;
 				      &union_ctx_id->mech_type);
 	if (status != GSS_S_COMPLETE) {
 	    free(union_ctx_id);
 	    return (status);
 	}
-
-	/* set the new context handle to caller's data */
-	*context_handle = (gss_ctx_id_t)union_ctx_id;
     }
 
     /*
      * get the appropriate cred handle from the union cred struct.
      */
@@ -275,12 +274,14 @@ gss_cred_id_t *		d_cred;
 						  &temp_ret_flags,
 						  time_rec,
 					d_cred ? &tmp_d_cred : NULL);
 
 	    /* If there's more work to do, keep going... */
-	    if (status == GSS_S_CONTINUE_NEEDED)
+	    if (status == GSS_S_CONTINUE_NEEDED) {
+		*context_handle = (gss_ctx_id_t)union_ctx_id;
 		return GSS_S_CONTINUE_NEEDED;
+	    }
 
 	    /* if the call failed, return with failure */
 	    if (status != GSS_S_COMPLETE) {
 		map_error(minor_status, mech);
 		goto error_out;
@@ -362,18 +363,26 @@ gss_cred_id_t *		d_cred;
 
 	    if (mech_type != NULL)
 		*mech_type = gssint_get_public_oid(actual_mech);
 	    if (ret_flags != NULL)
 		*ret_flags = temp_ret_flags;
-	    return	(status);
+	    *context_handle = (gss_ctx_id_t)union_ctx_id;
+	    return GSS_S_COMPLETE;
     } else {
 
 	status = GSS_S_BAD_MECH;
     }
 
 error_out:
-    if (union_ctx_id) {
+	/*
+	 * RFC 2744 5.1 requires that we not create a context on a failed first
+	 * call to accept, and recommends that on a failed subsequent call we
+	 * make the caller responsible for calling gss_delete_sec_context.
+	 * Even if the mech deleted its context, keep the union context around
+	 * for the caller to delete.
+	 */
+    if (union_ctx_id && *context_handle == GSS_C_NO_CONTEXT) {
 	if (union_ctx_id->mech_type) {
 	    if (union_ctx_id->mech_type->elements)
 		free(union_ctx_id->mech_type->elements);
 	    free(union_ctx_id->mech_type);
 	}
@@ -382,11 +391,10 @@ error_out:
 	    mech->gss_delete_sec_context(&temp_minor_status,
 					 &union_ctx_id->internal_ctx_id,
 					 GSS_C_NO_BUFFER);
 	}
 	free(union_ctx_id);
-	*context_handle = GSS_C_NO_CONTEXT;
     }
 
     if (src_name)
 	*src_name = GSS_C_NO_NAME;
 
diff --git a/src/lib/gssapi/mechglue/g_complete_auth_token.c b/src/lib/gssapi/mechglue/g_complete_auth_token.c
index 91815513017..4bcb47e84b9 100644
--- a/src/lib/gssapi/mechglue/g_complete_auth_token.c
+++ b/src/lib/gssapi/mechglue/g_complete_auth_token.c
@@ -50,10 +50,12 @@ gss_complete_auth_token (OM_uint32 *minor_status,
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return GSS_S_NO_CONTEXT;
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech != NULL) {
 	if (mech->gss_complete_auth_token != NULL) {
 	    status = mech->gss_complete_auth_token(minor_status,
diff --git a/src/lib/gssapi/mechglue/g_context_time.c b/src/lib/gssapi/mechglue/g_context_time.c
index 2ff8d0996ef..c947e7646c1 100644
--- a/src/lib/gssapi/mechglue/g_context_time.c
+++ b/src/lib/gssapi/mechglue/g_context_time.c
@@ -56,10 +56,12 @@ OM_uint32 *		time_rec;
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
 
 	if (mech->gss_context_time) {
diff --git a/src/lib/gssapi/mechglue/g_delete_sec_context.c b/src/lib/gssapi/mechglue/g_delete_sec_context.c
index 4bf0dec5ce3..574ff02944b 100644
--- a/src/lib/gssapi/mechglue/g_delete_sec_context.c
+++ b/src/lib/gssapi/mechglue/g_delete_sec_context.c
@@ -85,16 +85,18 @@ gss_buffer_t		output_token;
 
     ctx = (gss_union_ctx_id_t) *context_handle;
     if (GSSINT_CHK_LOOP(ctx))
 	return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT);
 
-    status = gssint_delete_internal_sec_context(minor_status,
-						ctx->mech_type,
-						&ctx->internal_ctx_id,
-						output_token);
-    if (status)
-	return status;
+    if (ctx->internal_ctx_id != GSS_C_NO_CONTEXT) {
+	status = gssint_delete_internal_sec_context(minor_status,
+						    ctx->mech_type,
+						    &ctx->internal_ctx_id,
+						    output_token);
+	if (status)
+	    return status;
+    }
 
     /* now free up the space for the union context structure */
     free(ctx->mech_type->elements);
     free(ctx->mech_type);
     free(*context_handle);
diff --git a/src/lib/gssapi/mechglue/g_exp_sec_context.c b/src/lib/gssapi/mechglue/g_exp_sec_context.c
index b63745299f6..1d7990b1ca2 100644
--- a/src/lib/gssapi/mechglue/g_exp_sec_context.c
+++ b/src/lib/gssapi/mechglue/g_exp_sec_context.c
@@ -93,10 +93,12 @@ gss_buffer_t		interprocess_token;
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) *context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
     if (!mech)
 	return GSS_S_BAD_MECH;
     if (!mech->gss_export_sec_context)
 	return (GSS_S_UNAVAILABLE);
diff --git a/src/lib/gssapi/mechglue/g_init_sec_context.c b/src/lib/gssapi/mechglue/g_init_sec_context.c
index 9f154b8936d..e2df1ce261d 100644
--- a/src/lib/gssapi/mechglue/g_init_sec_context.c
+++ b/src/lib/gssapi/mechglue/g_init_sec_context.c
@@ -190,12 +190,17 @@ OM_uint32 *		time_rec;
 	    goto end;
 	}
 
 	/* copy the supplied context handle */
 	union_ctx_id->internal_ctx_id = GSS_C_NO_CONTEXT;
-    } else
+    } else {
 	union_ctx_id = (gss_union_ctx_id_t)*context_handle;
+	if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT) {
+	    status = GSS_S_NO_CONTEXT;
+	    goto end;
+	}
+    }
 
     /*
      * get the appropriate cred handle from the union cred struct.
      * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will
      * use the default credential.
@@ -222,19 +227,17 @@ OM_uint32 *		time_rec;
 	ret_flags,
 	time_rec);
 
     if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
 	/*
-	 * The spec says the preferred method is to delete all context info on
-	 * the first call to init, and on all subsequent calls make the caller
-	 * responsible for calling gss_delete_sec_context.  However, if the
-	 * mechanism decided to delete the internal context, we should also
-	 * delete the union context.
+	 * RFC 2744 5.19 requires that we not create a context on a failed
+	 * first call to init, and recommends that on a failed subsequent call
+	 * we make the caller responsible for calling gss_delete_sec_context.
+	 * Even if the mech deleted its context, keep the union context around
+	 * for the caller to delete.
 	 */
 	map_error(minor_status, mech);
-	if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT)
-	    *context_handle = GSS_C_NO_CONTEXT;
 	if (*context_handle == GSS_C_NO_CONTEXT) {
 	    free(union_ctx_id->mech_type->elements);
 	    free(union_ctx_id->mech_type);
 	    free(union_ctx_id);
 	}
diff --git a/src/lib/gssapi/mechglue/g_inq_context.c b/src/lib/gssapi/mechglue/g_inq_context.c
index 6f1c71eede9..6c0d98dd334 100644
--- a/src/lib/gssapi/mechglue/g_inq_context.c
+++ b/src/lib/gssapi/mechglue/g_inq_context.c
@@ -102,10 +102,12 @@ gss_inquire_context(
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (!mech || !mech->gss_inquire_context || !mech->gss_display_name ||
 	!mech->gss_release_name) {
 	return (GSS_S_UNAVAILABLE);
diff --git a/src/lib/gssapi/mechglue/g_prf.c b/src/lib/gssapi/mechglue/g_prf.c
index fcca3e44c4c..9e168adfe0d 100644
--- a/src/lib/gssapi/mechglue/g_prf.c
+++ b/src/lib/gssapi/mechglue/g_prf.c
@@ -57,10 +57,12 @@ gss_pseudo_random (OM_uint32 *minor_status,
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return GSS_S_NO_CONTEXT;
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech != NULL) {
 	if (mech->gss_pseudo_random != NULL) {
 	    status = mech->gss_pseudo_random(minor_status,
diff --git a/src/lib/gssapi/mechglue/g_process_context.c b/src/lib/gssapi/mechglue/g_process_context.c
index bc260aeb10b..3968b5d9c67 100644
--- a/src/lib/gssapi/mechglue/g_process_context.c
+++ b/src/lib/gssapi/mechglue/g_process_context.c
@@ -59,10 +59,12 @@ gss_buffer_t		token_buffer;
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
 
 	if (mech->gss_process_context_token) {
diff --git a/src/lib/gssapi/mechglue/g_seal.c b/src/lib/gssapi/mechglue/g_seal.c
index f17241c9089..3db1ee095b3 100644
--- a/src/lib/gssapi/mechglue/g_seal.c
+++ b/src/lib/gssapi/mechglue/g_seal.c
@@ -90,10 +90,12 @@ gss_wrap( OM_uint32 *minor_status,
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+        return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
         if (mech->gss_wrap) {
             status = mech->gss_wrap(minor_status,
@@ -224,10 +226,12 @@ gss_wrap_size_limit(OM_uint32  *minor_status,
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+        return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (!mech)
         return (GSS_S_BAD_MECH);
 
diff --git a/src/lib/gssapi/mechglue/g_sign.c b/src/lib/gssapi/mechglue/g_sign.c
index 86d641aa2e2..03fbd8c01f3 100644
--- a/src/lib/gssapi/mechglue/g_sign.c
+++ b/src/lib/gssapi/mechglue/g_sign.c
@@ -92,10 +92,12 @@ gss_buffer_t		msg_token;
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
 	if (mech->gss_get_mic) {
 	    status = mech->gss_get_mic(
diff --git a/src/lib/gssapi/mechglue/g_unseal.c b/src/lib/gssapi/mechglue/g_unseal.c
index 3e8053c6e9a..c208635b676 100644
--- a/src/lib/gssapi/mechglue/g_unseal.c
+++ b/src/lib/gssapi/mechglue/g_unseal.c
@@ -74,10 +74,12 @@ gss_qop_t *		qop_state;
     /*
      * select the approprate underlying mechanism routine and
      * call it.
      */
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
 	if (mech->gss_unwrap) {
 	    status = mech->gss_unwrap(minor_status,
diff --git a/src/lib/gssapi/mechglue/g_unwrap_aead.c b/src/lib/gssapi/mechglue/g_unwrap_aead.c
index e78bff2d328..0682bd89982 100644
--- a/src/lib/gssapi/mechglue/g_unwrap_aead.c
+++ b/src/lib/gssapi/mechglue/g_unwrap_aead.c
@@ -184,10 +184,12 @@ gss_qop_t		*qop_state;
     /*
      * select the approprate underlying mechanism routine and
      * call it.
      */
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (!mech)
 	return (GSS_S_BAD_MECH);
 
diff --git a/src/lib/gssapi/mechglue/g_unwrap_iov.c b/src/lib/gssapi/mechglue/g_unwrap_iov.c
index c0dd314b1be..599be2c7b2f 100644
--- a/src/lib/gssapi/mechglue/g_unwrap_iov.c
+++ b/src/lib/gssapi/mechglue/g_unwrap_iov.c
@@ -87,10 +87,12 @@ int			iov_count;
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
 	if (mech->gss_unwrap_iov) {
 	    status = mech->gss_unwrap_iov(
@@ -126,10 +128,12 @@ gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
     if (status != GSS_S_COMPLETE)
 	return status;
 
     /* Select the approprate underlying mechanism routine and call it. */
     ctx = (gss_union_ctx_id_t)context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return GSS_S_NO_CONTEXT;
     mech = gssint_get_mechanism(ctx->mech_type);
     if (mech == NULL)
 	return GSS_S_BAD_MECH;
     if (mech->gss_verify_mic_iov == NULL)
 	return GSS_S_UNAVAILABLE;
diff --git a/src/lib/gssapi/mechglue/g_verify.c b/src/lib/gssapi/mechglue/g_verify.c
index 1578ae11109..8996fce8d59 100644
--- a/src/lib/gssapi/mechglue/g_verify.c
+++ b/src/lib/gssapi/mechglue/g_verify.c
@@ -63,10 +63,12 @@ gss_qop_t *		qop_state;
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
 	if (mech->gss_verify_mic) {
 	    status = mech->gss_verify_mic(
diff --git a/src/lib/gssapi/mechglue/g_wrap_aead.c b/src/lib/gssapi/mechglue/g_wrap_aead.c
index 96cdf3ce6ab..7fe3b7b35bd 100644
--- a/src/lib/gssapi/mechglue/g_wrap_aead.c
+++ b/src/lib/gssapi/mechglue/g_wrap_aead.c
@@ -254,10 +254,12 @@ gss_buffer_t		output_message_buffer;
     /*
      * select the approprate underlying mechanism routine and
      * call it.
      */
     ctx = (gss_union_ctx_id_t)context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
     if (!mech)
 	return (GSS_S_BAD_MECH);
 
     return gssint_wrap_aead(mech, minor_status, ctx,
diff --git a/src/lib/gssapi/mechglue/g_wrap_iov.c b/src/lib/gssapi/mechglue/g_wrap_iov.c
index 40cd98fc91c..14447c4ee1a 100644
--- a/src/lib/gssapi/mechglue/g_wrap_iov.c
+++ b/src/lib/gssapi/mechglue/g_wrap_iov.c
@@ -91,10 +91,12 @@ int			iov_count;
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
 	if (mech->gss_wrap_iov) {
 	    status = mech->gss_wrap_iov(
@@ -149,10 +151,12 @@ int			iov_count;
      * select the approprate underlying mechanism routine and
      * call it.
      */
 
     ctx = (gss_union_ctx_id_t) context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return (GSS_S_NO_CONTEXT);
     mech = gssint_get_mechanism (ctx->mech_type);
 
     if (mech) {
 	if (mech->gss_wrap_iov_length) {
 	    status = mech->gss_wrap_iov_length(
@@ -188,10 +192,12 @@ gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
     if (status != GSS_S_COMPLETE)
 	return status;
 
     /* Select the approprate underlying mechanism routine and call it. */
     ctx = (gss_union_ctx_id_t)context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return GSS_S_NO_CONTEXT;
     mech = gssint_get_mechanism(ctx->mech_type);
     if (mech == NULL)
 	return GSS_S_BAD_MECH;
     if (mech->gss_get_mic_iov == NULL)
 	return GSS_S_UNAVAILABLE;
@@ -216,10 +222,12 @@ gss_get_mic_iov_length(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
     if (status != GSS_S_COMPLETE)
 	return status;
 
     /* Select the approprate underlying mechanism routine and call it. */
     ctx = (gss_union_ctx_id_t)context_handle;
+    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
+	return GSS_S_NO_CONTEXT;
     mech = gssint_get_mechanism(ctx->mech_type);
     if (mech == NULL)
 	return GSS_S_BAD_MECH;
     if (mech->gss_get_mic_iov_length == NULL)
 	return GSS_S_UNAVAILABLE;

Vulnerable code: 
	/* set the new context handle to caller's data */
	*context_handle = (gss_ctx_id_t)union_ctx_id;
	    if (status == GSS_S_CONTINUE_NEEDED)
	    return	(status);
    if (union_ctx_id) {
	*context_handle = GSS_C_NO_CONTEXT;
    status = gssint_delete_internal_sec_context(minor_status,
						ctx->mech_type,
						&ctx->internal_ctx_id,
						output_token);
    if (status)
	return status;
    } else
	 * The spec says the preferred method is to delete all context info on
	 * the first call to init, and on all subsequent calls make the caller
	 * responsible for calling gss_delete_sec_context.  However, if the
	 * mechanism decided to delete the internal context, we should also
	 * delete the union context.
	if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT)
	    *context_handle = GSS_C_NO_CONTEXT;
Fixed code: 	if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT)
	    return (GSS_S_NO_CONTEXT);
	    if (status == GSS_S_CONTINUE_NEEDED) {
		*context_handle = (gss_ctx_id_t)union_ctx_id;
	    }
	    *context_handle = (gss_ctx_id_t)union_ctx_id;
	    return GSS_S_COMPLETE;
	/*
	 * RFC 2744 5.1 requires that we not create a context on a failed first
	 * call to accept, and recommends that on a failed subsequent call we
	 * make the caller responsible for calling gss_delete_sec_context.
	 * Even if the mech deleted its context, keep the union context around
	 * for the caller to delete.
	 */
    if (union_ctx_id && *context_handle == GSS_C_NO_CONTEXT) {
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return GSS_S_NO_CONTEXT;
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id != GSS_C_NO_CONTEXT) {
	status = gssint_delete_internal_sec_context(minor_status,
						    ctx->mech_type,
						    &ctx->internal_ctx_id,
						    output_token);
	if (status)
	    return status;
    }
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return (GSS_S_NO_CONTEXT);
    } else {
	if (union_ctx_id->internal_ctx_id == GSS_C_NO_CONTEXT) {
	    status = GSS_S_NO_CONTEXT;
	    goto end;
	}
    }
	 * RFC 2744 5.19 requires that we not create a context on a failed
	 * first call to init, and recommends that on a failed subsequent call
	 * we make the caller responsible for calling gss_delete_sec_context.
	 * Even if the mech deleted its context, keep the union context around
	 * for the caller to delete.
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return GSS_S_NO_CONTEXT;
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
        return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
        return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return GSS_S_NO_CONTEXT;
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return (GSS_S_NO_CONTEXT);
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return GSS_S_NO_CONTEXT;
    if (ctx->internal_ctx_id == GSS_C_NO_CONTEXT)
	return GSS_S_NO_CONTEXT;