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"
35 OM_uint32 GSSAPI_CALLCONV _gss_spnego_process_context_token
36 (OM_uint32 *minor_status,
37 gss_const_ctx_id_t context_handle,
38 const gss_buffer_t token_buffer
45 if (context_handle == GSS_C_NO_CONTEXT)
46 return GSS_S_NO_CONTEXT;
48 context = (gss_ctx_id_t)context_handle;
49 ctx = (gssspnego_ctx)context_handle;
51 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
53 ret = gss_process_context_token(minor_status,
54 ctx->negotiated_ctx_id,
56 if (ret != GSS_S_COMPLETE) {
57 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
61 ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
63 return _gss_spnego_internal_delete_sec_context(minor_status,
68 OM_uint32 GSSAPI_CALLCONV _gss_spnego_delete_sec_context
69 (OM_uint32 *minor_status,
70 gss_ctx_id_t *context_handle,
71 gss_buffer_t output_token
76 if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
77 return GSS_S_NO_CONTEXT;
79 ctx = (gssspnego_ctx)*context_handle;
81 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
83 return _gss_spnego_internal_delete_sec_context(minor_status,
88 OM_uint32 GSSAPI_CALLCONV _gss_spnego_context_time
89 (OM_uint32 *minor_status,
90 gss_const_ctx_id_t context_handle,
97 if (context_handle == GSS_C_NO_CONTEXT) {
98 return GSS_S_NO_CONTEXT;
101 ctx = (gssspnego_ctx)context_handle;
103 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
104 return GSS_S_NO_CONTEXT;
107 return gss_context_time(minor_status,
108 ctx->negotiated_ctx_id,
112 OM_uint32 GSSAPI_CALLCONV _gss_spnego_get_mic
113 (OM_uint32 *minor_status,
114 gss_const_ctx_id_t context_handle,
116 const gss_buffer_t message_buffer,
117 gss_buffer_t message_token
124 if (context_handle == GSS_C_NO_CONTEXT) {
125 return GSS_S_NO_CONTEXT;
128 ctx = (gssspnego_ctx)context_handle;
130 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
131 return GSS_S_NO_CONTEXT;
134 return gss_get_mic(minor_status, ctx->negotiated_ctx_id,
135 qop_req, message_buffer, message_token);
138 OM_uint32 GSSAPI_CALLCONV _gss_spnego_verify_mic
139 (OM_uint32 * minor_status,
140 gss_const_ctx_id_t context_handle,
141 const gss_buffer_t message_buffer,
142 const gss_buffer_t token_buffer,
143 gss_qop_t * qop_state
150 if (context_handle == GSS_C_NO_CONTEXT) {
151 return GSS_S_NO_CONTEXT;
154 ctx = (gssspnego_ctx)context_handle;
156 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
157 return GSS_S_NO_CONTEXT;
160 return gss_verify_mic(minor_status,
161 ctx->negotiated_ctx_id,
167 OM_uint32 GSSAPI_CALLCONV _gss_spnego_wrap
168 (OM_uint32 * minor_status,
169 gss_const_ctx_id_t context_handle,
172 const gss_buffer_t input_message_buffer,
174 gss_buffer_t output_message_buffer
181 if (context_handle == GSS_C_NO_CONTEXT) {
182 return GSS_S_NO_CONTEXT;
185 ctx = (gssspnego_ctx)context_handle;
187 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
188 return GSS_S_NO_CONTEXT;
191 return gss_wrap(minor_status,
192 ctx->negotiated_ctx_id,
195 input_message_buffer,
197 output_message_buffer);
200 OM_uint32 GSSAPI_CALLCONV _gss_spnego_unwrap
201 (OM_uint32 * minor_status,
202 gss_const_ctx_id_t context_handle,
203 const gss_buffer_t input_message_buffer,
204 gss_buffer_t output_message_buffer,
206 gss_qop_t * qop_state
213 if (context_handle == GSS_C_NO_CONTEXT) {
214 return GSS_S_NO_CONTEXT;
217 ctx = (gssspnego_ctx)context_handle;
219 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
220 return GSS_S_NO_CONTEXT;
223 return gss_unwrap(minor_status,
224 ctx->negotiated_ctx_id,
225 input_message_buffer,
226 output_message_buffer,
231 OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_context (
232 OM_uint32 * minor_status,
233 gss_const_ctx_id_t context_handle,
234 gss_name_t * src_name,
235 gss_name_t * targ_name,
236 OM_uint32 * lifetime_rec,
238 OM_uint32 * ctx_flags,
239 int * locally_initiated,
248 if (context_handle == GSS_C_NO_CONTEXT)
249 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;
256 maj_stat = gss_inquire_context(minor_status,
257 ctx->negotiated_ctx_id,
267 *open_context = gssspnego_ctx_complete_p(ctx);
272 OM_uint32 GSSAPI_CALLCONV _gss_spnego_wrap_size_limit (
273 OM_uint32 * minor_status,
274 gss_const_ctx_id_t context_handle,
277 OM_uint32 req_output_size,
278 OM_uint32 * max_input_size
285 if (context_handle == GSS_C_NO_CONTEXT) {
286 return GSS_S_NO_CONTEXT;
289 ctx = (gssspnego_ctx)context_handle;
291 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
292 return GSS_S_NO_CONTEXT;
295 return gss_wrap_size_limit(minor_status,
296 ctx->negotiated_ctx_id,
303 OM_uint32 GSSAPI_CALLCONV _gss_spnego_export_sec_context (
304 OM_uint32 * minor_status,
305 gss_ctx_id_t * context_handle,
306 gss_buffer_t interprocess_token
310 OM_uint32 major_status;
314 if (context_handle == NULL)
315 return GSS_S_NO_CONTEXT;
317 ctx = (gssspnego_ctx)*context_handle;
320 return GSS_S_NO_CONTEXT;
322 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
325 * Partial context export is only supported on the acceptor side, as we
326 * cannot represent the initiator function pointer state in an exported
327 * token, and also because it is mostly useful for acceptors which need
328 * to manage multiple initiator states.
330 if (ctx->flags.local && !gssspnego_ctx_complete_p(ctx)) {
331 major_status = GSS_S_NO_CONTEXT;
335 major_status = _gss_spnego_export_sec_context_internal(minor_status,
340 if (major_status == GSS_S_COMPLETE)
341 major_status = _gss_spnego_internal_delete_sec_context(minor_status,
345 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
350 OM_uint32 GSSAPI_CALLCONV _gss_spnego_import_sec_context (
351 OM_uint32 * minor_status,
352 const gss_buffer_t interprocess_token,
353 gss_ctx_id_t *context_handle
356 return _gss_spnego_import_sec_context_internal(minor_status,
358 (gssspnego_ctx *)context_handle);
361 OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_names_for_mech (
362 OM_uint32 * minor_status,
363 const gss_OID mechanism,
364 gss_OID_set * name_types
367 gss_OID_set mechs, names, n;
373 ret = _gss_spnego_indicate_mechs(minor_status, &mechs);
374 if (ret != GSS_S_COMPLETE)
377 ret = gss_create_empty_oid_set(minor_status, &names);
378 if (ret != GSS_S_COMPLETE)
381 for (i = 0; i < mechs->count; i++) {
382 ret = gss_inquire_names_for_mech(minor_status,
388 for (j = 0; j < n->count; j++)
389 gss_add_oid_set_member(minor_status,
392 gss_release_oid_set(&junk, &n);
395 ret = GSS_S_COMPLETE;
399 gss_release_oid_set(&junk, &mechs);
404 OM_uint32 GSSAPI_CALLCONV
405 _gss_spnego_wrap_iov(OM_uint32 * minor_status,
406 gss_ctx_id_t context_handle,
410 gss_iov_buffer_desc *iov,
413 gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
417 if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
418 return GSS_S_NO_CONTEXT;
420 return gss_wrap_iov(minor_status, ctx->negotiated_ctx_id,
421 conf_req_flag, qop_req, conf_state,
425 OM_uint32 GSSAPI_CALLCONV
426 _gss_spnego_unwrap_iov(OM_uint32 *minor_status,
427 gss_ctx_id_t context_handle,
429 gss_qop_t *qop_state,
430 gss_iov_buffer_desc *iov,
433 gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
437 if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
438 return GSS_S_NO_CONTEXT;
440 return gss_unwrap_iov(minor_status,
441 ctx->negotiated_ctx_id,
442 conf_state, qop_state,
446 OM_uint32 GSSAPI_CALLCONV
447 _gss_spnego_wrap_iov_length(OM_uint32 * minor_status,
448 gss_ctx_id_t context_handle,
452 gss_iov_buffer_desc *iov,
455 gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
459 if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
460 return GSS_S_NO_CONTEXT;
462 return gss_wrap_iov_length(minor_status, ctx->negotiated_ctx_id,
463 conf_req_flag, qop_req, conf_state,
468 OM_uint32 GSSAPI_CALLCONV _gss_spnego_complete_auth_token
469 (OM_uint32 * minor_status,
470 gss_const_ctx_id_t context_handle,
471 gss_buffer_t input_message_buffer)
477 if (context_handle == GSS_C_NO_CONTEXT) {
478 return GSS_S_NO_CONTEXT;
481 ctx = (gssspnego_ctx)context_handle;
483 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
484 return GSS_S_NO_CONTEXT;
487 return gss_complete_auth_token(minor_status,
488 ctx->negotiated_ctx_id,
489 input_message_buffer);
493 OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_sec_context_by_oid
494 (OM_uint32 * minor_status,
495 gss_const_ctx_id_t context_handle,
496 const gss_OID desired_object,
497 gss_buffer_set_t *data_set)
503 if (context_handle == GSS_C_NO_CONTEXT) {
504 return GSS_S_NO_CONTEXT;
507 ctx = (gssspnego_ctx)context_handle;
509 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
510 return GSS_S_NO_CONTEXT;
513 return gss_inquire_sec_context_by_oid(minor_status,
514 ctx->negotiated_ctx_id,
519 OM_uint32 GSSAPI_CALLCONV _gss_spnego_set_sec_context_option
520 (OM_uint32 * minor_status,
521 gss_ctx_id_t * context_handle,
522 const gss_OID desired_object,
523 const gss_buffer_t value)
530 * Return GSS_S_UNAVAILABLE with a NULL context handle as at
531 * present no context options can be set globally on SPNEGO
532 * itself. Global mechanism context options are set directly
533 * on the mechanism; per-context context options are set below
534 * if ctx->negotiated_ctx_id != GSS_C_NO_CONTEXT.
536 if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
537 return GSS_S_UNAVAILABLE;
539 ctx = (gssspnego_ctx)*context_handle;
541 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
542 return GSS_S_NO_CONTEXT;
545 return gss_set_sec_context_option(minor_status,
546 &ctx->negotiated_ctx_id,
552 OM_uint32 GSSAPI_CALLCONV
553 _gss_spnego_pseudo_random(OM_uint32 *minor_status,
554 gss_ctx_id_t context_handle,
556 const gss_buffer_t prf_in,
557 ssize_t desired_output_len,
558 gss_buffer_t prf_out)
564 if (context_handle == GSS_C_NO_CONTEXT)
565 return GSS_S_NO_CONTEXT;
567 ctx = (gssspnego_ctx)context_handle;
569 if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
570 return GSS_S_NO_CONTEXT;
572 return gss_pseudo_random(minor_status,
573 ctx->negotiated_ctx_id,