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/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
;
95 char hostname
[MAXHOSTNAMELEN
+ 1], *p
;
96 gss_buffer_desc name_buf
;
98 gss_name_t target_princ
;
99 gss_name_t canon_princ
;
102 gss_buffer_desc data
;
105 memset(&nt
, 0, sizeof(nt
));
107 nt
.element
= choice_NegotiationTokenWin_negTokenInit
;
108 nt
.u
.negTokenInit
.reqFlags
= NULL
;
109 nt
.u
.negTokenInit
.mechToken
= NULL
;
110 nt
.u
.negTokenInit
.negHints
= NULL
;
112 ret
= _gss_spnego_indicate_mechtypelist(minor_status
, GSS_C_NO_NAME
,
113 acceptor_approved
, 1, NULL
,
114 &nt
.u
.negTokenInit
.mechTypes
, NULL
);
115 if (ret
!= GSS_S_COMPLETE
) {
119 memset(&target_princ
, 0, sizeof(target_princ
));
120 if (gethostname(hostname
, sizeof(hostname
) - 2) != 0) {
121 *minor_status
= errno
;
122 free_NegotiationTokenWin(&nt
);
123 return GSS_S_FAILURE
;
125 hostname
[sizeof(hostname
) - 1] = '\0';
127 /* Send the constructed SAM name for this host */
128 for (p
= hostname
; *p
!= '\0' && *p
!= '.'; p
++) {
129 *p
= toupper((unsigned char)*p
);
134 name_buf
.length
= strlen(hostname
);
135 name_buf
.value
= hostname
;
137 ret
= gss_import_name(minor_status
, &name_buf
,
140 if (ret
!= GSS_S_COMPLETE
) {
141 free_NegotiationTokenWin(&nt
);
146 name_buf
.value
= NULL
;
148 /* Canonicalize the name using the preferred mechanism */
149 ret
= gss_canonicalize_name(minor_status
,
153 if (ret
!= GSS_S_COMPLETE
) {
154 free_NegotiationTokenWin(&nt
);
155 gss_release_name(&minor
, &target_princ
);
159 ret
= gss_display_name(minor_status
, canon_princ
,
160 &name_buf
, &name_type
);
161 if (ret
!= GSS_S_COMPLETE
) {
162 free_NegotiationTokenWin(&nt
);
163 gss_release_name(&minor
, &canon_princ
);
164 gss_release_name(&minor
, &target_princ
);
168 gss_release_name(&minor
, &canon_princ
);
169 gss_release_name(&minor
, &target_princ
);
171 ALLOC(nt
.u
.negTokenInit
.negHints
, 1);
172 if (nt
.u
.negTokenInit
.negHints
== NULL
) {
173 *minor_status
= ENOMEM
;
174 gss_release_buffer(&minor
, &name_buf
);
175 free_NegotiationTokenWin(&nt
);
176 return GSS_S_FAILURE
;
179 ALLOC(nt
.u
.negTokenInit
.negHints
->hintName
, 1);
180 if (nt
.u
.negTokenInit
.negHints
->hintName
== NULL
) {
181 *minor_status
= ENOMEM
;
182 gss_release_buffer(&minor
, &name_buf
);
183 free_NegotiationTokenWin(&nt
);
184 return GSS_S_FAILURE
;
187 *(nt
.u
.negTokenInit
.negHints
->hintName
) = name_buf
.value
;
188 name_buf
.value
= NULL
;
189 nt
.u
.negTokenInit
.negHints
->hintAddress
= NULL
;
191 ASN1_MALLOC_ENCODE(NegotiationTokenWin
,
192 data
.value
, data
.length
, &nt
, &buf_len
, ret
);
193 free_NegotiationTokenWin(&nt
);
197 if (data
.length
!= buf_len
)
200 ret
= gss_encapsulate_token(&data
, GSS_SPNEGO_MECHANISM
, output_token
);
204 if (ret
!= GSS_S_COMPLETE
)
209 return GSS_S_CONTINUE_NEEDED
;
213 send_accept (OM_uint32
*minor_status
,
214 gssspnego_ctx context_handle
,
215 gss_buffer_t mech_token
,
216 int initial_response
,
217 gss_buffer_t mech_buf
,
218 gss_buffer_t output_token
)
222 gss_buffer_desc mech_mic_buf
;
225 memset(&nt
, 0, sizeof(nt
));
227 nt
.element
= choice_NegotiationToken_negTokenResp
;
229 ALLOC(nt
.u
.negTokenResp
.negResult
, 1);
230 if (nt
.u
.negTokenResp
.negResult
== NULL
) {
231 *minor_status
= ENOMEM
;
232 return GSS_S_FAILURE
;
235 if (context_handle
->open
) {
236 if (mech_token
!= GSS_C_NO_BUFFER
237 && mech_token
->length
!= 0
238 && mech_buf
!= GSS_C_NO_BUFFER
)
239 *(nt
.u
.negTokenResp
.negResult
) = accept_incomplete
;
241 *(nt
.u
.negTokenResp
.negResult
) = accept_completed
;
243 if (initial_response
&& context_handle
->require_mic
)
244 *(nt
.u
.negTokenResp
.negResult
) = request_mic
;
246 *(nt
.u
.negTokenResp
.negResult
) = accept_incomplete
;
249 if (initial_response
) {
250 ALLOC(nt
.u
.negTokenResp
.supportedMech
, 1);
251 if (nt
.u
.negTokenResp
.supportedMech
== NULL
) {
252 free_NegotiationToken(&nt
);
253 *minor_status
= ENOMEM
;
254 return GSS_S_FAILURE
;
257 ret
= der_get_oid(context_handle
->preferred_mech_type
->elements
,
258 context_handle
->preferred_mech_type
->length
,
259 nt
.u
.negTokenResp
.supportedMech
,
262 free_NegotiationToken(&nt
);
263 *minor_status
= ENOMEM
;
264 return GSS_S_FAILURE
;
267 nt
.u
.negTokenResp
.supportedMech
= NULL
;
270 if (mech_token
!= GSS_C_NO_BUFFER
&& mech_token
->length
!= 0) {
271 ALLOC(nt
.u
.negTokenResp
.responseToken
, 1);
272 if (nt
.u
.negTokenResp
.responseToken
== NULL
) {
273 free_NegotiationToken(&nt
);
274 *minor_status
= ENOMEM
;
275 return GSS_S_FAILURE
;
277 nt
.u
.negTokenResp
.responseToken
->length
= mech_token
->length
;
278 nt
.u
.negTokenResp
.responseToken
->data
= mech_token
->value
;
279 mech_token
->length
= 0;
280 mech_token
->value
= NULL
;
282 nt
.u
.negTokenResp
.responseToken
= NULL
;
285 if (mech_buf
!= GSS_C_NO_BUFFER
) {
286 ret
= gss_get_mic(minor_status
,
287 context_handle
->negotiated_ctx_id
,
291 if (ret
== GSS_S_COMPLETE
) {
292 ALLOC(nt
.u
.negTokenResp
.mechListMIC
, 1);
293 if (nt
.u
.negTokenResp
.mechListMIC
== NULL
) {
294 gss_release_buffer(minor_status
, &mech_mic_buf
);
295 free_NegotiationToken(&nt
);
296 *minor_status
= ENOMEM
;
297 return GSS_S_FAILURE
;
299 nt
.u
.negTokenResp
.mechListMIC
->length
= mech_mic_buf
.length
;
300 nt
.u
.negTokenResp
.mechListMIC
->data
= mech_mic_buf
.value
;
301 } else if (ret
== GSS_S_UNAVAILABLE
) {
302 nt
.u
.negTokenResp
.mechListMIC
= NULL
;
304 free_NegotiationToken(&nt
);
309 nt
.u
.negTokenResp
.mechListMIC
= NULL
;
311 ASN1_MALLOC_ENCODE(NegotiationToken
,
312 output_token
->value
, output_token
->length
,
315 free_NegotiationToken(&nt
);
317 return GSS_S_FAILURE
;
321 * The response should not be encapsulated, because
322 * it is a SubsequentContextToken (note though RFC 1964
323 * specifies encapsulation for all _Kerberos_ tokens).
326 if (*(nt
.u
.negTokenResp
.negResult
) == accept_completed
)
327 ret
= GSS_S_COMPLETE
;
329 ret
= GSS_S_CONTINUE_NEEDED
;
330 free_NegotiationToken(&nt
);
337 (OM_uint32
*minor_status
,
338 gssspnego_ctx context_handle
,
339 gss_buffer_t mech_buf
,
340 heim_octet_string
*mechListMIC
344 gss_buffer_desc mic_buf
;
346 if (context_handle
->verified_mic
) {
347 /* This doesn't make sense, we've already verified it? */
349 return GSS_S_DUPLICATE_TOKEN
;
352 if (mechListMIC
== NULL
) {
354 return GSS_S_DEFECTIVE_TOKEN
;
357 mic_buf
.length
= mechListMIC
->length
;
358 mic_buf
.value
= mechListMIC
->data
;
360 ret
= gss_verify_mic(minor_status
,
361 context_handle
->negotiated_ctx_id
,
366 if (ret
!= GSS_S_COMPLETE
)
367 ret
= GSS_S_DEFECTIVE_TOKEN
;
373 select_mech(OM_uint32
*minor_status
, MechType
*mechType
, int verify_p
,
384 ret
= der_put_oid ((unsigned char *)mechbuf
+ sizeof(mechbuf
) - 1,
389 return GSS_S_DEFECTIVE_TOKEN
;
392 oid
.length
= mech_len
;
393 oid
.elements
= mechbuf
+ sizeof(mechbuf
) - mech_len
;
395 if (gss_oid_equal(&oid
, GSS_SPNEGO_MECHANISM
)) {
396 return GSS_S_BAD_MECH
;
401 /* Translate broken MS Kebreros OID */
402 if (gss_oid_equal(&oid
, &_gss_spnego_mskrb_mechanism_oid_desc
))
403 oidp
= &_gss_spnego_krb5_mechanism_oid_desc
;
408 ret
= gss_indicate_mechs(&junk
, &mechs
);
412 for (i
= 0; i
< mechs
->count
; i
++)
413 if (gss_oid_equal(&mechs
->elements
[i
], oidp
))
416 if (i
== mechs
->count
) {
417 gss_release_oid_set(&junk
, &mechs
);
418 return GSS_S_BAD_MECH
;
420 gss_release_oid_set(&junk
, &mechs
);
422 ret
= gss_duplicate_oid(minor_status
,
423 &oid
, /* possibly this should be oidp */
427 gss_name_t name
= GSS_C_NO_NAME
;
428 gss_buffer_desc namebuf
;
429 char *str
= NULL
, *host
, hostname
[MAXHOSTNAMELEN
];
431 host
= getenv("GSSAPI_SPNEGO_NAME");
432 if (host
== NULL
|| issuid()) {
433 if (gethostname(hostname
, sizeof(hostname
)) != 0) {
434 *minor_status
= errno
;
435 return GSS_S_FAILURE
;
437 asprintf(&str
, "host@%s", hostname
);
441 namebuf
.length
= strlen(host
);
442 namebuf
.value
= host
;
444 ret
= gss_import_name(minor_status
, &namebuf
,
445 GSS_C_NT_HOSTBASED_SERVICE
, &name
);
448 if (ret
!= GSS_S_COMPLETE
)
451 ret
= acceptor_approved(name
, *mech_p
);
452 gss_release_name(&junk
, &name
);
460 acceptor_complete(OM_uint32
* minor_status
,
463 gss_buffer_t mech_buf
,
464 gss_buffer_t mech_input_token
,
465 gss_buffer_t mech_output_token
,
466 heim_octet_string
*mic
,
467 gss_buffer_t output_token
)
470 int require_mic
, verify_mic
;
476 ret
= _gss_spnego_require_mechlist_mic(minor_status
, ctx
, &require_mic
);
480 ctx
->require_mic
= require_mic
;
485 if (ctx
->open
&& require_mic
) {
486 if (mech_input_token
== GSS_C_NO_BUFFER
) { /* Even/One */
489 } else if (mech_output_token
!= GSS_C_NO_BUFFER
&&
490 mech_output_token
->length
== 0) { /* Odd */
491 *get_mic
= verify_mic
= 1;
492 } else { /* Even/One */
497 if (verify_mic
|| get_mic
) {
501 ASN1_MALLOC_ENCODE(MechTypeList
,
502 mech_buf
->value
, mech_buf
->length
,
503 &ctx
->initiator_mech_types
, &buf_len
, eret
);
505 *minor_status
= eret
;
506 return GSS_S_FAILURE
;
508 if (buf
.length
!= buf_len
)
513 ret
= verify_mechlist_mic(minor_status
, ctx
, mech_buf
, mic
);
516 send_reject (minor_status
, output_token
);
521 ctx
->verified_mic
= 1;
527 *get_mic
= verify_mic
= 0;
529 return GSS_S_COMPLETE
;
535 (OM_uint32
* minor_status
,
536 gss_ctx_id_t
* context_handle
,
537 const gss_cred_id_t acceptor_cred_handle
,
538 const gss_buffer_t input_token_buffer
,
539 const gss_channel_bindings_t input_chan_bindings
,
540 gss_name_t
* src_name
,
542 gss_buffer_t output_token
,
543 OM_uint32
* ret_flags
,
544 OM_uint32
* time_rec
,
545 gss_cred_id_t
*delegated_cred_handle
553 gss_buffer_desc data
;
554 gss_buffer_t mech_input_token
= GSS_C_NO_BUFFER
;
555 gss_buffer_desc mech_output_token
;
556 gss_buffer_desc mech_buf
;
557 gss_OID preferred_mech_type
= GSS_C_NO_OID
;
559 gssspnego_cred acceptor_cred
= (gssspnego_cred
)acceptor_cred_handle
;
563 mech_output_token
.value
= NULL
;
564 mech_output_token
.length
= 0;
565 mech_buf
.value
= NULL
;
567 if (input_token_buffer
->length
== 0)
568 return send_supported_mechs (minor_status
, output_token
);
570 ret
= _gss_spnego_alloc_sec_context(minor_status
, context_handle
);
571 if (ret
!= GSS_S_COMPLETE
)
574 ctx
= (gssspnego_ctx
)*context_handle
;
577 * The GSS-API encapsulation is only present on the initial
578 * context token (negTokenInit).
580 ret
= gss_decapsulate_token (input_token_buffer
,
581 GSS_SPNEGO_MECHANISM
,
586 ret
= decode_NegotiationToken(data
.value
, data
.length
, &nt
, &nt_len
);
587 gss_release_buffer(minor_status
, &data
);
590 return GSS_S_DEFECTIVE_TOKEN
;
592 if (nt
.element
!= choice_NegotiationToken_negTokenInit
) {
594 return GSS_S_DEFECTIVE_TOKEN
;
596 ni
= &nt
.u
.negTokenInit
;
598 if (ni
->mechTypes
.len
< 1) {
599 free_NegotiationToken(&nt
);
601 return GSS_S_DEFECTIVE_TOKEN
;
604 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
606 ret
= copy_MechTypeList(&ni
->mechTypes
, &ctx
->initiator_mech_types
);
608 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
609 free_NegotiationToken(&nt
);
611 return GSS_S_FAILURE
;
615 * First we try the opportunistic token if we have support for it,
616 * don't try to verify we have credential for the token,
617 * gss_accept_sec_context() will (hopefully) tell us that.
621 ret
= select_mech(minor_status
,
622 &ni
->mechTypes
.val
[0],
624 &preferred_mech_type
);
626 if (ret
== 0 && ni
->mechToken
!= NULL
) {
627 gss_cred_id_t mech_delegated_cred
= GSS_C_NO_CREDENTIAL
;
628 gss_cred_id_t mech_cred
;
629 gss_buffer_desc ibuf
;
631 ibuf
.length
= ni
->mechToken
->length
;
632 ibuf
.value
= ni
->mechToken
->data
;
633 mech_input_token
= &ibuf
;
635 if (acceptor_cred
!= NULL
)
636 mech_cred
= acceptor_cred
->negotiated_cred_id
;
638 mech_cred
= GSS_C_NO_CREDENTIAL
;
640 if (ctx
->mech_src_name
!= GSS_C_NO_NAME
)
641 gss_release_name(&junk
, &ctx
->mech_src_name
);
643 ret
= gss_accept_sec_context(minor_status
,
644 &ctx
->negotiated_ctx_id
,
649 &ctx
->negotiated_mech_type
,
653 &mech_delegated_cred
);
655 if (mech_delegated_cred
&& delegated_cred_handle
) {
656 _gss_spnego_alloc_cred(&junk
,
658 delegated_cred_handle
);
659 } else if (mech_delegated_cred
!= GSS_C_NO_CREDENTIAL
)
660 gss_release_cred(&junk
, &mech_delegated_cred
);
662 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
) {
663 ctx
->preferred_mech_type
= preferred_mech_type
;
664 ctx
->negotiated_mech_type
= preferred_mech_type
;
665 if (ret
== GSS_S_COMPLETE
)
668 ret
= acceptor_complete(minor_status
,
676 if (ret
!= GSS_S_COMPLETE
)
681 gss_mg_collect_error(preferred_mech_type
, ret
, *minor_status
);
686 * If opportunistic token failed, lets try the other mechs.
689 if (!first_ok
&& ni
->mechToken
!= NULL
) {
691 preferred_mech_type
= GSS_C_NO_OID
;
693 /* Call glue layer to find first mech we support */
694 for (i
= 1; i
< ni
->mechTypes
.len
; ++i
) {
695 ret
= select_mech(minor_status
,
696 &ni
->mechTypes
.val
[i
],
698 &preferred_mech_type
);
702 if (preferred_mech_type
== GSS_C_NO_OID
) {
703 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
704 free_NegotiationToken(&nt
);
708 ctx
->preferred_mech_type
= preferred_mech_type
;
709 ctx
->negotiated_mech_type
= preferred_mech_type
;
713 * The initial token always have a response
716 ret
= send_accept (minor_status
,
720 get_mic
? &mech_buf
: NULL
,
726 if (mech_output_token
.value
!= NULL
)
727 gss_release_buffer(&junk
, &mech_output_token
);
728 if (mech_buf
.value
!= NULL
) {
729 free(mech_buf
.value
);
730 mech_buf
.value
= NULL
;
732 free_NegotiationToken(&nt
);
735 if (ret
== GSS_S_COMPLETE
) {
736 if (src_name
!= NULL
&& ctx
->mech_src_name
!= NULL
) {
739 name
= calloc(1, sizeof(*name
));
741 name
->mech
= ctx
->mech_src_name
;
742 ctx
->mech_src_name
= NULL
;
743 *src_name
= (gss_name_t
)name
;
748 if (mech_type
!= NULL
)
749 *mech_type
= ctx
->negotiated_mech_type
;
750 if (ret_flags
!= NULL
)
751 *ret_flags
= ctx
->mech_flags
;
752 if (time_rec
!= NULL
)
753 *time_rec
= ctx
->mech_time_rec
;
755 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
) {
756 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
760 _gss_spnego_internal_delete_sec_context(&junk
, context_handle
,
769 (OM_uint32
* minor_status
,
770 gss_ctx_id_t
* context_handle
,
771 const gss_cred_id_t acceptor_cred_handle
,
772 const gss_buffer_t input_token_buffer
,
773 const gss_channel_bindings_t input_chan_bindings
,
774 gss_name_t
* src_name
,
776 gss_buffer_t output_token
,
777 OM_uint32
* ret_flags
,
778 OM_uint32
* time_rec
,
779 gss_cred_id_t
*delegated_cred_handle
782 OM_uint32 ret
, ret2
, minor
, junk
;
786 unsigned int negResult
= accept_incomplete
;
787 gss_buffer_t mech_input_token
= GSS_C_NO_BUFFER
;
788 gss_buffer_t mech_output_token
= GSS_C_NO_BUFFER
;
789 gss_buffer_desc mech_buf
;
791 gssspnego_cred acceptor_cred
= (gssspnego_cred
)acceptor_cred_handle
;
793 mech_buf
.value
= NULL
;
795 ctx
= (gssspnego_ctx
)*context_handle
;
798 * The GSS-API encapsulation is only present on the initial
799 * context token (negTokenInit).
802 ret
= decode_NegotiationToken(input_token_buffer
->value
,
803 input_token_buffer
->length
,
807 return GSS_S_DEFECTIVE_TOKEN
;
809 if (nt
.element
!= choice_NegotiationToken_negTokenResp
) {
811 return GSS_S_DEFECTIVE_TOKEN
;
813 na
= &nt
.u
.negTokenResp
;
815 if (na
->negResult
!= NULL
) {
816 negResult
= *(na
->negResult
);
819 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
822 gss_buffer_desc ibuf
, obuf
;
823 int require_mic
, get_mic
= 0;
824 int require_response
;
825 heim_octet_string
*mic
;
827 if (na
->responseToken
!= NULL
) {
828 ibuf
.length
= na
->responseToken
->length
;
829 ibuf
.value
= na
->responseToken
->data
;
830 mech_input_token
= &ibuf
;
836 if (mech_input_token
!= GSS_C_NO_BUFFER
) {
837 gss_cred_id_t mech_cred
;
838 gss_cred_id_t mech_delegated_cred
= GSS_C_NO_CREDENTIAL
;
840 if (acceptor_cred
!= NULL
)
841 mech_cred
= acceptor_cred
->negotiated_cred_id
;
843 mech_cred
= GSS_C_NO_CREDENTIAL
;
845 if (ctx
->mech_src_name
!= GSS_C_NO_NAME
)
846 gss_release_name(&minor
, &ctx
->mech_src_name
);
848 ret
= gss_accept_sec_context(&minor
,
849 &ctx
->negotiated_ctx_id
,
854 &ctx
->negotiated_mech_type
,
858 &mech_delegated_cred
);
860 if (mech_delegated_cred
&& delegated_cred_handle
) {
861 _gss_spnego_alloc_cred(&junk
,
863 delegated_cred_handle
);
864 } else if (mech_delegated_cred
!= GSS_C_NO_CREDENTIAL
)
865 gss_release_cred(&junk
, &mech_delegated_cred
);
867 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
) {
868 mech_output_token
= &obuf
;
870 if (ret
!= GSS_S_COMPLETE
&& ret
!= GSS_S_CONTINUE_NEEDED
) {
871 free_NegotiationToken(&nt
);
872 gss_mg_collect_error(ctx
->negotiated_mech_type
, ret
, minor
);
873 send_reject (minor_status
, output_token
);
874 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
877 if (ret
== GSS_S_COMPLETE
)
880 ret
= GSS_S_COMPLETE
;
882 ret2
= _gss_spnego_require_mechlist_mic(minor_status
,
888 ctx
->require_mic
= require_mic
;
890 mic
= na
->mechListMIC
;
894 if (ret
== GSS_S_COMPLETE
)
895 ret
= acceptor_complete(minor_status
,
904 if (ctx
->mech_flags
& GSS_C_DCE_STYLE
)
905 require_response
= (negResult
!= accept_completed
);
907 require_response
= 0;
910 * Check whether we need to send a result: there should be only
911 * one accept_completed response sent in the entire negotiation
913 if ((mech_output_token
!= GSS_C_NO_BUFFER
&&
914 mech_output_token
->length
!= 0)
915 || (ctx
->open
&& negResult
== accept_incomplete
)
918 ret2
= send_accept (minor_status
,
922 get_mic
? &mech_buf
: NULL
,
929 if (ret2
!= GSS_S_COMPLETE
)
931 if (mech_output_token
!= NULL
)
932 gss_release_buffer(&minor
, mech_output_token
);
933 if (mech_buf
.value
!= NULL
)
934 free(mech_buf
.value
);
935 free_NegotiationToken(&nt
);
938 if (ret
== GSS_S_COMPLETE
) {
939 if (src_name
!= NULL
&& ctx
->mech_src_name
!= NULL
) {
942 name
= calloc(1, sizeof(*name
));
944 name
->mech
= ctx
->mech_src_name
;
945 ctx
->mech_src_name
= NULL
;
946 *src_name
= (gss_name_t
)name
;
951 if (mech_type
!= NULL
)
952 *mech_type
= ctx
->negotiated_mech_type
;
953 if (ret_flags
!= NULL
)
954 *ret_flags
= ctx
->mech_flags
;
955 if (time_rec
!= NULL
)
956 *time_rec
= ctx
->mech_time_rec
;
958 if (ret
== GSS_S_COMPLETE
|| ret
== GSS_S_CONTINUE_NEEDED
) {
959 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
963 _gss_spnego_internal_delete_sec_context(&minor
, context_handle
,
970 _gss_spnego_accept_sec_context
971 (OM_uint32
* minor_status
,
972 gss_ctx_id_t
* context_handle
,
973 const gss_cred_id_t acceptor_cred_handle
,
974 const gss_buffer_t input_token_buffer
,
975 const gss_channel_bindings_t input_chan_bindings
,
976 gss_name_t
* src_name
,
978 gss_buffer_t output_token
,
979 OM_uint32
* ret_flags
,
980 OM_uint32
* time_rec
,
981 gss_cred_id_t
*delegated_cred_handle
984 _gss_accept_sec_context_t
*func
;
988 output_token
->length
= 0;
989 output_token
->value
= NULL
;
991 if (src_name
!= NULL
)
992 *src_name
= GSS_C_NO_NAME
;
993 if (mech_type
!= NULL
)
994 *mech_type
= GSS_C_NO_OID
;
995 if (ret_flags
!= NULL
)
997 if (time_rec
!= NULL
)
999 if (delegated_cred_handle
!= NULL
)
1000 *delegated_cred_handle
= GSS_C_NO_CREDENTIAL
;
1003 if (*context_handle
== GSS_C_NO_CONTEXT
)
1004 func
= acceptor_start
;
1006 func
= acceptor_continue
;
1009 return (*func
)(minor_status
, context_handle
, acceptor_cred_handle
,
1010 input_token_buffer
, input_chan_bindings
,
1011 src_name
, mech_type
, output_token
, ret_flags
,
1012 time_rec
, delegated_cred_handle
);