fixes from Stefan Metzmacher
[heimdal.git] / lib / gssapi / krb5 / init_sec_context.c
blob3de4d9575ea426b48c94f0813bed023c0a55ecd1
1 /*
2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "krb5/gsskrb5_locl.h"
36 RCSID("$Id$");
39 * copy the addresses from `input_chan_bindings' (if any) to
40 * the auth context `ac'
43 static OM_uint32
44 set_addresses (krb5_context context,
45 krb5_auth_context ac,
46 const gss_channel_bindings_t input_chan_bindings)
48 /* Port numbers are expected to be in application_data.value,
49 * initator's port first */
51 krb5_address initiator_addr, acceptor_addr;
52 krb5_error_code kret;
54 if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS
55 || input_chan_bindings->application_data.length !=
56 2 * sizeof(ac->local_port))
57 return 0;
59 memset(&initiator_addr, 0, sizeof(initiator_addr));
60 memset(&acceptor_addr, 0, sizeof(acceptor_addr));
62 ac->local_port =
63 *(int16_t *) input_chan_bindings->application_data.value;
65 ac->remote_port =
66 *((int16_t *) input_chan_bindings->application_data.value + 1);
68 kret = _gsskrb5i_address_to_krb5addr(context,
69 input_chan_bindings->acceptor_addrtype,
70 &input_chan_bindings->acceptor_address,
71 ac->remote_port,
72 &acceptor_addr);
73 if (kret)
74 return kret;
76 kret = _gsskrb5i_address_to_krb5addr(context,
77 input_chan_bindings->initiator_addrtype,
78 &input_chan_bindings->initiator_address,
79 ac->local_port,
80 &initiator_addr);
81 if (kret) {
82 krb5_free_address (context, &acceptor_addr);
83 return kret;
86 kret = krb5_auth_con_setaddrs(context,
87 ac,
88 &initiator_addr, /* local address */
89 &acceptor_addr); /* remote address */
91 krb5_free_address (context, &initiator_addr);
92 krb5_free_address (context, &acceptor_addr);
94 #if 0
95 free(input_chan_bindings->application_data.value);
96 input_chan_bindings->application_data.value = NULL;
97 input_chan_bindings->application_data.length = 0;
98 #endif
100 return kret;
103 OM_uint32
104 _gsskrb5_create_ctx(
105 OM_uint32 * minor_status,
106 gss_ctx_id_t * context_handle,
107 krb5_context context,
108 const gss_channel_bindings_t input_chan_bindings,
109 enum gss_ctx_id_t_state state)
111 krb5_error_code kret;
112 gsskrb5_ctx ctx;
114 *context_handle = NULL;
116 ctx = malloc(sizeof(*ctx));
117 if (ctx == NULL) {
118 *minor_status = ENOMEM;
119 return GSS_S_FAILURE;
121 ctx->auth_context = NULL;
122 ctx->source = NULL;
123 ctx->target = NULL;
124 ctx->state = state;
125 ctx->flags = 0;
126 ctx->more_flags = 0;
127 ctx->service_keyblock = NULL;
128 ctx->ticket = NULL;
129 krb5_data_zero(&ctx->fwd_data);
130 ctx->lifetime = GSS_C_INDEFINITE;
131 ctx->order = NULL;
132 HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
134 kret = krb5_auth_con_init (context, &ctx->auth_context);
135 if (kret) {
136 *minor_status = kret;
138 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
140 return GSS_S_FAILURE;
143 kret = set_addresses(context, ctx->auth_context, input_chan_bindings);
144 if (kret) {
145 *minor_status = kret;
147 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
149 krb5_auth_con_free(context, ctx->auth_context);
151 return GSS_S_BAD_BINDINGS;
155 * We need a sequence number
158 krb5_auth_con_addflags(context,
159 ctx->auth_context,
160 KRB5_AUTH_CONTEXT_DO_SEQUENCE |
161 KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED,
162 NULL);
164 *context_handle = (gss_ctx_id_t)ctx;
166 return GSS_S_COMPLETE;
170 static OM_uint32
171 gsskrb5_get_creds(
172 OM_uint32 * minor_status,
173 krb5_context context,
174 krb5_ccache ccache,
175 gsskrb5_ctx ctx,
176 krb5_const_principal target_name,
177 OM_uint32 time_req,
178 OM_uint32 * time_rec,
179 krb5_creds ** cred)
181 OM_uint32 ret;
182 krb5_error_code kret;
183 krb5_creds this_cred;
184 OM_uint32 lifetime_rec;
186 *cred = NULL;
188 memset(&this_cred, 0, sizeof(this_cred));
189 this_cred.client = ctx->source;
190 this_cred.server = ctx->target;
192 if (time_req && time_req != GSS_C_INDEFINITE) {
193 krb5_timestamp ts;
195 krb5_timeofday (context, &ts);
196 this_cred.times.endtime = ts + time_req;
197 } else {
198 this_cred.times.endtime = 0;
201 this_cred.session.keytype = KEYTYPE_NULL;
203 kret = krb5_get_credentials(context,
205 ccache,
206 &this_cred,
207 cred);
208 if (kret) {
209 *minor_status = kret;
210 return GSS_S_FAILURE;
213 ctx->lifetime = (*cred)->times.endtime;
215 ret = _gsskrb5_lifetime_left(minor_status, context,
216 ctx->lifetime, &lifetime_rec);
217 if (ret) return ret;
219 if (lifetime_rec == 0) {
220 *minor_status = 0;
221 return GSS_S_CONTEXT_EXPIRED;
224 if (time_rec) *time_rec = lifetime_rec;
226 return GSS_S_COMPLETE;
229 static OM_uint32
230 gsskrb5_initiator_ready(
231 OM_uint32 * minor_status,
232 gsskrb5_ctx ctx,
233 krb5_context context)
235 OM_uint32 ret;
236 int32_t seq_number;
237 int is_cfx = 0;
238 OM_uint32 flags = ctx->flags;
240 krb5_auth_getremoteseqnumber (context,
241 ctx->auth_context,
242 &seq_number);
244 _gsskrb5i_is_cfx(ctx, &is_cfx);
246 ret = _gssapi_msg_order_create(minor_status,
247 &ctx->order,
248 _gssapi_msg_order_f(flags),
249 seq_number, 0, is_cfx);
250 if (ret) return ret;
252 ctx->state = INITIATOR_READY;
253 ctx->more_flags |= OPEN;
255 return GSS_S_COMPLETE;
259 * handle delegated creds in init-sec-context
262 static void
263 do_delegation (krb5_context context,
264 krb5_auth_context ac,
265 krb5_ccache ccache,
266 krb5_creds *cred,
267 krb5_const_principal name,
268 krb5_data *fwd_data,
269 uint32_t *flags)
271 krb5_creds creds;
272 KDCOptions fwd_flags;
273 krb5_error_code kret;
275 memset (&creds, 0, sizeof(creds));
276 krb5_data_zero (fwd_data);
278 kret = krb5_cc_get_principal(context, ccache, &creds.client);
279 if (kret)
280 goto out;
282 kret = krb5_build_principal(context,
283 &creds.server,
284 strlen(creds.client->realm),
285 creds.client->realm,
286 KRB5_TGS_NAME,
287 creds.client->realm,
288 NULL);
289 if (kret)
290 goto out;
292 creds.times.endtime = 0;
294 memset(&fwd_flags, 0, sizeof(fwd_flags));
295 fwd_flags.forwarded = 1;
296 fwd_flags.forwardable = 1;
298 if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/
299 name->name.name_string.len < 2)
300 goto out;
302 kret = krb5_get_forwarded_creds(context,
304 ccache,
305 KDCOptions2int(fwd_flags),
306 name->name.name_string.val[1],
307 &creds,
308 fwd_data);
310 out:
311 if (kret)
312 *flags &= ~GSS_C_DELEG_FLAG;
313 else
314 *flags |= GSS_C_DELEG_FLAG;
316 if (creds.client)
317 krb5_free_principal(context, creds.client);
318 if (creds.server)
319 krb5_free_principal(context, creds.server);
323 * first stage of init-sec-context
326 static OM_uint32
327 init_auth
328 (OM_uint32 * minor_status,
329 gsskrb5_cred cred,
330 gsskrb5_ctx ctx,
331 krb5_context context,
332 krb5_const_principal name,
333 const gss_OID mech_type,
334 OM_uint32 req_flags,
335 OM_uint32 time_req,
336 const gss_channel_bindings_t input_chan_bindings,
337 const gss_buffer_t input_token,
338 gss_OID * actual_mech_type,
339 gss_buffer_t output_token,
340 OM_uint32 * ret_flags,
341 OM_uint32 * time_rec
344 OM_uint32 ret = GSS_S_FAILURE;
345 krb5_error_code kret;
346 krb5_flags ap_options;
347 krb5_creds *kcred = NULL;
348 krb5_data outbuf;
349 krb5_ccache ccache = NULL;
350 uint32_t flags;
351 krb5_data authenticator;
352 Checksum cksum;
353 krb5_enctype enctype;
354 krb5_data fwd_data;
355 OM_uint32 lifetime_rec;
357 krb5_data_zero(&outbuf);
358 krb5_data_zero(&fwd_data);
360 *minor_status = 0;
362 if (actual_mech_type)
363 *actual_mech_type = GSS_KRB5_MECHANISM;
365 if (cred == NULL) {
366 kret = krb5_cc_default (context, &ccache);
367 if (kret) {
368 *minor_status = kret;
369 ret = GSS_S_FAILURE;
370 goto failure;
372 } else
373 ccache = cred->ccache;
375 kret = krb5_cc_get_principal (context, ccache, &ctx->source);
376 if (kret) {
377 *minor_status = kret;
378 ret = GSS_S_FAILURE;
379 goto failure;
382 kret = krb5_copy_principal (context, name, &ctx->target);
383 if (kret) {
384 *minor_status = kret;
385 ret = GSS_S_FAILURE;
386 goto failure;
389 ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
390 if (ret)
391 goto failure;
395 * This is hideous glue for (NFS) clients that wants to limit the
396 * available enctypes to what it can support (encryption in
397 * kernel). If there is no enctypes selected for this credential,
398 * reset it to the default set of enctypes.
401 krb5_enctype *enctypes = NULL;
403 if (cred && cred->enctypes)
404 enctypes = cred->enctypes;
405 krb5_set_default_in_tkt_etypes(context, enctypes);
408 ret = gsskrb5_get_creds(minor_status,
409 context,
410 ccache,
411 ctx,
412 ctx->target,
413 time_req,
414 time_rec,
415 &kcred);
416 if (ret)
417 goto failure;
419 ctx->lifetime = kcred->times.endtime;
421 ret = _gsskrb5_lifetime_left(minor_status,
422 context,
423 ctx->lifetime,
424 &lifetime_rec);
425 if (ret) {
426 goto failure;
429 if (lifetime_rec == 0) {
430 *minor_status = 0;
431 ret = GSS_S_CONTEXT_EXPIRED;
432 goto failure;
435 krb5_auth_con_setkey(context,
436 ctx->auth_context,
437 &kcred->session);
439 kret = krb5_auth_con_generatelocalsubkey(context,
440 ctx->auth_context,
441 &kcred->session);
442 if(kret) {
443 *minor_status = kret;
444 ret = GSS_S_FAILURE;
445 goto failure;
449 * If the credential doesn't have ok-as-delegate, check what local
450 * policy say about ok-as-delegate, default is FALSE that makes
451 * code ignore the KDC setting and follow what the application
452 * requested. If it is TRUE, strip of the GSS_C_DELEG_FLAG if the
453 * KDC doesn't set ok-as-delegate.
455 if (!kcred->flags.b.ok_as_delegate) {
456 krb5_boolean delegate;
458 krb5_appdefault_boolean(context,
459 "gssapi", name->realm,
460 "ok-as-delegate", FALSE, &delegate);
461 if (delegate)
462 req_flags &= ~GSS_C_DELEG_FLAG;
465 flags = 0;
466 ap_options = 0;
467 if (req_flags & GSS_C_DELEG_FLAG)
468 do_delegation (context,
469 ctx->auth_context,
470 ccache, kcred, name, &fwd_data, &flags);
472 if (req_flags & GSS_C_MUTUAL_FLAG) {
473 flags |= GSS_C_MUTUAL_FLAG;
474 ap_options |= AP_OPTS_MUTUAL_REQUIRED;
477 if (req_flags & GSS_C_REPLAY_FLAG)
478 flags |= GSS_C_REPLAY_FLAG;
479 if (req_flags & GSS_C_SEQUENCE_FLAG)
480 flags |= GSS_C_SEQUENCE_FLAG;
481 if (req_flags & GSS_C_ANON_FLAG)
482 ; /* XXX */
483 if (req_flags & GSS_C_DCE_STYLE) {
484 /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */
485 flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG;
486 ap_options |= AP_OPTS_MUTUAL_REQUIRED;
488 if (req_flags & GSS_C_IDENTIFY_FLAG)
489 flags |= GSS_C_IDENTIFY_FLAG;
490 if (req_flags & GSS_C_EXTENDED_ERROR_FLAG)
491 flags |= GSS_C_EXTENDED_ERROR_FLAG;
493 if (req_flags & GSS_C_CONF_FLAG) {
494 flags |= GSS_C_CONF_FLAG;
496 if (req_flags & GSS_C_INTEG_FLAG) {
497 flags |= GSS_C_INTEG_FLAG;
499 if (cred == NULL || !(cred->cred_flags & GSS_CF_NO_CI_FLAGS)) {
500 flags |= GSS_C_CONF_FLAG;
501 flags |= GSS_C_INTEG_FLAG;
503 flags |= GSS_C_TRANS_FLAG;
505 if (ret_flags)
506 *ret_flags = flags;
507 ctx->flags = flags;
508 ctx->more_flags |= LOCAL;
510 ret = _gsskrb5_create_8003_checksum (minor_status,
511 input_chan_bindings,
512 flags,
513 &fwd_data,
514 &cksum);
515 krb5_data_free (&fwd_data);
516 if (ret)
517 goto failure;
519 enctype = ctx->auth_context->keyblock->keytype;
521 kret = krb5_build_authenticator (context,
522 ctx->auth_context,
523 enctype,
524 kcred,
525 &cksum,
526 NULL,
527 &authenticator,
528 KRB5_KU_AP_REQ_AUTH);
530 if (kret) {
531 *minor_status = kret;
532 ret = GSS_S_FAILURE;
533 goto failure;
536 kret = krb5_build_ap_req (context,
537 enctype,
538 kcred,
539 ap_options,
540 authenticator,
541 &outbuf);
543 if (kret) {
544 *minor_status = kret;
545 ret = GSS_S_FAILURE;
546 goto failure;
549 ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token,
550 (u_char *)"\x01\x00", GSS_KRB5_MECHANISM);
551 if (ret)
552 goto failure;
554 krb5_data_free (&outbuf);
555 krb5_free_creds(context, kcred);
556 free_Checksum(&cksum);
557 if (cred == NULL)
558 krb5_cc_close(context, ccache);
560 if (flags & GSS_C_MUTUAL_FLAG) {
561 ctx->state = INITIATOR_WAIT_FOR_MUTAL;
562 return GSS_S_CONTINUE_NEEDED;
565 return gsskrb5_initiator_ready(minor_status, ctx, context);
566 failure:
567 if(kcred)
568 krb5_free_creds(context, kcred);
569 if (ccache && cred == NULL)
570 krb5_cc_close(context, ccache);
572 return ret;
576 static OM_uint32
577 repl_mutual
578 (OM_uint32 * minor_status,
579 gsskrb5_ctx ctx,
580 krb5_context context,
581 const gss_OID mech_type,
582 OM_uint32 req_flags,
583 OM_uint32 time_req,
584 const gss_channel_bindings_t input_chan_bindings,
585 const gss_buffer_t input_token,
586 gss_OID * actual_mech_type,
587 gss_buffer_t output_token,
588 OM_uint32 * ret_flags,
589 OM_uint32 * time_rec
592 OM_uint32 ret;
593 krb5_error_code kret;
594 krb5_data indata;
595 krb5_ap_rep_enc_part *repl;
596 int is_cfx = 0;
598 output_token->length = 0;
599 output_token->value = NULL;
601 if (actual_mech_type)
602 *actual_mech_type = GSS_KRB5_MECHANISM;
604 if (ctx->flags & GSS_C_DCE_STYLE) {
605 /* There is no OID wrapping. */
606 indata.length = input_token->length;
607 indata.data = input_token->value;
608 } else {
609 ret = _gsskrb5_decapsulate (minor_status,
610 input_token,
611 &indata,
612 "\x02\x00",
613 GSS_KRB5_MECHANISM);
614 if (ret) {
615 /* XXX - Handle AP_ERROR */
616 return ret;
620 kret = krb5_rd_rep (context,
621 ctx->auth_context,
622 &indata,
623 &repl);
624 if (kret) {
625 *minor_status = kret;
626 return GSS_S_FAILURE;
628 krb5_free_ap_rep_enc_part (context,
629 repl);
631 _gsskrb5i_is_cfx(ctx, &is_cfx);
632 if (is_cfx) {
633 krb5_keyblock *key = NULL;
635 kret = krb5_auth_con_getremotesubkey(context,
636 ctx->auth_context,
637 &key);
638 if (kret == 0 && key != NULL) {
639 ctx->more_flags |= ACCEPTOR_SUBKEY;
640 krb5_free_keyblock (context, key);
645 *minor_status = 0;
646 if (time_rec) {
647 ret = _gsskrb5_lifetime_left(minor_status,
648 context,
649 ctx->lifetime,
650 time_rec);
651 } else {
652 ret = GSS_S_COMPLETE;
654 if (ret_flags)
655 *ret_flags = ctx->flags;
657 if (req_flags & GSS_C_DCE_STYLE) {
658 int32_t con_flags;
659 krb5_data outbuf;
661 /* Do don't do sequence number for the mk-rep */
662 krb5_auth_con_removeflags(context,
663 ctx->auth_context,
664 KRB5_AUTH_CONTEXT_DO_SEQUENCE,
665 &con_flags);
667 kret = krb5_mk_rep(context,
668 ctx->auth_context,
669 &outbuf);
670 if (kret) {
671 *minor_status = kret;
672 return GSS_S_FAILURE;
675 output_token->length = outbuf.length;
676 output_token->value = outbuf.data;
678 krb5_auth_con_removeflags(context,
679 ctx->auth_context,
680 KRB5_AUTH_CONTEXT_DO_SEQUENCE,
681 NULL);
684 return gsskrb5_initiator_ready(minor_status, ctx, context);
688 * gss_init_sec_context
691 OM_uint32 _gsskrb5_init_sec_context
692 (OM_uint32 * minor_status,
693 const gss_cred_id_t cred_handle,
694 gss_ctx_id_t * context_handle,
695 const gss_name_t target_name,
696 const gss_OID mech_type,
697 OM_uint32 req_flags,
698 OM_uint32 time_req,
699 const gss_channel_bindings_t input_chan_bindings,
700 const gss_buffer_t input_token,
701 gss_OID * actual_mech_type,
702 gss_buffer_t output_token,
703 OM_uint32 * ret_flags,
704 OM_uint32 * time_rec
707 krb5_context context;
708 gsskrb5_cred cred = (gsskrb5_cred)cred_handle;
709 krb5_const_principal name = (krb5_const_principal)target_name;
710 gsskrb5_ctx ctx;
711 OM_uint32 ret;
713 GSSAPI_KRB5_INIT (&context);
715 output_token->length = 0;
716 output_token->value = NULL;
718 if (context_handle == NULL) {
719 *minor_status = 0;
720 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
723 if (ret_flags)
724 *ret_flags = 0;
725 if (time_rec)
726 *time_rec = 0;
728 if (target_name == GSS_C_NO_NAME) {
729 if (actual_mech_type)
730 *actual_mech_type = GSS_C_NO_OID;
731 *minor_status = 0;
732 return GSS_S_BAD_NAME;
735 if (mech_type != GSS_C_NO_OID &&
736 !gss_oid_equal(mech_type, GSS_KRB5_MECHANISM))
737 return GSS_S_BAD_MECH;
739 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
740 OM_uint32 ret;
742 if (*context_handle != GSS_C_NO_CONTEXT) {
743 *minor_status = 0;
744 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
747 ret = _gsskrb5_create_ctx(minor_status,
748 context_handle,
749 context,
750 input_chan_bindings,
751 INITIATOR_START);
752 if (ret)
753 return ret;
756 if (*context_handle == GSS_C_NO_CONTEXT) {
757 *minor_status = 0;
758 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE;
761 ctx = (gsskrb5_ctx) *context_handle;
763 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
765 switch (ctx->state) {
766 case INITIATOR_START:
767 ret = init_auth(minor_status,
768 cred,
769 ctx,
770 context,
771 name,
772 mech_type,
773 req_flags,
774 time_req,
775 input_chan_bindings,
776 input_token,
777 actual_mech_type,
778 output_token,
779 ret_flags,
780 time_rec);
781 break;
782 case INITIATOR_WAIT_FOR_MUTAL:
783 ret = repl_mutual(minor_status,
784 ctx,
785 context,
786 mech_type,
787 req_flags,
788 time_req,
789 input_chan_bindings,
790 input_token,
791 actual_mech_type,
792 output_token,
793 ret_flags,
794 time_rec);
795 break;
796 case INITIATOR_READY:
798 * If we get there, the caller have called
799 * gss_init_sec_context() one time too many.
801 *minor_status = 0;
802 ret = GSS_S_BAD_STATUS;
803 break;
804 default:
805 *minor_status = 0;
806 ret = GSS_S_BAD_STATUS;
807 break;
809 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
811 /* destroy context in case of error */
812 if (GSS_ERROR(ret)) {
813 OM_uint32 min2;
814 _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
817 return ret;