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 const gss_ctx_id_t context_handle,
72 const gss_buffer_t token_buffer
75 gss_ctx_id_t context ;
79 if (context_handle == GSS_C_NO_CONTEXT)
80 return GSS_S_NO_CONTEXT;
82 context = 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 const gss_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 const gss_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 const gss_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 const gss_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 const gss_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 const gss_name_t name1,
268 const gss_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 const gss_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 const gss_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 const gss_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 const gss_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 const gss_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 const gss_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 const gss_name_t src_name,
638 gss_name_t * dest_name
641 return gss_duplicate_name(minor_status, src_name, dest_name);
645 OM_uint32 GSSAPI_CALLCONV
646 _gss_spnego_wrap_iov(OM_uint32 * minor_status,
647 gss_ctx_id_t context_handle,
651 gss_iov_buffer_desc *iov,
654 gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
658 if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
659 return GSS_S_NO_CONTEXT;
661 return gss_wrap_iov(minor_status, ctx->negotiated_ctx_id,
662 conf_req_flag, qop_req, conf_state,
666 OM_uint32 GSSAPI_CALLCONV
667 _gss_spnego_unwrap_iov(OM_uint32 *minor_status,
668 gss_ctx_id_t context_handle,
670 gss_qop_t *qop_state,
671 gss_iov_buffer_desc *iov,
674 gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
678 if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
679 return GSS_S_NO_CONTEXT;
681 return gss_unwrap_iov(minor_status,
682 ctx->negotiated_ctx_id,
683 conf_state, qop_state,
687 OM_uint32 GSSAPI_CALLCONV
688 _gss_spnego_wrap_iov_length(OM_uint32 * minor_status,
689 gss_ctx_id_t context_handle,
693 gss_iov_buffer_desc *iov,
696 gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
700 if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
701 return GSS_S_NO_CONTEXT;
703 return gss_wrap_iov_length(minor_status, ctx->negotiated_ctx_id,
704 conf_req_flag, qop_req, conf_state,
711 OM_uint32 GSSAPI_CALLCONV _gss_spnego_complete_auth_token
712 (OM_uint32 * minor_status,
713 const gss_ctx_id_t context_handle,
714 gss_buffer_t input_message_buffer)
720 if (context_handle == GSS_C_NO_CONTEXT) {
721 return GSS_S_NO_CONTEXT;
724 ctx = (gssspnego_ctx)context_handle;
726 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
727 return GSS_S_NO_CONTEXT;
730 return gss_complete_auth_token(minor_status,
731 ctx->negotiated_ctx_id,
732 input_message_buffer);
736 OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_sec_context_by_oid
737 (OM_uint32 * minor_status,
738 const gss_ctx_id_t context_handle,
739 const gss_OID desired_object,
740 gss_buffer_set_t *data_set)
746 if (context_handle == GSS_C_NO_CONTEXT) {
747 return GSS_S_NO_CONTEXT;
750 ctx = (gssspnego_ctx)context_handle;
752 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
753 return GSS_S_NO_CONTEXT;
756 return gss_inquire_sec_context_by_oid(minor_status,
757 ctx->negotiated_ctx_id,
762 OM_uint32 GSSAPI_CALLCONV _gss_spnego_set_sec_context_option
763 (OM_uint32 * minor_status,
764 gss_ctx_id_t * context_handle,
765 const gss_OID desired_object,
766 const gss_buffer_t value)
772 if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) {
773 return GSS_S_NO_CONTEXT;
776 ctx = (gssspnego_ctx)*context_handle;
778 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
779 return GSS_S_NO_CONTEXT;
782 return gss_set_sec_context_option(minor_status,
783 &ctx->negotiated_ctx_id,
789 OM_uint32 GSSAPI_CALLCONV
790 _gss_spnego_pseudo_random(OM_uint32 *minor_status,
791 gss_ctx_id_t context_handle,
793 const gss_buffer_t prf_in,
794 ssize_t desired_output_len,
795 gss_buffer_t prf_out)
801 if (context_handle == GSS_C_NO_CONTEXT)
802 return GSS_S_NO_CONTEXT;
804 ctx = (gssspnego_ctx)context_handle;
806 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
807 return GSS_S_NO_CONTEXT;
809 return gss_pseudo_random(minor_status,
810 ctx->negotiated_ctx_id,