2 * Copyright (c) 2004, PADL Software Pty Ltd.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of PADL Software nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include "spnego_locl.h"
36 spnego_supported_mechs(OM_uint32
*minor_status
, gss_OID_set
*mechs
)
42 ret
= gss_indicate_mechs(minor_status
, &m
);
43 if (ret
!= GSS_S_COMPLETE
)
46 ret
= gss_create_empty_oid_set(minor_status
, mechs
);
47 if (ret
!= GSS_S_COMPLETE
) {
48 gss_release_oid_set(&junk
, &m
);
52 for (i
= 0; i
< m
->count
; i
++) {
53 if (gss_oid_equal(&m
->elements
[i
], GSS_SPNEGO_MECHANISM
))
56 ret
= gss_add_oid_set_member(minor_status
, &m
->elements
[i
], mechs
);
58 gss_release_oid_set(&junk
, &m
);
59 gss_release_oid_set(&junk
, mechs
);
63 gss_release_oid_set(&junk
, &m
);
69 OM_uint32 GSSAPI_CALLCONV _gss_spnego_process_context_token
70 (OM_uint32
*minor_status
,
71 gss_const_ctx_id_t context_handle
,
72 const gss_buffer_t token_buffer
79 if (context_handle
== GSS_C_NO_CONTEXT
)
80 return GSS_S_NO_CONTEXT
;
82 context
= (gss_ctx_id_t
)context_handle
;
83 ctx
= (gssspnego_ctx
)context_handle
;
85 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
87 ret
= gss_process_context_token(minor_status
,
88 ctx
->negotiated_ctx_id
,
90 if (ret
!= GSS_S_COMPLETE
) {
91 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
95 ctx
->negotiated_ctx_id
= GSS_C_NO_CONTEXT
;
97 return _gss_spnego_internal_delete_sec_context(minor_status
,
102 OM_uint32 GSSAPI_CALLCONV _gss_spnego_delete_sec_context
103 (OM_uint32
*minor_status
,
104 gss_ctx_id_t
*context_handle
,
105 gss_buffer_t output_token
110 if (context_handle
== NULL
|| *context_handle
== GSS_C_NO_CONTEXT
)
111 return GSS_S_NO_CONTEXT
;
113 ctx
= (gssspnego_ctx
)*context_handle
;
115 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
117 return _gss_spnego_internal_delete_sec_context(minor_status
,
122 OM_uint32 GSSAPI_CALLCONV _gss_spnego_context_time
123 (OM_uint32
*minor_status
,
124 gss_const_ctx_id_t context_handle
,
131 if (context_handle
== GSS_C_NO_CONTEXT
) {
132 return GSS_S_NO_CONTEXT
;
135 ctx
= (gssspnego_ctx
)context_handle
;
137 if (ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
) {
138 return GSS_S_NO_CONTEXT
;
141 return gss_context_time(minor_status
,
142 ctx
->negotiated_ctx_id
,
146 OM_uint32 GSSAPI_CALLCONV _gss_spnego_get_mic
147 (OM_uint32
*minor_status
,
148 gss_const_ctx_id_t context_handle
,
150 const gss_buffer_t message_buffer
,
151 gss_buffer_t message_token
158 if (context_handle
== GSS_C_NO_CONTEXT
) {
159 return GSS_S_NO_CONTEXT
;
162 ctx
= (gssspnego_ctx
)context_handle
;
164 if (ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
) {
165 return GSS_S_NO_CONTEXT
;
168 return gss_get_mic(minor_status
, ctx
->negotiated_ctx_id
,
169 qop_req
, message_buffer
, message_token
);
172 OM_uint32 GSSAPI_CALLCONV _gss_spnego_verify_mic
173 (OM_uint32
* minor_status
,
174 gss_const_ctx_id_t context_handle
,
175 const gss_buffer_t message_buffer
,
176 const gss_buffer_t token_buffer
,
177 gss_qop_t
* qop_state
184 if (context_handle
== GSS_C_NO_CONTEXT
) {
185 return GSS_S_NO_CONTEXT
;
188 ctx
= (gssspnego_ctx
)context_handle
;
190 if (ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
) {
191 return GSS_S_NO_CONTEXT
;
194 return gss_verify_mic(minor_status
,
195 ctx
->negotiated_ctx_id
,
201 OM_uint32 GSSAPI_CALLCONV _gss_spnego_wrap
202 (OM_uint32
* minor_status
,
203 gss_const_ctx_id_t context_handle
,
206 const gss_buffer_t input_message_buffer
,
208 gss_buffer_t output_message_buffer
215 if (context_handle
== GSS_C_NO_CONTEXT
) {
216 return GSS_S_NO_CONTEXT
;
219 ctx
= (gssspnego_ctx
)context_handle
;
221 if (ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
) {
222 return GSS_S_NO_CONTEXT
;
225 return gss_wrap(minor_status
,
226 ctx
->negotiated_ctx_id
,
229 input_message_buffer
,
231 output_message_buffer
);
234 OM_uint32 GSSAPI_CALLCONV _gss_spnego_unwrap
235 (OM_uint32
* minor_status
,
236 gss_const_ctx_id_t context_handle
,
237 const gss_buffer_t input_message_buffer
,
238 gss_buffer_t output_message_buffer
,
240 gss_qop_t
* qop_state
247 if (context_handle
== GSS_C_NO_CONTEXT
) {
248 return GSS_S_NO_CONTEXT
;
251 ctx
= (gssspnego_ctx
)context_handle
;
253 if (ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
) {
254 return GSS_S_NO_CONTEXT
;
257 return gss_unwrap(minor_status
,
258 ctx
->negotiated_ctx_id
,
259 input_message_buffer
,
260 output_message_buffer
,
265 OM_uint32 GSSAPI_CALLCONV _gss_spnego_compare_name
266 (OM_uint32
*minor_status
,
267 gss_const_name_t name1
,
268 gss_const_name_t name2
,
272 spnego_name n1
= (spnego_name
)name1
;
273 spnego_name n2
= (spnego_name
)name2
;
277 if (!gss_oid_equal(&n1
->type
, &n2
->type
))
278 return GSS_S_COMPLETE
;
279 if (n1
->value
.length
!= n2
->value
.length
)
280 return GSS_S_COMPLETE
;
281 if (memcmp(n1
->value
.value
, n2
->value
.value
, n2
->value
.length
) != 0)
282 return GSS_S_COMPLETE
;
286 return GSS_S_COMPLETE
;
289 OM_uint32 GSSAPI_CALLCONV _gss_spnego_display_name
290 (OM_uint32
* minor_status
,
291 gss_const_name_t input_name
,
292 gss_buffer_t output_name_buffer
,
293 gss_OID
* output_name_type
296 spnego_name name
= (spnego_name
)input_name
;
300 if (name
== NULL
|| name
->mech
== GSS_C_NO_NAME
)
301 return GSS_S_FAILURE
;
303 return gss_display_name(minor_status
, name
->mech
,
304 output_name_buffer
, output_name_type
);
307 OM_uint32 GSSAPI_CALLCONV _gss_spnego_import_name
308 (OM_uint32
* minor_status
,
309 const gss_buffer_t name_buffer
,
310 const gss_OID name_type
,
311 gss_name_t
* output_name
319 name
= calloc(1, sizeof(*name
));
321 *minor_status
= ENOMEM
;
322 return GSS_S_FAILURE
;
325 maj_stat
= _gss_copy_oid(minor_status
, name_type
, &name
->type
);
328 return GSS_S_FAILURE
;
331 maj_stat
= _gss_copy_buffer(minor_status
, name_buffer
, &name
->value
);
333 gss_name_t rname
= (gss_name_t
)name
;
334 _gss_spnego_release_name(minor_status
, &rname
);
335 return GSS_S_FAILURE
;
337 name
->mech
= GSS_C_NO_NAME
;
338 *output_name
= (gss_name_t
)name
;
340 return GSS_S_COMPLETE
;
343 OM_uint32 GSSAPI_CALLCONV _gss_spnego_export_name
344 (OM_uint32
* minor_status
,
345 gss_const_name_t input_name
,
346 gss_buffer_t exported_name
352 if (input_name
== GSS_C_NO_NAME
)
353 return GSS_S_BAD_NAME
;
355 name
= (spnego_name
)input_name
;
356 if (name
->mech
== GSS_C_NO_NAME
)
357 return GSS_S_BAD_NAME
;
359 return gss_export_name(minor_status
, name
->mech
, exported_name
);
362 OM_uint32 GSSAPI_CALLCONV _gss_spnego_release_name
363 (OM_uint32
* minor_status
,
364 gss_name_t
* input_name
369 if (*input_name
!= GSS_C_NO_NAME
) {
371 spnego_name name
= (spnego_name
)*input_name
;
372 _gss_free_oid(&junk
, &name
->type
);
373 gss_release_buffer(&junk
, &name
->value
);
374 if (name
->mech
!= GSS_C_NO_NAME
)
375 gss_release_name(&junk
, &name
->mech
);
378 *input_name
= GSS_C_NO_NAME
;
380 return GSS_S_COMPLETE
;
383 OM_uint32 GSSAPI_CALLCONV
_gss_spnego_inquire_context (
384 OM_uint32
* minor_status
,
385 gss_const_ctx_id_t context_handle
,
386 gss_name_t
* src_name
,
387 gss_name_t
* targ_name
,
388 OM_uint32
* lifetime_rec
,
390 OM_uint32
* ctx_flags
,
391 int * locally_initiated
,
396 OM_uint32 maj_stat
, junk
;
397 gss_name_t src_mn
, targ_mn
;
401 if (context_handle
== GSS_C_NO_CONTEXT
)
402 return GSS_S_NO_CONTEXT
;
404 ctx
= (gssspnego_ctx
)context_handle
;
406 if (ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
)
407 return GSS_S_NO_CONTEXT
;
409 maj_stat
= gss_inquire_context(minor_status
,
410 ctx
->negotiated_ctx_id
,
418 if (maj_stat
!= GSS_S_COMPLETE
)
422 spnego_name name
= calloc(1, sizeof(*name
));
426 *src_name
= (gss_name_t
)name
;
428 gss_release_name(&junk
, &src_mn
);
431 spnego_name name
= calloc(1, sizeof(*name
));
433 gss_release_name(minor_status
, src_name
);
436 name
->mech
= targ_mn
;
437 *targ_name
= (gss_name_t
)name
;
439 gss_release_name(&junk
, &targ_mn
);
441 return GSS_S_COMPLETE
;
444 gss_release_name(&junk
, &targ_mn
);
445 gss_release_name(&junk
, &src_mn
);
446 *minor_status
= ENOMEM
;
447 return GSS_S_FAILURE
;
450 OM_uint32 GSSAPI_CALLCONV
_gss_spnego_wrap_size_limit (
451 OM_uint32
* minor_status
,
452 gss_const_ctx_id_t context_handle
,
455 OM_uint32 req_output_size
,
456 OM_uint32
* max_input_size
463 if (context_handle
== GSS_C_NO_CONTEXT
) {
464 return GSS_S_NO_CONTEXT
;
467 ctx
= (gssspnego_ctx
)context_handle
;
469 if (ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
) {
470 return GSS_S_NO_CONTEXT
;
473 return gss_wrap_size_limit(minor_status
,
474 ctx
->negotiated_ctx_id
,
481 OM_uint32 GSSAPI_CALLCONV
_gss_spnego_export_sec_context (
482 OM_uint32
* minor_status
,
483 gss_ctx_id_t
* context_handle
,
484 gss_buffer_t interprocess_token
492 if (context_handle
== NULL
) {
493 return GSS_S_NO_CONTEXT
;
496 ctx
= (gssspnego_ctx
)*context_handle
;
499 return GSS_S_NO_CONTEXT
;
501 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
503 if (ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
) {
504 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
505 return GSS_S_NO_CONTEXT
;
508 ret
= gss_export_sec_context(minor_status
,
509 &ctx
->negotiated_ctx_id
,
511 if (ret
== GSS_S_COMPLETE
) {
512 ret
= _gss_spnego_internal_delete_sec_context(minor_status
,
515 if (ret
== GSS_S_COMPLETE
)
516 return GSS_S_COMPLETE
;
519 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
524 OM_uint32 GSSAPI_CALLCONV
_gss_spnego_import_sec_context (
525 OM_uint32
* minor_status
,
526 const gss_buffer_t interprocess_token
,
527 gss_ctx_id_t
*context_handle
530 OM_uint32 ret
, minor
;
531 gss_ctx_id_t context
;
534 ret
= _gss_spnego_alloc_sec_context(minor_status
, &context
);
535 if (ret
!= GSS_S_COMPLETE
) {
538 ctx
= (gssspnego_ctx
)context
;
540 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
542 ret
= gss_import_sec_context(minor_status
,
544 &ctx
->negotiated_ctx_id
);
545 if (ret
!= GSS_S_COMPLETE
) {
546 _gss_spnego_internal_delete_sec_context(&minor
, context_handle
, GSS_C_NO_BUFFER
);
551 /* don't bother filling in the rest of the fields */
553 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
555 *context_handle
= (gss_ctx_id_t
)ctx
;
557 return GSS_S_COMPLETE
;
560 OM_uint32 GSSAPI_CALLCONV
_gss_spnego_inquire_names_for_mech (
561 OM_uint32
* minor_status
,
562 const gss_OID mechanism
,
563 gss_OID_set
* name_types
566 gss_OID_set mechs
, names
, n
;
572 ret
= spnego_supported_mechs(minor_status
, &mechs
);
573 if (ret
!= GSS_S_COMPLETE
)
576 ret
= gss_create_empty_oid_set(minor_status
, &names
);
577 if (ret
!= GSS_S_COMPLETE
)
580 for (i
= 0; i
< mechs
->count
; i
++) {
581 ret
= gss_inquire_names_for_mech(minor_status
,
587 for (j
= 0; j
< n
->count
; j
++)
588 gss_add_oid_set_member(minor_status
,
591 gss_release_oid_set(&junk
, &n
);
594 ret
= GSS_S_COMPLETE
;
598 gss_release_oid_set(&junk
, &mechs
);
603 OM_uint32 GSSAPI_CALLCONV
_gss_spnego_inquire_mechs_for_name (
604 OM_uint32
* minor_status
,
605 gss_const_name_t input_name
,
606 gss_OID_set
* mech_types
611 ret
= gss_create_empty_oid_set(minor_status
, mech_types
);
615 ret
= gss_add_oid_set_member(minor_status
,
616 GSS_SPNEGO_MECHANISM
,
619 gss_release_oid_set(&junk
, mech_types
);
624 OM_uint32 GSSAPI_CALLCONV
_gss_spnego_canonicalize_name (
625 OM_uint32
* minor_status
,
626 gss_const_name_t input_name
,
627 const gss_OID mech_type
,
628 gss_name_t
* output_name
632 return gss_duplicate_name(minor_status
, input_name
, output_name
);
635 OM_uint32 GSSAPI_CALLCONV
_gss_spnego_duplicate_name (
636 OM_uint32
* minor_status
,
637 gss_const_name_t src_name
,
638 gss_name_t
* dest_name
641 return gss_duplicate_name(minor_status
, src_name
, dest_name
);
644 OM_uint32 GSSAPI_CALLCONV
645 _gss_spnego_wrap_iov(OM_uint32
* minor_status
,
646 gss_ctx_id_t context_handle
,
650 gss_iov_buffer_desc
*iov
,
653 gssspnego_ctx ctx
= (gssspnego_ctx
)context_handle
;
657 if (ctx
== NULL
|| ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
)
658 return GSS_S_NO_CONTEXT
;
660 return gss_wrap_iov(minor_status
, ctx
->negotiated_ctx_id
,
661 conf_req_flag
, qop_req
, conf_state
,
665 OM_uint32 GSSAPI_CALLCONV
666 _gss_spnego_unwrap_iov(OM_uint32
*minor_status
,
667 gss_ctx_id_t context_handle
,
669 gss_qop_t
*qop_state
,
670 gss_iov_buffer_desc
*iov
,
673 gssspnego_ctx ctx
= (gssspnego_ctx
)context_handle
;
677 if (ctx
== NULL
|| ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
)
678 return GSS_S_NO_CONTEXT
;
680 return gss_unwrap_iov(minor_status
,
681 ctx
->negotiated_ctx_id
,
682 conf_state
, qop_state
,
686 OM_uint32 GSSAPI_CALLCONV
687 _gss_spnego_wrap_iov_length(OM_uint32
* minor_status
,
688 gss_ctx_id_t context_handle
,
692 gss_iov_buffer_desc
*iov
,
695 gssspnego_ctx ctx
= (gssspnego_ctx
)context_handle
;
699 if (ctx
== NULL
|| ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
)
700 return GSS_S_NO_CONTEXT
;
702 return gss_wrap_iov_length(minor_status
, ctx
->negotiated_ctx_id
,
703 conf_req_flag
, qop_req
, conf_state
,
708 OM_uint32 GSSAPI_CALLCONV _gss_spnego_complete_auth_token
709 (OM_uint32
* minor_status
,
710 gss_const_ctx_id_t context_handle
,
711 gss_buffer_t input_message_buffer
)
717 if (context_handle
== GSS_C_NO_CONTEXT
) {
718 return GSS_S_NO_CONTEXT
;
721 ctx
= (gssspnego_ctx
)context_handle
;
723 if (ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
) {
724 return GSS_S_NO_CONTEXT
;
727 return gss_complete_auth_token(minor_status
,
728 ctx
->negotiated_ctx_id
,
729 input_message_buffer
);
733 OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_sec_context_by_oid
734 (OM_uint32
* minor_status
,
735 gss_const_ctx_id_t context_handle
,
736 const gss_OID desired_object
,
737 gss_buffer_set_t
*data_set
)
743 if (context_handle
== GSS_C_NO_CONTEXT
) {
744 return GSS_S_NO_CONTEXT
;
747 ctx
= (gssspnego_ctx
)context_handle
;
749 if (ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
) {
750 return GSS_S_NO_CONTEXT
;
753 return gss_inquire_sec_context_by_oid(minor_status
,
754 ctx
->negotiated_ctx_id
,
759 OM_uint32 GSSAPI_CALLCONV _gss_spnego_set_sec_context_option
760 (OM_uint32
* minor_status
,
761 gss_ctx_id_t
* context_handle
,
762 const gss_OID desired_object
,
763 const gss_buffer_t value
)
769 if (context_handle
== NULL
|| *context_handle
== GSS_C_NO_CONTEXT
) {
770 return GSS_S_NO_CONTEXT
;
773 ctx
= (gssspnego_ctx
)*context_handle
;
775 if (ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
) {
776 return GSS_S_NO_CONTEXT
;
779 return gss_set_sec_context_option(minor_status
,
780 &ctx
->negotiated_ctx_id
,
786 OM_uint32 GSSAPI_CALLCONV
787 _gss_spnego_pseudo_random(OM_uint32
*minor_status
,
788 gss_ctx_id_t context_handle
,
790 const gss_buffer_t prf_in
,
791 ssize_t desired_output_len
,
792 gss_buffer_t prf_out
)
798 if (context_handle
== GSS_C_NO_CONTEXT
)
799 return GSS_S_NO_CONTEXT
;
801 ctx
= (gssspnego_ctx
)context_handle
;
803 if (ctx
->negotiated_ctx_id
== GSS_C_NO_CONTEXT
)
804 return GSS_S_NO_CONTEXT
;
806 return gss_pseudo_random(minor_status
,
807 ctx
->negotiated_ctx_id
,