1 /* $NetBSD: accept_sec_context.c,v 1.1.1.2 2014/04/24 12:45:29 pettai Exp $ */
4 * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2004 PADL Software Pty Ltd.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include "spnego_locl.h"
39 send_reject (OM_uint32
*minor_status
,
40 gss_buffer_t output_token
)
45 nt
.element
= choice_NegotiationToken_negTokenResp
;
47 ALLOC(nt
.u
.negTokenResp
.negResult
, 1);
48 if (nt
.u
.negTokenResp
.negResult
== NULL
) {
49 *minor_status
= ENOMEM
;
52 *(nt
.u
.negTokenResp
.negResult
) = reject
;
53 nt
.u
.negTokenResp
.supportedMech
= NULL
;
54 nt
.u
.negTokenResp
.responseToken
= NULL
;
55 nt
.u
.negTokenResp
.mechListMIC
= NULL
;
57 ASN1_MALLOC_ENCODE(NegotiationToken
,
58 output_token
->value
, output_token
->length
, &nt
,
59 &size
, *minor_status
);
60 free_NegotiationToken(&nt
);
61 if (*minor_status
!= 0)
64 return GSS_S_BAD_MECH
;
68 acceptor_approved(gss_name_t target_name
, gss_OID mech
)
70 gss_cred_id_t cred
= GSS_C_NO_CREDENTIAL
;
74 if (target_name
== GSS_C_NO_NAME
)
75 return GSS_S_COMPLETE
;
77 gss_create_empty_oid_set(&junk
, &oidset
);
78 gss_add_oid_set_member(&junk
, mech
, &oidset
);
80 ret
= gss_acquire_cred(&junk
, target_name
, GSS_C_INDEFINITE
, oidset
,
81 GSS_C_ACCEPT
, &cred
, NULL
, NULL
);
82 gss_release_oid_set(&junk
, &oidset
);
83 if (ret
!= GSS_S_COMPLETE
)
85 gss_release_cred(&junk
, &cred
);
87 return GSS_S_COMPLETE
;
91 send_supported_mechs (OM_uint32
*minor_status
,
92 gss_buffer_t output_token
)
94 NegotiationTokenWin nt
;
99 memset(&nt
, 0, sizeof(nt
));
101 nt
.element
= choice_NegotiationTokenWin_negTokenInit
;
102 nt
.u
.negTokenInit
.reqFlags
= NULL
;
103 nt
.u
.negTokenInit
.mechToken
= NULL
;
104 nt
.u
.negTokenInit
.negHints
= NULL
;
106 ret
= _gss_spnego_indicate_mechtypelist(minor_status
, GSS_C_NO_NAME
,
107 acceptor_approved
, 1, NULL
,
108 &nt
.u
.negTokenInit
.mechTypes
, NULL
);
109 if (ret
!= GSS_S_COMPLETE
) {
113 ALLOC(nt
.u
.negTokenInit
.negHints
, 1);
114 if (nt
.u
.negTokenInit
.negHints
== NULL
) {
115 *minor_status
= ENOMEM
;
116 free_NegotiationTokenWin(&nt
);
117 return GSS_S_FAILURE
;
120 ALLOC(nt
.u
.negTokenInit
.negHints
->hintName
, 1);
121 if (nt
.u
.negTokenInit
.negHints
->hintName
== NULL
) {
122 *minor_status
= ENOMEM
;
123 free_NegotiationTokenWin(&nt
);
124 return GSS_S_FAILURE
;
127 *nt
.u
.negTokenInit
.negHints
->hintName
= strdup("not_defined_in_RFC4178@please_ignore");
128 nt
.u
.negTokenInit
.negHints
->hintAddress
= NULL
;
130 ASN1_MALLOC_ENCODE(NegotiationTokenWin
,
131 data
.value
, data
.length
, &nt
, &buf_len
, ret
);
132 free_NegotiationTokenWin(&nt
);
135 return GSS_S_FAILURE
;
137 if (data
.length
!= buf_len
) {
139 UNREACHABLE(return GSS_S_FAILURE
);
142 ret
= gss_encapsulate_token(&data
, GSS_SPNEGO_MECHANISM
, output_token
);
146 if (ret
!= GSS_S_COMPLETE
)
151 return GSS_S_CONTINUE_NEEDED
;
155 send_accept (OM_uint32
*minor_status
,
156 gssspnego_ctx context_handle
,
157 gss_buffer_t mech_token
,
158 int initial_response
,
159 gss_buffer_t mech_buf
,
160 gss_buffer_t output_token
)
164 gss_buffer_desc mech_mic_buf
;
167 memset(&nt
, 0, sizeof(nt
));
169 nt
.element
= choice_NegotiationToken_negTokenResp
;
171 ALLOC(nt
.u
.negTokenResp
.negResult
, 1);
172 if (nt
.u
.negTokenResp
.negResult
== NULL
) {
173 *minor_status
= ENOMEM
;
174 return GSS_S_FAILURE
;
177 if (context_handle
->open
) {
178 if (mech_token
!= GSS_C_NO_BUFFER
179 && mech_token
->length
!= 0
180 && mech_buf
!= GSS_C_NO_BUFFER
)
181 *(nt
.u
.negTokenResp
.negResult
) = accept_incomplete
;
183 *(nt
.u
.negTokenResp
.negResult
) = accept_completed
;
185 if (initial_response
&& context_handle
->require_mic
)
186 *(nt
.u
.negTokenResp
.negResult
) = request_mic
;
188 *(nt
.u
.negTokenResp
.negResult
) = accept_incomplete
;
191 if (initial_response
) {
192 ALLOC(nt
.u
.negTokenResp
.supportedMech
, 1);
193 if (nt
.u
.negTokenResp
.supportedMech
== NULL
) {
194 free_NegotiationToken(&nt
);
195 *minor_status
= ENOMEM
;
196 return GSS_S_FAILURE
;
199 ret
= der_get_oid(context_handle
->preferred_mech_type
->elements
,
200 context_handle
->preferred_mech_type
->length
,
201 nt
.u
.negTokenResp
.supportedMech
,
204 free_NegotiationToken(&nt
);
205 *minor_status
= ENOMEM
;
206 return GSS_S_FAILURE
;
209 nt
.u
.negTokenResp
.supportedMech
= NULL
;
212 if (mech_token
!= GSS_C_NO_BUFFER
&& mech_token
->length
!= 0) {
213 ALLOC(nt
.u
.negTokenResp
.responseToken
, 1);
214 if (nt
.u
.negTokenResp
.responseToken
== NULL
) {
215 free_NegotiationToken(&nt
);
216 *minor_status
= ENOMEM
;
217 return GSS_S_FAILURE
;
219 nt
.u
.negTokenResp
.responseToken
->length
= mech_token
->length
;
220 nt
.u
.negTokenResp
.responseToken
->data
= mech_token
->value
;
221 mech_token
->length
= 0;
222 mech_token
->value
= NULL
;
224 nt
.u
.negTokenResp
.responseToken
= NULL
;
227 if (mech_buf
!= GSS_C_NO_BUFFER
) {
228 ret
= gss_get_mic(minor_status
,
229 context_handle
->negotiated_ctx_id
,
233 if (ret
== GSS_S_COMPLETE
) {
234 ALLOC(nt
.u
.negTokenResp
.mechListMIC
, 1);
235 if (nt
.u
.negTokenResp
.mechListMIC
== NULL
) {
236 gss_release_buffer(minor_status
, &mech_mic_buf
);
237 free_NegotiationToken(&nt
);
238 *minor_status
= ENOMEM
;
239 return GSS_S_FAILURE
;
241 nt
.u
.negTokenResp
.mechListMIC
->length
= mech_mic_buf
.length
;
242 nt
.u
.negTokenResp
.mechListMIC
->data
= mech_mic_buf
.value
;
243 } else if (ret
== GSS_S_UNAVAILABLE
) {
244 nt
.u
.negTokenResp
.mechListMIC
= NULL
;
246 free_NegotiationToken(&nt
);
251 nt
.u
.negTokenResp
.mechListMIC
= NULL
;
253 ASN1_MALLOC_ENCODE(NegotiationToken
,
254 output_token
->value
, output_token
->length
,
257 free_NegotiationToken(&nt
);
259 return GSS_S_FAILURE
;
263 * The response should not be encapsulated, because
264 * it is a SubsequentContextToken (note though RFC 1964
265 * specifies encapsulation for all _Kerberos_ tokens).
268 if (*(nt
.u
.negTokenResp
.negResult
) == accept_completed
)
269 ret
= GSS_S_COMPLETE
;
271 ret
= GSS_S_CONTINUE_NEEDED
;
272 free_NegotiationToken(&nt
);
279 (OM_uint32
*minor_status
,
280 gssspnego_ctx context_handle
,
281 gss_buffer_t mech_buf
,
282 heim_octet_string
*mechListMIC
286 gss_buffer_desc mic_buf
;
288 if (context_handle
->verified_mic
) {
289 /* This doesn't make sense, we've already verified it? */
291 return GSS_S_DUPLICATE_TOKEN
;
294 if (mechListMIC
== NULL
) {
296 return GSS_S_DEFECTIVE_TOKEN
;
299 mic_buf
.length
= mechListMIC
->length
;
300 mic_buf
.value
= mechListMIC
->data
;
302 ret
= gss_verify_mic(minor_status
,
303 context_handle
->negotiated_ctx_id
,
308 if (ret
!= GSS_S_COMPLETE
)
309 ret
= GSS_S_DEFECTIVE_TOKEN
;
315 select_mech(OM_uint32
*minor_status
, MechType
*mechType
, int verify_p
,
326 ret
= der_put_oid ((unsigned char *)mechbuf
+ sizeof(mechbuf
) - 1,
331 return GSS_S_DEFECTIVE_TOKEN
;
334 oid
.length
= mech_len
;
335 oid
.elements
= mechbuf
+ sizeof(mechbuf
) - mech_len
;
337 if (gss_oid_equal(&oid
, GSS_SPNEGO_MECHANISM
)) {
338 return GSS_S_BAD_MECH
;
343 /* Translate broken MS Kebreros OID */
344 if (gss_oid_equal(&oid
, &_gss_spnego_mskrb_mechanism_oid_desc
))
345 oidp
= &_gss_spnego_krb5_mechanism_oid_desc
;
350 ret
= gss_indicate_mechs(&junk
, &mechs
);
354 for (i
= 0; i
< mechs
->count
; i
++)
355 if (gss_oid_equal(&mechs
->elements
[i
], oidp
))
358 if (i
== mechs
->count
) {
359 gss_release_oid_set(&junk
, &mechs
);
360 return GSS_S_BAD_MECH
;
362 gss_release_oid_set(&junk
, &mechs
);
364 ret
= gss_duplicate_oid(minor_status
,
365 &oid
, /* possibly this should be oidp */
369 gss_name_t name
= GSS_C_NO_NAME
;
370 gss_buffer_desc namebuf
;
371 char *str
= NULL
, *host
, hostname
[MAXHOSTNAMELEN
];
373 host
= getenv("GSSAPI_SPNEGO_NAME");
374 if (host
== NULL
|| issuid()) {
376 if (gethostname(hostname
, sizeof(hostname
)) != 0) {
377 *minor_status
= errno
;
378 return GSS_S_FAILURE
;
380 rv
= asprintf(&str
, "host@%s", hostname
);
381 if (rv
< 0 || str
== NULL
) {
382 *minor_status
= ENOMEM
;
383 return GSS_S_FAILURE
;
388 namebuf
.length
= strlen(host
);
389 namebuf
.value
= host
;
391 ret
= gss_import_name(minor_status
, &namebuf
,
392 GSS_C_NT_HOSTBASED_SERVICE
, &name
);
395 if (ret
!= GSS_S_COMPLETE
)
398 ret
= acceptor_approved(name
, *mech_p
);
399 gss_release_name(&junk
, &name
);
407 acceptor_complete(OM_uint32
* minor_status
,
410 gss_buffer_t mech_buf
,
411 gss_buffer_t mech_input_token
,
412 gss_buffer_t mech_output_token
,
413 heim_octet_string
*mic
,
414 gss_buffer_t output_token
)
417 int require_mic
, verify_mic
;
419 ret
= _gss_spnego_require_mechlist_mic(minor_status
, ctx
, &require_mic
);
423 ctx
->require_mic
= require_mic
;
428 if (ctx
->open
&& require_mic
) {
429 if (mech_input_token
== GSS_C_NO_BUFFER
) { /* Even/One */
432 } else if (mech_output_token
!= GSS_C_NO_BUFFER
&&
433 mech_output_token
->length
== 0) { /* Odd */
434 *get_mic
= verify_mic
= 1;
435 } else { /* Even/One */
440 if (verify_mic
|| *get_mic
) {
444 ASN1_MALLOC_ENCODE(MechTypeList
,
445 mech_buf
->value
, mech_buf
->length
,
446 &ctx
->initiator_mech_types
, &buf_len
, eret
);
448 *minor_status
= eret
;
449 return GSS_S_FAILURE
;
451 heim_assert(mech_buf
->length
== buf_len
, "Internal ASN.1 error");
452 UNREACHABLE(return GSS_S_FAILURE
);
456 ret
= verify_mechlist_mic(minor_status
, ctx
, mech_buf
, mic
);
459 send_reject (minor_status
, output_token
);
462 ctx
->verified_mic
= 1;
467 return GSS_S_COMPLETE
;
471 static OM_uint32 GSSAPI_CALLCONV
473 (OM_uint32
* minor_status
,
474 gss_ctx_id_t
* context_handle
,
475 const gss_cred_id_t acceptor_cred_handle
,
476 const gss_buffer_t input_token_buffer
,
477 const gss_channel_bindings_t input_chan_bindings
,
478 gss_name_t
* src_name
,
480 gss_buffer_t output_token
,
481 OM_uint32
* ret_flags
,
482 OM_uint32
* time_rec
,
483 gss_cred_id_t
*delegated_cred_handle
490 gss_buffer_desc data
;
491 gss_buffer_t mech_input_token
= GSS_C_NO_BUFFER
;
492 gss_buffer_desc mech_output_token
;
493 gss_buffer_desc mech_buf
;
494 gss_OID preferred_mech_type
= GSS_C_NO_OID
;
499 mech_output_token
.value
= NULL
;
500 mech_output_token
.length
= 0;
501 mech_buf
.value
= NULL
;
503 if (input_token_buffer
->length
== 0)
504 return send_supported_mechs (minor_status
, output_token
);
506 ret
= _gss_spnego_alloc_sec_context(minor_status
, context_handle
);
507 if (ret
!= GSS_S_COMPLETE
)
510 ctx
= (gssspnego_ctx
)*context_handle
;
513 * The GSS-API encapsulation is only present on the initial
514 * context token (negTokenInit).
516 ret
= gss_decapsulate_token (input_token_buffer
,
517 GSS_SPNEGO_MECHANISM
,
522 ret
= decode_NegotiationToken(data
.value
, data
.length
, &nt
, &nt_len
);
523 gss_release_buffer(minor_status
, &data
);
526 return GSS_S_DEFECTIVE_TOKEN
;
528 if (nt
.element
!= choice_NegotiationToken_negTokenInit
) {
530 return GSS_S_DEFECTIVE_TOKEN
;
532 ni
= &nt
.u
.negTokenInit
;
534 if (ni
->mechTypes
.len
< 1) {
535 free_NegotiationToken(&nt
);
537 return GSS_S_DEFECTIVE_TOKEN
;
540 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
542 ret
= copy_MechTypeList(&ni
->mechTypes
, &ctx
->initiator_mech_types
);
544 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
545 free_NegotiationToken(&nt
);
547 return GSS_S_FAILURE
;
551 * First we try the opportunistic token if we have support for it,
552 * don't try to verify we have credential for the token,
553 * gss_accept_sec_context() will (hopefully) tell us that.
557 ret
= select_mech(minor_status
,
558 &ni
->mechTypes
.val
[0],
560 &preferred_mech_type
);
562 if (ret
== 0 && ni
->mechToken
!= NULL
) {
563 gss_buffer_desc ibuf
;
565 ibuf
.length
= ni
->mechToken
->length
;
566 ibuf
.value
= ni
->mechToken
->data
;
567 mech_input_token
= &ibuf
;
569 if (ctx
->mech_src_name
!= GSS_C_NO_NAME
)
570 gss_release_name(&junk
, &ctx
->mech_src_name
);
572 ret
= gss_accept_sec_context(minor_status
,
573 &ctx
->negotiated_ctx_id
,
574 acceptor_cred_handle
,
578 &ctx
->negotiated_mech_type
,
582 delegated_cred_handle
);
584 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
) {
585 ctx
->preferred_mech_type
= preferred_mech_type
;
586 if (ret
== GSS_S_COMPLETE
)
589 ret
= acceptor_complete(minor_status
,
597 if (ret
!= GSS_S_COMPLETE
)
602 gss_mg_collect_error(preferred_mech_type
, ret
, *minor_status
);
607 * If opportunistic token failed, lets try the other mechs.
610 if (!first_ok
&& ni
->mechToken
!= NULL
) {
613 preferred_mech_type
= GSS_C_NO_OID
;
615 /* Call glue layer to find first mech we support */
616 for (j
= 1; j
< ni
->mechTypes
.len
; ++j
) {
617 ret
= select_mech(minor_status
,
618 &ni
->mechTypes
.val
[j
],
620 &preferred_mech_type
);
624 if (preferred_mech_type
== GSS_C_NO_OID
) {
625 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
626 free_NegotiationToken(&nt
);
630 ctx
->preferred_mech_type
= preferred_mech_type
;
634 * The initial token always have a response
637 ret
= send_accept (minor_status
,
641 get_mic
? &mech_buf
: NULL
,
647 if (mech_output_token
.value
!= NULL
)
648 gss_release_buffer(&junk
, &mech_output_token
);
649 if (mech_buf
.value
!= NULL
) {
650 free(mech_buf
.value
);
651 mech_buf
.value
= NULL
;
653 free_NegotiationToken(&nt
);
656 if (ret
== GSS_S_COMPLETE
) {
657 if (src_name
!= NULL
&& ctx
->mech_src_name
!= NULL
) {
660 name
= calloc(1, sizeof(*name
));
662 name
->mech
= ctx
->mech_src_name
;
663 ctx
->mech_src_name
= NULL
;
664 *src_name
= (gss_name_t
)name
;
669 if (mech_type
!= NULL
)
670 *mech_type
= ctx
->negotiated_mech_type
;
671 if (ret_flags
!= NULL
)
672 *ret_flags
= ctx
->mech_flags
;
673 if (time_rec
!= NULL
)
674 *time_rec
= ctx
->mech_time_rec
;
676 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
) {
677 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
681 _gss_spnego_internal_delete_sec_context(&junk
, context_handle
,
688 static OM_uint32 GSSAPI_CALLCONV
690 (OM_uint32
* minor_status
,
691 gss_ctx_id_t
* context_handle
,
692 const gss_cred_id_t acceptor_cred_handle
,
693 const gss_buffer_t input_token_buffer
,
694 const gss_channel_bindings_t input_chan_bindings
,
695 gss_name_t
* src_name
,
697 gss_buffer_t output_token
,
698 OM_uint32
* ret_flags
,
699 OM_uint32
* time_rec
,
700 gss_cred_id_t
*delegated_cred_handle
703 OM_uint32 ret
, ret2
, minor
;
707 unsigned int negResult
= accept_incomplete
;
708 gss_buffer_t mech_input_token
= GSS_C_NO_BUFFER
;
709 gss_buffer_t mech_output_token
= GSS_C_NO_BUFFER
;
710 gss_buffer_desc mech_buf
;
713 mech_buf
.value
= NULL
;
715 ctx
= (gssspnego_ctx
)*context_handle
;
718 * The GSS-API encapsulation is only present on the initial
719 * context token (negTokenInit).
722 ret
= decode_NegotiationToken(input_token_buffer
->value
,
723 input_token_buffer
->length
,
727 return GSS_S_DEFECTIVE_TOKEN
;
729 if (nt
.element
!= choice_NegotiationToken_negTokenResp
) {
731 return GSS_S_DEFECTIVE_TOKEN
;
733 na
= &nt
.u
.negTokenResp
;
735 if (na
->negResult
!= NULL
) {
736 negResult
= *(na
->negResult
);
739 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
742 gss_buffer_desc ibuf
, obuf
;
743 int require_mic
, get_mic
= 0;
744 int require_response
;
745 heim_octet_string
*mic
;
747 if (na
->responseToken
!= NULL
) {
748 ibuf
.length
= na
->responseToken
->length
;
749 ibuf
.value
= na
->responseToken
->data
;
750 mech_input_token
= &ibuf
;
756 if (mech_input_token
!= GSS_C_NO_BUFFER
) {
758 if (ctx
->mech_src_name
!= GSS_C_NO_NAME
)
759 gss_release_name(&minor
, &ctx
->mech_src_name
);
761 ret
= gss_accept_sec_context(&minor
,
762 &ctx
->negotiated_ctx_id
,
763 acceptor_cred_handle
,
767 &ctx
->negotiated_mech_type
,
771 delegated_cred_handle
);
773 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
) {
774 mech_output_token
= &obuf
;
776 if (ret
!= GSS_S_COMPLETE
&& ret
!= GSS_S_CONTINUE_NEEDED
) {
777 free_NegotiationToken(&nt
);
778 gss_mg_collect_error(ctx
->negotiated_mech_type
, ret
, minor
);
779 send_reject (minor_status
, output_token
);
780 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
783 if (ret
== GSS_S_COMPLETE
)
786 ret
= GSS_S_COMPLETE
;
788 ret2
= _gss_spnego_require_mechlist_mic(minor_status
,
794 ctx
->require_mic
= require_mic
;
796 mic
= na
->mechListMIC
;
800 if (ret
== GSS_S_COMPLETE
)
801 ret
= acceptor_complete(minor_status
,
810 if (ctx
->mech_flags
& GSS_C_DCE_STYLE
)
811 require_response
= (negResult
!= accept_completed
);
813 require_response
= 0;
816 * Check whether we need to send a result: there should be only
817 * one accept_completed response sent in the entire negotiation
819 if ((mech_output_token
!= GSS_C_NO_BUFFER
&&
820 mech_output_token
->length
!= 0)
821 || (ctx
->open
&& negResult
== accept_incomplete
)
824 ret2
= send_accept (minor_status
,
828 get_mic
? &mech_buf
: NULL
,
835 if (ret2
!= GSS_S_COMPLETE
)
837 if (mech_output_token
!= NULL
)
838 gss_release_buffer(&minor
, mech_output_token
);
839 if (mech_buf
.value
!= NULL
)
840 free(mech_buf
.value
);
841 free_NegotiationToken(&nt
);
844 if (ret
== GSS_S_COMPLETE
) {
845 if (src_name
!= NULL
&& ctx
->mech_src_name
!= NULL
) {
848 name
= calloc(1, sizeof(*name
));
850 name
->mech
= ctx
->mech_src_name
;
851 ctx
->mech_src_name
= NULL
;
852 *src_name
= (gss_name_t
)name
;
857 if (mech_type
!= NULL
)
858 *mech_type
= ctx
->negotiated_mech_type
;
859 if (ret_flags
!= NULL
)
860 *ret_flags
= ctx
->mech_flags
;
861 if (time_rec
!= NULL
)
862 *time_rec
= ctx
->mech_time_rec
;
864 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
) {
865 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
869 _gss_spnego_internal_delete_sec_context(&minor
, context_handle
,
875 OM_uint32 GSSAPI_CALLCONV
876 _gss_spnego_accept_sec_context
877 (OM_uint32
* minor_status
,
878 gss_ctx_id_t
* context_handle
,
879 const gss_cred_id_t acceptor_cred_handle
,
880 const gss_buffer_t input_token_buffer
,
881 const gss_channel_bindings_t input_chan_bindings
,
882 gss_name_t
* src_name
,
884 gss_buffer_t output_token
,
885 OM_uint32
* ret_flags
,
886 OM_uint32
* time_rec
,
887 gss_cred_id_t
*delegated_cred_handle
890 _gss_accept_sec_context_t
*func
;
894 output_token
->length
= 0;
895 output_token
->value
= NULL
;
897 if (src_name
!= NULL
)
898 *src_name
= GSS_C_NO_NAME
;
899 if (mech_type
!= NULL
)
900 *mech_type
= GSS_C_NO_OID
;
901 if (ret_flags
!= NULL
)
903 if (time_rec
!= NULL
)
905 if (delegated_cred_handle
!= NULL
)
906 *delegated_cred_handle
= GSS_C_NO_CREDENTIAL
;
909 if (*context_handle
== GSS_C_NO_CONTEXT
)
910 func
= acceptor_start
;
912 func
= acceptor_continue
;
915 return (*func
)(minor_status
, context_handle
, acceptor_cred_handle
,
916 input_token_buffer
, input_chan_bindings
,
917 src_name
, mech_type
, output_token
, ret_flags
,
918 time_rec
, delegated_cred_handle
);