1/*
2 * Copyright (c) 2004, PADL Software Pty Ltd.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 *
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.
15 *
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.
19 *
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
30 * SUCH DAMAGE.
31 */
32
33#include "spnego/spnego_locl.h"
34
35RCSID("$Id: context_stubs.c 21035 2007-06-09 15:32:47Z lha $");
36
37static OM_uint32
38spnego_supported_mechs(OM_uint32 *minor_status, gss_OID_set *mechs)
39{
40    OM_uint32 ret, junk;
41    gss_OID_set m;
42    int i;
43
44    ret = gss_indicate_mechs(minor_status, &m);
45    if (ret != GSS_S_COMPLETE)
46	return ret;
47
48    ret = gss_create_empty_oid_set(minor_status, mechs);
49    if (ret != GSS_S_COMPLETE) {
50	gss_release_oid_set(&junk, &m);
51	return ret;
52    }
53
54    for (i = 0; i < m->count; i++) {
55	if (gss_oid_equal(&m->elements[i], GSS_SPNEGO_MECHANISM))
56	    continue;
57
58	ret = gss_add_oid_set_member(minor_status, &m->elements[i], mechs);
59	if (ret) {
60	    gss_release_oid_set(&junk, &m);
61	    gss_release_oid_set(&junk, mechs);
62	    return ret;
63	}
64    }
65    return ret;
66}
67
68
69
70OM_uint32 _gss_spnego_process_context_token
71           (OM_uint32 *minor_status,
72            const gss_ctx_id_t context_handle,
73            const gss_buffer_t token_buffer
74           )
75{
76    gss_ctx_id_t context ;
77    gssspnego_ctx ctx;
78    OM_uint32 ret;
79
80    if (context_handle == GSS_C_NO_CONTEXT)
81	return GSS_S_NO_CONTEXT;
82
83    context = context_handle;
84    ctx = (gssspnego_ctx)context_handle;
85
86    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
87
88    ret = gss_process_context_token(minor_status,
89				    ctx->negotiated_ctx_id,
90				    token_buffer);
91    if (ret != GSS_S_COMPLETE) {
92	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
93	return ret;
94    }
95
96    ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
97
98    return _gss_spnego_internal_delete_sec_context(minor_status,
99					   &context,
100					   GSS_C_NO_BUFFER);
101}
102
103OM_uint32 _gss_spnego_delete_sec_context
104           (OM_uint32 *minor_status,
105            gss_ctx_id_t *context_handle,
106            gss_buffer_t output_token
107           )
108{
109    gssspnego_ctx ctx;
110
111    if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
112	return GSS_S_NO_CONTEXT;
113
114    ctx = (gssspnego_ctx)*context_handle;
115
116    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
117
118    return _gss_spnego_internal_delete_sec_context(minor_status,
119						   context_handle,
120						   output_token);
121}
122
123OM_uint32 _gss_spnego_context_time
124           (OM_uint32 *minor_status,
125            const gss_ctx_id_t context_handle,
126            OM_uint32 *time_rec
127           )
128{
129    gssspnego_ctx ctx;
130    *minor_status = 0;
131
132    if (context_handle == GSS_C_NO_CONTEXT) {
133	return GSS_S_NO_CONTEXT;
134    }
135
136    ctx = (gssspnego_ctx)context_handle;
137
138    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
139	return GSS_S_NO_CONTEXT;
140    }
141
142    return gss_context_time(minor_status,
143			    ctx->negotiated_ctx_id,
144			    time_rec);
145}
146
147OM_uint32 _gss_spnego_get_mic
148           (OM_uint32 *minor_status,
149            const gss_ctx_id_t context_handle,
150            gss_qop_t qop_req,
151            const gss_buffer_t message_buffer,
152            gss_buffer_t message_token
153           )
154{
155    gssspnego_ctx ctx;
156
157    *minor_status = 0;
158
159    if (context_handle == GSS_C_NO_CONTEXT) {
160	return GSS_S_NO_CONTEXT;
161    }
162
163    ctx = (gssspnego_ctx)context_handle;
164
165    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
166	return GSS_S_NO_CONTEXT;
167    }
168
169    return gss_get_mic(minor_status, ctx->negotiated_ctx_id,
170		       qop_req, message_buffer, message_token);
171}
172
173OM_uint32 _gss_spnego_verify_mic
174           (OM_uint32 * minor_status,
175            const gss_ctx_id_t context_handle,
176            const gss_buffer_t message_buffer,
177            const gss_buffer_t token_buffer,
178            gss_qop_t * qop_state
179           )
180{
181    gssspnego_ctx ctx;
182
183    *minor_status = 0;
184
185    if (context_handle == GSS_C_NO_CONTEXT) {
186	return GSS_S_NO_CONTEXT;
187    }
188
189    ctx = (gssspnego_ctx)context_handle;
190
191    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
192	return GSS_S_NO_CONTEXT;
193    }
194
195    return gss_verify_mic(minor_status,
196			  ctx->negotiated_ctx_id,
197			  message_buffer,
198			  token_buffer,
199			  qop_state);
200}
201
202OM_uint32 _gss_spnego_wrap
203           (OM_uint32 * minor_status,
204            const gss_ctx_id_t context_handle,
205            int conf_req_flag,
206            gss_qop_t qop_req,
207            const gss_buffer_t input_message_buffer,
208            int * conf_state,
209            gss_buffer_t output_message_buffer
210           )
211{
212    gssspnego_ctx ctx;
213
214    *minor_status = 0;
215
216    if (context_handle == GSS_C_NO_CONTEXT) {
217	return GSS_S_NO_CONTEXT;
218    }
219
220    ctx = (gssspnego_ctx)context_handle;
221
222    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
223	return GSS_S_NO_CONTEXT;
224    }
225
226    return gss_wrap(minor_status,
227		    ctx->negotiated_ctx_id,
228		    conf_req_flag,
229		    qop_req,
230		    input_message_buffer,
231		    conf_state,
232		    output_message_buffer);
233}
234
235OM_uint32 _gss_spnego_unwrap
236           (OM_uint32 * minor_status,
237            const gss_ctx_id_t context_handle,
238            const gss_buffer_t input_message_buffer,
239            gss_buffer_t output_message_buffer,
240            int * conf_state,
241            gss_qop_t * qop_state
242           )
243{
244    gssspnego_ctx ctx;
245
246    *minor_status = 0;
247
248    if (context_handle == GSS_C_NO_CONTEXT) {
249	return GSS_S_NO_CONTEXT;
250    }
251
252    ctx = (gssspnego_ctx)context_handle;
253
254    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
255	return GSS_S_NO_CONTEXT;
256    }
257
258    return gss_unwrap(minor_status,
259		      ctx->negotiated_ctx_id,
260		      input_message_buffer,
261		      output_message_buffer,
262		      conf_state,
263		      qop_state);
264}
265
266OM_uint32 _gss_spnego_display_status
267           (OM_uint32 * minor_status,
268            OM_uint32 status_value,
269            int status_type,
270            const gss_OID mech_type,
271            OM_uint32 * message_context,
272            gss_buffer_t status_string
273           )
274{
275    return GSS_S_FAILURE;
276}
277
278OM_uint32 _gss_spnego_compare_name
279           (OM_uint32 *minor_status,
280            const gss_name_t name1,
281            const gss_name_t name2,
282            int * name_equal
283           )
284{
285    spnego_name n1 = (spnego_name)name1;
286    spnego_name n2 = (spnego_name)name2;
287
288    *name_equal = 0;
289
290    if (!gss_oid_equal(&n1->type, &n2->type))
291	return GSS_S_COMPLETE;
292    if (n1->value.length != n2->value.length)
293	return GSS_S_COMPLETE;
294    if (memcmp(n1->value.value, n2->value.value, n2->value.length) != 0)
295	return GSS_S_COMPLETE;
296
297    *name_equal = 1;
298
299    return GSS_S_COMPLETE;
300}
301
302OM_uint32 _gss_spnego_display_name
303           (OM_uint32 * minor_status,
304            const gss_name_t input_name,
305            gss_buffer_t output_name_buffer,
306            gss_OID * output_name_type
307           )
308{
309    spnego_name name = (spnego_name)input_name;
310
311    *minor_status = 0;
312
313    if (name == NULL || name->mech == GSS_C_NO_NAME)
314	return GSS_S_FAILURE;
315
316    return gss_display_name(minor_status, name->mech,
317			    output_name_buffer, output_name_type);
318}
319
320OM_uint32 _gss_spnego_import_name
321           (OM_uint32 * minor_status,
322            const gss_buffer_t name_buffer,
323            const gss_OID name_type,
324            gss_name_t * output_name
325           )
326{
327    spnego_name name;
328    OM_uint32 maj_stat;
329
330    *minor_status = 0;
331
332    name = calloc(1, sizeof(*name));
333    if (name == NULL) {
334	*minor_status = ENOMEM;
335	return GSS_S_FAILURE;
336    }
337
338    maj_stat = _gss_copy_oid(minor_status, name_type, &name->type);
339    if (maj_stat) {
340	free(name);
341	return GSS_S_FAILURE;
342    }
343
344    maj_stat = _gss_copy_buffer(minor_status, name_buffer, &name->value);
345    if (maj_stat) {
346	gss_name_t rname = (gss_name_t)name;
347	_gss_spnego_release_name(minor_status, &rname);
348	return GSS_S_FAILURE;
349    }
350    name->mech = GSS_C_NO_NAME;
351    *output_name = (gss_name_t)name;
352
353    return GSS_S_COMPLETE;
354}
355
356OM_uint32 _gss_spnego_export_name
357           (OM_uint32  * minor_status,
358            const gss_name_t input_name,
359            gss_buffer_t exported_name
360           )
361{
362    spnego_name name;
363    *minor_status = 0;
364
365    if (input_name == GSS_C_NO_NAME)
366	return GSS_S_BAD_NAME;
367
368    name = (spnego_name)input_name;
369    if (name->mech == GSS_C_NO_NAME)
370	return GSS_S_BAD_NAME;
371
372    return gss_export_name(minor_status, name->mech, exported_name);
373}
374
375OM_uint32 _gss_spnego_release_name
376           (OM_uint32 * minor_status,
377            gss_name_t * input_name
378           )
379{
380    *minor_status = 0;
381
382    if (*input_name != GSS_C_NO_NAME) {
383	OM_uint32 junk;
384	spnego_name name = (spnego_name)*input_name;
385	_gss_free_oid(&junk, &name->type);
386	gss_release_buffer(&junk, &name->value);
387	if (name->mech != GSS_C_NO_NAME)
388	    gss_release_name(&junk, &name->mech);
389	free(name);
390
391	*input_name = GSS_C_NO_NAME;
392    }
393    return GSS_S_COMPLETE;
394}
395
396OM_uint32 _gss_spnego_inquire_context (
397            OM_uint32 * minor_status,
398            const gss_ctx_id_t context_handle,
399            gss_name_t * src_name,
400            gss_name_t * targ_name,
401            OM_uint32 * lifetime_rec,
402            gss_OID * mech_type,
403            OM_uint32 * ctx_flags,
404            int * locally_initiated,
405            int * open_context
406           )
407{
408    gssspnego_ctx ctx;
409
410    *minor_status = 0;
411
412    if (context_handle == GSS_C_NO_CONTEXT) {
413	return GSS_S_NO_CONTEXT;
414    }
415
416    ctx = (gssspnego_ctx)context_handle;
417
418    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
419	return GSS_S_NO_CONTEXT;
420    }
421
422    return gss_inquire_context(minor_status,
423			       ctx->negotiated_ctx_id,
424			       src_name,
425			       targ_name,
426			       lifetime_rec,
427			       mech_type,
428			       ctx_flags,
429			       locally_initiated,
430			       open_context);
431}
432
433OM_uint32 _gss_spnego_wrap_size_limit (
434            OM_uint32 * minor_status,
435            const gss_ctx_id_t context_handle,
436            int conf_req_flag,
437            gss_qop_t qop_req,
438            OM_uint32 req_output_size,
439            OM_uint32 * max_input_size
440           )
441{
442    gssspnego_ctx ctx;
443
444    *minor_status = 0;
445
446    if (context_handle == GSS_C_NO_CONTEXT) {
447	return GSS_S_NO_CONTEXT;
448    }
449
450    ctx = (gssspnego_ctx)context_handle;
451
452    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
453	return GSS_S_NO_CONTEXT;
454    }
455
456    return gss_wrap_size_limit(minor_status,
457			       ctx->negotiated_ctx_id,
458			       conf_req_flag,
459			       qop_req,
460			       req_output_size,
461			       max_input_size);
462}
463
464OM_uint32 _gss_spnego_export_sec_context (
465            OM_uint32 * minor_status,
466            gss_ctx_id_t * context_handle,
467            gss_buffer_t interprocess_token
468           )
469{
470    gssspnego_ctx ctx;
471    OM_uint32 ret;
472
473    *minor_status = 0;
474
475    if (context_handle == NULL) {
476	return GSS_S_NO_CONTEXT;
477    }
478
479    ctx = (gssspnego_ctx)*context_handle;
480
481    if (ctx == NULL)
482	return GSS_S_NO_CONTEXT;
483
484    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
485
486    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
487	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
488	return GSS_S_NO_CONTEXT;
489    }
490
491    ret = gss_export_sec_context(minor_status,
492				 &ctx->negotiated_ctx_id,
493				 interprocess_token);
494    if (ret == GSS_S_COMPLETE) {
495	ret = _gss_spnego_internal_delete_sec_context(minor_status,
496					     context_handle,
497					     GSS_C_NO_BUFFER);
498	if (ret == GSS_S_COMPLETE)
499	    return GSS_S_COMPLETE;
500    }
501
502    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
503
504    return ret;
505}
506
507OM_uint32 _gss_spnego_import_sec_context (
508            OM_uint32 * minor_status,
509            const gss_buffer_t interprocess_token,
510            gss_ctx_id_t *context_handle
511           )
512{
513    OM_uint32 ret, minor;
514    gss_ctx_id_t context;
515    gssspnego_ctx ctx;
516
517    ret = _gss_spnego_alloc_sec_context(minor_status, &context);
518    if (ret != GSS_S_COMPLETE) {
519	return ret;
520    }
521    ctx = (gssspnego_ctx)context;
522
523    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
524
525    ret = gss_import_sec_context(minor_status,
526				 interprocess_token,
527				 &ctx->negotiated_ctx_id);
528    if (ret != GSS_S_COMPLETE) {
529	_gss_spnego_internal_delete_sec_context(&minor, context_handle, GSS_C_NO_BUFFER);
530	return ret;
531    }
532
533    ctx->open = 1;
534    /* don't bother filling in the rest of the fields */
535
536    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
537
538    *context_handle = (gss_ctx_id_t)ctx;
539
540    return GSS_S_COMPLETE;
541}
542
543OM_uint32 _gss_spnego_inquire_names_for_mech (
544            OM_uint32 * minor_status,
545            const gss_OID mechanism,
546            gss_OID_set * name_types
547           )
548{
549    gss_OID_set mechs, names, n;
550    OM_uint32 ret, junk;
551    int i, j;
552
553    *name_types = NULL;
554
555    ret = spnego_supported_mechs(minor_status, &mechs);
556    if (ret != GSS_S_COMPLETE)
557	return ret;
558
559    ret = gss_create_empty_oid_set(minor_status, &names);
560    if (ret != GSS_S_COMPLETE)
561	goto out;
562
563    for (i = 0; i < mechs->count; i++) {
564	ret = gss_inquire_names_for_mech(minor_status,
565					 &mechs->elements[i],
566					 &n);
567	if (ret)
568	    continue;
569
570	for (j = 0; j < n->count; j++)
571	    gss_add_oid_set_member(minor_status,
572				   &n->elements[j],
573				   &names);
574	gss_release_oid_set(&junk, &n);
575    }
576
577    ret = GSS_S_COMPLETE;
578    *name_types = names;
579out:
580
581    gss_release_oid_set(&junk, &mechs);
582
583    return GSS_S_COMPLETE;
584}
585
586OM_uint32 _gss_spnego_inquire_mechs_for_name (
587            OM_uint32 * minor_status,
588            const gss_name_t input_name,
589            gss_OID_set * mech_types
590           )
591{
592    OM_uint32 ret, junk;
593
594    ret = gss_create_empty_oid_set(minor_status, mech_types);
595    if (ret)
596	return ret;
597
598    ret = gss_add_oid_set_member(minor_status,
599				 GSS_SPNEGO_MECHANISM,
600				 mech_types);
601    if (ret)
602	gss_release_oid_set(&junk, mech_types);
603
604    return ret;
605}
606
607OM_uint32 _gss_spnego_canonicalize_name (
608            OM_uint32 * minor_status,
609            const gss_name_t input_name,
610            const gss_OID mech_type,
611            gss_name_t * output_name
612           )
613{
614    /* XXX */
615    return gss_duplicate_name(minor_status, input_name, output_name);
616}
617
618OM_uint32 _gss_spnego_duplicate_name (
619            OM_uint32 * minor_status,
620            const gss_name_t src_name,
621            gss_name_t * dest_name
622           )
623{
624    return gss_duplicate_name(minor_status, src_name, dest_name);
625}
626
627OM_uint32 _gss_spnego_sign
628           (OM_uint32 * minor_status,
629            gss_ctx_id_t context_handle,
630            int qop_req,
631            gss_buffer_t message_buffer,
632            gss_buffer_t message_token
633           )
634{
635    gssspnego_ctx ctx;
636
637    *minor_status = 0;
638
639    if (context_handle == GSS_C_NO_CONTEXT) {
640	return GSS_S_NO_CONTEXT;
641    }
642
643    ctx = (gssspnego_ctx)context_handle;
644
645    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
646	return GSS_S_NO_CONTEXT;
647    }
648
649    return gss_sign(minor_status,
650		    ctx->negotiated_ctx_id,
651		    qop_req,
652		    message_buffer,
653		    message_token);
654}
655
656OM_uint32 _gss_spnego_verify
657           (OM_uint32 * minor_status,
658            gss_ctx_id_t context_handle,
659            gss_buffer_t message_buffer,
660            gss_buffer_t token_buffer,
661            int * qop_state
662           )
663{
664    gssspnego_ctx ctx;
665
666    *minor_status = 0;
667
668    if (context_handle == GSS_C_NO_CONTEXT) {
669	return GSS_S_NO_CONTEXT;
670    }
671
672    ctx = (gssspnego_ctx)context_handle;
673
674    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
675	return GSS_S_NO_CONTEXT;
676    }
677
678    return gss_verify(minor_status,
679		      ctx->negotiated_ctx_id,
680		      message_buffer,
681		      token_buffer,
682		      qop_state);
683}
684
685OM_uint32 _gss_spnego_seal
686           (OM_uint32 * minor_status,
687            gss_ctx_id_t context_handle,
688            int conf_req_flag,
689            int qop_req,
690            gss_buffer_t input_message_buffer,
691            int * conf_state,
692            gss_buffer_t output_message_buffer
693           )
694{
695    gssspnego_ctx ctx;
696
697    *minor_status = 0;
698
699    if (context_handle == GSS_C_NO_CONTEXT) {
700	return GSS_S_NO_CONTEXT;
701    }
702
703    ctx = (gssspnego_ctx)context_handle;
704
705    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
706	return GSS_S_NO_CONTEXT;
707    }
708
709    return gss_seal(minor_status,
710		    ctx->negotiated_ctx_id,
711		    conf_req_flag,
712		    qop_req,
713		    input_message_buffer,
714		    conf_state,
715		    output_message_buffer);
716}
717
718OM_uint32 _gss_spnego_unseal
719           (OM_uint32 * minor_status,
720            gss_ctx_id_t context_handle,
721            gss_buffer_t input_message_buffer,
722            gss_buffer_t output_message_buffer,
723            int * conf_state,
724            int * qop_state
725           )
726{
727    gssspnego_ctx ctx;
728
729    *minor_status = 0;
730
731    if (context_handle == GSS_C_NO_CONTEXT) {
732	return GSS_S_NO_CONTEXT;
733    }
734
735    ctx = (gssspnego_ctx)context_handle;
736
737    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
738	return GSS_S_NO_CONTEXT;
739    }
740
741    return gss_unseal(minor_status,
742		      ctx->negotiated_ctx_id,
743		      input_message_buffer,
744		      output_message_buffer,
745		      conf_state,
746		      qop_state);
747}
748
749#if 0
750OM_uint32 _gss_spnego_unwrap_ex
751           (OM_uint32 * minor_status,
752            const gss_ctx_id_t context_handle,
753	    const gss_buffer_t token_header_buffer,
754	    const gss_buffer_t associated_data_buffer,
755	    const gss_buffer_t input_message_buffer,
756	    gss_buffer_t output_message_buffer,
757	    int * conf_state,
758	    gss_qop_t * qop_state)
759{
760    gssspnego_ctx ctx;
761
762    *minor_status = 0;
763
764    if (context_handle == GSS_C_NO_CONTEXT) {
765	return GSS_S_NO_CONTEXT;
766    }
767
768    ctx = (gssspnego_ctx)context_handle;
769
770    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
771	return GSS_S_NO_CONTEXT;
772    }
773
774    return gss_unwrap_ex(minor_status,
775			 ctx->negotiated_ctx_id,
776			 token_header_buffer,
777			 associated_data_buffer,
778			 input_message_buffer,
779			 output_message_buffer,
780			 conf_state,
781			 qop_state);
782}
783
784OM_uint32 _gss_spnego_wrap_ex
785           (OM_uint32 * minor_status,
786            const gss_ctx_id_t context_handle,
787            int conf_req_flag,
788            gss_qop_t qop_req,
789            const gss_buffer_t associated_data_buffer,
790            const gss_buffer_t input_message_buffer,
791            int * conf_state,
792            gss_buffer_t output_token_buffer,
793            gss_buffer_t output_message_buffer
794	   )
795{
796    gssspnego_ctx ctx;
797
798    *minor_status = 0;
799
800    if (context_handle == GSS_C_NO_CONTEXT) {
801	return GSS_S_NO_CONTEXT;
802    }
803
804    ctx = (gssspnego_ctx)context_handle;
805
806    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
807	return GSS_S_NO_CONTEXT;
808    }
809
810    if ((ctx->mech_flags & GSS_C_DCE_STYLE) == 0 &&
811	associated_data_buffer->length != input_message_buffer->length) {
812	*minor_status = EINVAL;
813	return GSS_S_BAD_QOP;
814    }
815
816    return gss_wrap_ex(minor_status,
817		       ctx->negotiated_ctx_id,
818		       conf_req_flag,
819		       qop_req,
820		       associated_data_buffer,
821		       input_message_buffer,
822		       conf_state,
823		       output_token_buffer,
824		       output_message_buffer);
825}
826
827OM_uint32 _gss_spnego_complete_auth_token
828           (OM_uint32 * minor_status,
829            const gss_ctx_id_t context_handle,
830	    gss_buffer_t input_message_buffer)
831{
832    gssspnego_ctx ctx;
833
834    *minor_status = 0;
835
836    if (context_handle == GSS_C_NO_CONTEXT) {
837	return GSS_S_NO_CONTEXT;
838    }
839
840    ctx = (gssspnego_ctx)context_handle;
841
842    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
843	return GSS_S_NO_CONTEXT;
844    }
845
846    return gss_complete_auth_token(minor_status,
847				   ctx->negotiated_ctx_id,
848				   input_message_buffer);
849}
850#endif
851
852OM_uint32 _gss_spnego_inquire_sec_context_by_oid
853           (OM_uint32 * minor_status,
854            const gss_ctx_id_t context_handle,
855            const gss_OID desired_object,
856            gss_buffer_set_t *data_set)
857{
858    gssspnego_ctx ctx;
859
860    *minor_status = 0;
861
862    if (context_handle == GSS_C_NO_CONTEXT) {
863	return GSS_S_NO_CONTEXT;
864    }
865
866    ctx = (gssspnego_ctx)context_handle;
867
868    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
869	return GSS_S_NO_CONTEXT;
870    }
871
872    return gss_inquire_sec_context_by_oid(minor_status,
873					  ctx->negotiated_ctx_id,
874					  desired_object,
875					  data_set);
876}
877
878OM_uint32 _gss_spnego_set_sec_context_option
879           (OM_uint32 * minor_status,
880            gss_ctx_id_t * context_handle,
881            const gss_OID desired_object,
882            const gss_buffer_t value)
883{
884    gssspnego_ctx ctx;
885
886    *minor_status = 0;
887
888    if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) {
889	return GSS_S_NO_CONTEXT;
890    }
891
892    ctx = (gssspnego_ctx)context_handle;
893
894    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
895	return GSS_S_NO_CONTEXT;
896    }
897
898    return gss_set_sec_context_option(minor_status,
899				      &ctx->negotiated_ctx_id,
900				      desired_object,
901				      value);
902}
903
904