2 * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * Portions Copyright (c) 2004 PADL Software Pty Ltd.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
34 #include "spnego_locl.h"
37 send_reject (OM_uint32
*minor_status
,
38 gss_buffer_t output_token
)
43 nt
.element
= choice_NegotiationToken_negTokenResp
;
45 ALLOC(nt
.u
.negTokenResp
.negResult
, 1);
46 if (nt
.u
.negTokenResp
.negResult
== NULL
) {
47 *minor_status
= ENOMEM
;
50 *(nt
.u
.negTokenResp
.negResult
) = reject
;
51 nt
.u
.negTokenResp
.supportedMech
= NULL
;
52 nt
.u
.negTokenResp
.responseToken
= NULL
;
53 nt
.u
.negTokenResp
.mechListMIC
= NULL
;
55 ASN1_MALLOC_ENCODE(NegotiationToken
,
56 output_token
->value
, output_token
->length
, &nt
,
57 &size
, *minor_status
);
58 free_NegotiationToken(&nt
);
59 if (*minor_status
!= 0)
62 return GSS_S_BAD_MECH
;
66 acceptor_approved(gss_name_t target_name
, gss_OID mech
)
68 gss_cred_id_t cred
= GSS_C_NO_CREDENTIAL
;
72 if (target_name
== GSS_C_NO_NAME
)
73 return GSS_S_COMPLETE
;
75 gss_create_empty_oid_set(&junk
, &oidset
);
76 gss_add_oid_set_member(&junk
, mech
, &oidset
);
78 ret
= gss_acquire_cred(&junk
, target_name
, GSS_C_INDEFINITE
, oidset
,
79 GSS_C_ACCEPT
, &cred
, NULL
, NULL
);
80 gss_release_oid_set(&junk
, &oidset
);
81 if (ret
!= GSS_S_COMPLETE
)
83 gss_release_cred(&junk
, &cred
);
85 return GSS_S_COMPLETE
;
89 send_supported_mechs (OM_uint32
*minor_status
,
90 gss_buffer_t output_token
)
92 NegotiationTokenWin nt
;
97 memset(&nt
, 0, sizeof(nt
));
99 nt
.element
= choice_NegotiationTokenWin_negTokenInit
;
100 nt
.u
.negTokenInit
.reqFlags
= NULL
;
101 nt
.u
.negTokenInit
.mechToken
= NULL
;
102 nt
.u
.negTokenInit
.negHints
= NULL
;
104 ret
= _gss_spnego_indicate_mechtypelist(minor_status
, GSS_C_NO_NAME
,
105 acceptor_approved
, 1, NULL
,
106 &nt
.u
.negTokenInit
.mechTypes
, NULL
);
107 if (ret
!= GSS_S_COMPLETE
) {
111 ALLOC(nt
.u
.negTokenInit
.negHints
, 1);
112 if (nt
.u
.negTokenInit
.negHints
== NULL
) {
113 *minor_status
= ENOMEM
;
114 free_NegotiationTokenWin(&nt
);
115 return GSS_S_FAILURE
;
118 ALLOC(nt
.u
.negTokenInit
.negHints
->hintName
, 1);
119 if (nt
.u
.negTokenInit
.negHints
->hintName
== NULL
) {
120 *minor_status
= ENOMEM
;
121 free_NegotiationTokenWin(&nt
);
122 return GSS_S_FAILURE
;
125 *nt
.u
.negTokenInit
.negHints
->hintName
= strdup("not_defined_in_RFC4178@please_ignore");
126 nt
.u
.negTokenInit
.negHints
->hintAddress
= NULL
;
128 ASN1_MALLOC_ENCODE(NegotiationTokenWin
,
129 data
.value
, data
.length
, &nt
, &buf_len
, ret
);
130 free_NegotiationTokenWin(&nt
);
133 return GSS_S_FAILURE
;
135 if (data
.length
!= buf_len
)
138 ret
= gss_encapsulate_token(&data
, GSS_SPNEGO_MECHANISM
, output_token
);
142 if (ret
!= GSS_S_COMPLETE
)
147 return GSS_S_CONTINUE_NEEDED
;
151 send_accept (OM_uint32
*minor_status
,
152 gssspnego_ctx context_handle
,
153 gss_buffer_t mech_token
,
154 int initial_response
,
155 gss_buffer_t mech_buf
,
156 gss_buffer_t output_token
)
160 gss_buffer_desc mech_mic_buf
;
163 memset(&nt
, 0, sizeof(nt
));
165 nt
.element
= choice_NegotiationToken_negTokenResp
;
167 ALLOC(nt
.u
.negTokenResp
.negResult
, 1);
168 if (nt
.u
.negTokenResp
.negResult
== NULL
) {
169 *minor_status
= ENOMEM
;
170 return GSS_S_FAILURE
;
173 if (context_handle
->open
) {
174 if (mech_token
!= GSS_C_NO_BUFFER
175 && mech_token
->length
!= 0
176 && mech_buf
!= GSS_C_NO_BUFFER
)
177 *(nt
.u
.negTokenResp
.negResult
) = accept_incomplete
;
179 *(nt
.u
.negTokenResp
.negResult
) = accept_completed
;
181 if (initial_response
&& context_handle
->require_mic
)
182 *(nt
.u
.negTokenResp
.negResult
) = request_mic
;
184 *(nt
.u
.negTokenResp
.negResult
) = accept_incomplete
;
187 if (initial_response
) {
188 ALLOC(nt
.u
.negTokenResp
.supportedMech
, 1);
189 if (nt
.u
.negTokenResp
.supportedMech
== NULL
) {
190 free_NegotiationToken(&nt
);
191 *minor_status
= ENOMEM
;
192 return GSS_S_FAILURE
;
195 ret
= der_get_oid(context_handle
->preferred_mech_type
->elements
,
196 context_handle
->preferred_mech_type
->length
,
197 nt
.u
.negTokenResp
.supportedMech
,
200 free_NegotiationToken(&nt
);
201 *minor_status
= ENOMEM
;
202 return GSS_S_FAILURE
;
205 nt
.u
.negTokenResp
.supportedMech
= NULL
;
208 if (mech_token
!= GSS_C_NO_BUFFER
&& mech_token
->length
!= 0) {
209 ALLOC(nt
.u
.negTokenResp
.responseToken
, 1);
210 if (nt
.u
.negTokenResp
.responseToken
== NULL
) {
211 free_NegotiationToken(&nt
);
212 *minor_status
= ENOMEM
;
213 return GSS_S_FAILURE
;
215 nt
.u
.negTokenResp
.responseToken
->length
= mech_token
->length
;
216 nt
.u
.negTokenResp
.responseToken
->data
= mech_token
->value
;
217 mech_token
->length
= 0;
218 mech_token
->value
= NULL
;
220 nt
.u
.negTokenResp
.responseToken
= NULL
;
223 if (mech_buf
!= GSS_C_NO_BUFFER
) {
224 ret
= gss_get_mic(minor_status
,
225 context_handle
->negotiated_ctx_id
,
229 if (ret
== GSS_S_COMPLETE
) {
230 ALLOC(nt
.u
.negTokenResp
.mechListMIC
, 1);
231 if (nt
.u
.negTokenResp
.mechListMIC
== NULL
) {
232 gss_release_buffer(minor_status
, &mech_mic_buf
);
233 free_NegotiationToken(&nt
);
234 *minor_status
= ENOMEM
;
235 return GSS_S_FAILURE
;
237 nt
.u
.negTokenResp
.mechListMIC
->length
= mech_mic_buf
.length
;
238 nt
.u
.negTokenResp
.mechListMIC
->data
= mech_mic_buf
.value
;
239 } else if (ret
== GSS_S_UNAVAILABLE
) {
240 nt
.u
.negTokenResp
.mechListMIC
= NULL
;
242 free_NegotiationToken(&nt
);
247 nt
.u
.negTokenResp
.mechListMIC
= NULL
;
249 ASN1_MALLOC_ENCODE(NegotiationToken
,
250 output_token
->value
, output_token
->length
,
253 free_NegotiationToken(&nt
);
255 return GSS_S_FAILURE
;
259 * The response should not be encapsulated, because
260 * it is a SubsequentContextToken (note though RFC 1964
261 * specifies encapsulation for all _Kerberos_ tokens).
264 if (*(nt
.u
.negTokenResp
.negResult
) == accept_completed
)
265 ret
= GSS_S_COMPLETE
;
267 ret
= GSS_S_CONTINUE_NEEDED
;
268 free_NegotiationToken(&nt
);
275 (OM_uint32
*minor_status
,
276 gssspnego_ctx context_handle
,
277 gss_buffer_t mech_buf
,
278 heim_octet_string
*mechListMIC
282 gss_buffer_desc mic_buf
;
284 if (context_handle
->verified_mic
) {
285 /* This doesn't make sense, we've already verified it? */
287 return GSS_S_DUPLICATE_TOKEN
;
290 if (mechListMIC
== NULL
) {
292 return GSS_S_DEFECTIVE_TOKEN
;
295 mic_buf
.length
= mechListMIC
->length
;
296 mic_buf
.value
= mechListMIC
->data
;
298 ret
= gss_verify_mic(minor_status
,
299 context_handle
->negotiated_ctx_id
,
304 if (ret
!= GSS_S_COMPLETE
)
305 ret
= GSS_S_DEFECTIVE_TOKEN
;
311 select_mech(OM_uint32
*minor_status
, MechType
*mechType
, int verify_p
,
322 ret
= der_put_oid ((unsigned char *)mechbuf
+ sizeof(mechbuf
) - 1,
327 return GSS_S_DEFECTIVE_TOKEN
;
330 oid
.length
= mech_len
;
331 oid
.elements
= mechbuf
+ sizeof(mechbuf
) - mech_len
;
333 if (gss_oid_equal(&oid
, GSS_SPNEGO_MECHANISM
)) {
334 return GSS_S_BAD_MECH
;
339 /* Translate broken MS Kebreros OID */
340 if (gss_oid_equal(&oid
, &_gss_spnego_mskrb_mechanism_oid_desc
))
341 oidp
= &_gss_spnego_krb5_mechanism_oid_desc
;
346 ret
= gss_indicate_mechs(&junk
, &mechs
);
350 for (i
= 0; i
< mechs
->count
; i
++)
351 if (gss_oid_equal(&mechs
->elements
[i
], oidp
))
354 if (i
== mechs
->count
) {
355 gss_release_oid_set(&junk
, &mechs
);
356 return GSS_S_BAD_MECH
;
358 gss_release_oid_set(&junk
, &mechs
);
360 ret
= gss_duplicate_oid(minor_status
,
361 &oid
, /* possibly this should be oidp */
365 gss_name_t name
= GSS_C_NO_NAME
;
366 gss_buffer_desc namebuf
;
367 char *str
= NULL
, *host
, hostname
[MAXHOSTNAMELEN
];
369 host
= getenv("GSSAPI_SPNEGO_NAME");
370 if (host
== NULL
|| issuid()) {
371 if (gethostname(hostname
, sizeof(hostname
)) != 0) {
372 *minor_status
= errno
;
373 return GSS_S_FAILURE
;
375 asprintf(&str
, "host@%s", hostname
);
379 namebuf
.length
= strlen(host
);
380 namebuf
.value
= host
;
382 ret
= gss_import_name(minor_status
, &namebuf
,
383 GSS_C_NT_HOSTBASED_SERVICE
, &name
);
386 if (ret
!= GSS_S_COMPLETE
)
389 ret
= acceptor_approved(name
, *mech_p
);
390 gss_release_name(&junk
, &name
);
398 acceptor_complete(OM_uint32
* minor_status
,
401 gss_buffer_t mech_buf
,
402 gss_buffer_t mech_input_token
,
403 gss_buffer_t mech_output_token
,
404 heim_octet_string
*mic
,
405 gss_buffer_t output_token
)
408 int require_mic
, verify_mic
;
414 ret
= _gss_spnego_require_mechlist_mic(minor_status
, ctx
, &require_mic
);
418 ctx
->require_mic
= require_mic
;
423 if (ctx
->open
&& require_mic
) {
424 if (mech_input_token
== GSS_C_NO_BUFFER
) { /* Even/One */
427 } else if (mech_output_token
!= GSS_C_NO_BUFFER
&&
428 mech_output_token
->length
== 0) { /* Odd */
429 *get_mic
= verify_mic
= 1;
430 } else { /* Even/One */
435 if (verify_mic
|| *get_mic
) {
439 ASN1_MALLOC_ENCODE(MechTypeList
,
440 mech_buf
->value
, mech_buf
->length
,
441 &ctx
->initiator_mech_types
, &buf_len
, eret
);
443 *minor_status
= eret
;
444 return GSS_S_FAILURE
;
446 if (buf
.length
!= buf_len
)
451 ret
= verify_mechlist_mic(minor_status
, ctx
, mech_buf
, mic
);
454 send_reject (minor_status
, output_token
);
459 ctx
->verified_mic
= 1;
467 return GSS_S_COMPLETE
;
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
491 gss_buffer_desc data
;
492 gss_buffer_t mech_input_token
= GSS_C_NO_BUFFER
;
493 gss_buffer_desc mech_output_token
;
494 gss_buffer_desc mech_buf
;
495 gss_OID preferred_mech_type
= GSS_C_NO_OID
;
500 mech_output_token
.value
= NULL
;
501 mech_output_token
.length
= 0;
502 mech_buf
.value
= NULL
;
504 if (input_token_buffer
->length
== 0)
505 return send_supported_mechs (minor_status
, output_token
);
507 ret
= _gss_spnego_alloc_sec_context(minor_status
, context_handle
);
508 if (ret
!= GSS_S_COMPLETE
)
511 ctx
= (gssspnego_ctx
)*context_handle
;
514 * The GSS-API encapsulation is only present on the initial
515 * context token (negTokenInit).
517 ret
= gss_decapsulate_token (input_token_buffer
,
518 GSS_SPNEGO_MECHANISM
,
523 ret
= decode_NegotiationToken(data
.value
, data
.length
, &nt
, &nt_len
);
524 gss_release_buffer(minor_status
, &data
);
527 return GSS_S_DEFECTIVE_TOKEN
;
529 if (nt
.element
!= choice_NegotiationToken_negTokenInit
) {
531 return GSS_S_DEFECTIVE_TOKEN
;
533 ni
= &nt
.u
.negTokenInit
;
535 if (ni
->mechTypes
.len
< 1) {
536 free_NegotiationToken(&nt
);
538 return GSS_S_DEFECTIVE_TOKEN
;
541 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
543 ret
= copy_MechTypeList(&ni
->mechTypes
, &ctx
->initiator_mech_types
);
545 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
546 free_NegotiationToken(&nt
);
548 return GSS_S_FAILURE
;
552 * First we try the opportunistic token if we have support for it,
553 * don't try to verify we have credential for the token,
554 * gss_accept_sec_context() will (hopefully) tell us that.
558 ret
= select_mech(minor_status
,
559 &ni
->mechTypes
.val
[0],
561 &preferred_mech_type
);
563 if (ret
== 0 && ni
->mechToken
!= NULL
) {
564 gss_buffer_desc ibuf
;
566 ibuf
.length
= ni
->mechToken
->length
;
567 ibuf
.value
= ni
->mechToken
->data
;
568 mech_input_token
= &ibuf
;
570 if (ctx
->mech_src_name
!= GSS_C_NO_NAME
)
571 gss_release_name(&junk
, &ctx
->mech_src_name
);
573 ret
= gss_accept_sec_context(minor_status
,
574 &ctx
->negotiated_ctx_id
,
575 acceptor_cred_handle
,
579 &ctx
->negotiated_mech_type
,
583 delegated_cred_handle
);
585 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
) {
586 ctx
->preferred_mech_type
= preferred_mech_type
;
587 if (ret
== GSS_S_COMPLETE
)
590 ret
= acceptor_complete(minor_status
,
598 if (ret
!= GSS_S_COMPLETE
)
603 gss_mg_collect_error(preferred_mech_type
, ret
, *minor_status
);
608 * If opportunistic token failed, lets try the other mechs.
611 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 (i
= 1; i
< ni
->mechTypes
.len
; ++i
) {
617 ret
= select_mech(minor_status
,
618 &ni
->mechTypes
.val
[i
],
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
,
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
,
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
);