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_locl.h"
34 
35 static OM_uint32
36 spnego_supported_mechs(OM_uint32 *minor_status, gss_OID_set *mechs)
37 {
38     OM_uint32 ret, junk;
39     gss_OID_set m;
40     size_t i;
41 
42     ret = gss_indicate_mechs(minor_status, &m);
43     if (ret != GSS_S_COMPLETE)
44 	return ret;
45 
46     ret = gss_create_empty_oid_set(minor_status, mechs);
47     if (ret != GSS_S_COMPLETE) {
48 	gss_release_oid_set(&junk, &m);
49 	return ret;
50     }
51 
52     for (i = 0; i < m->count; i++) {
53 	if (gss_oid_equal(&m->elements[i], GSS_SPNEGO_MECHANISM))
54 	    continue;
55 
56 	ret = gss_add_oid_set_member(minor_status, &m->elements[i], mechs);
57 	if (ret) {
58 	    gss_release_oid_set(&junk, &m);
59 	    gss_release_oid_set(&junk, mechs);
60 	    return ret;
61 	}
62     }
63     gss_release_oid_set(&junk, &m);
64     return ret;
65 }
66 
67 
68 
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
73            )
74 {
75     gss_ctx_id_t context ;
76     gssspnego_ctx ctx;
77     OM_uint32 ret;
78 
79     if (context_handle == GSS_C_NO_CONTEXT)
80 	return GSS_S_NO_CONTEXT;
81 
82     context = context_handle;
83     ctx = (gssspnego_ctx)context_handle;
84 
85     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
86 
87     ret = gss_process_context_token(minor_status,
88 				    ctx->negotiated_ctx_id,
89 				    token_buffer);
90     if (ret != GSS_S_COMPLETE) {
91 	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
92 	return ret;
93     }
94 
95     ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
96 
97     return _gss_spnego_internal_delete_sec_context(minor_status,
98 					   &context,
99 					   GSS_C_NO_BUFFER);
100 }
101 
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
106            )
107 {
108     gssspnego_ctx ctx;
109 
110     if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT)
111 	return GSS_S_NO_CONTEXT;
112 
113     ctx = (gssspnego_ctx)*context_handle;
114 
115     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
116 
117     return _gss_spnego_internal_delete_sec_context(minor_status,
118 						   context_handle,
119 						   output_token);
120 }
121 
122 OM_uint32 GSSAPI_CALLCONV _gss_spnego_context_time
123            (OM_uint32 *minor_status,
124             const gss_ctx_id_t context_handle,
125             OM_uint32 *time_rec
126            )
127 {
128     gssspnego_ctx ctx;
129     *minor_status = 0;
130 
131     if (context_handle == GSS_C_NO_CONTEXT) {
132 	return GSS_S_NO_CONTEXT;
133     }
134 
135     ctx = (gssspnego_ctx)context_handle;
136 
137     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
138 	return GSS_S_NO_CONTEXT;
139     }
140 
141     return gss_context_time(minor_status,
142 			    ctx->negotiated_ctx_id,
143 			    time_rec);
144 }
145 
146 OM_uint32 GSSAPI_CALLCONV _gss_spnego_get_mic
147            (OM_uint32 *minor_status,
148             const gss_ctx_id_t context_handle,
149             gss_qop_t qop_req,
150             const gss_buffer_t message_buffer,
151             gss_buffer_t message_token
152            )
153 {
154     gssspnego_ctx ctx;
155 
156     *minor_status = 0;
157 
158     if (context_handle == GSS_C_NO_CONTEXT) {
159 	return GSS_S_NO_CONTEXT;
160     }
161 
162     ctx = (gssspnego_ctx)context_handle;
163 
164     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
165 	return GSS_S_NO_CONTEXT;
166     }
167 
168     return gss_get_mic(minor_status, ctx->negotiated_ctx_id,
169 		       qop_req, message_buffer, message_token);
170 }
171 
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
178            )
179 {
180     gssspnego_ctx ctx;
181 
182     *minor_status = 0;
183 
184     if (context_handle == GSS_C_NO_CONTEXT) {
185 	return GSS_S_NO_CONTEXT;
186     }
187 
188     ctx = (gssspnego_ctx)context_handle;
189 
190     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
191 	return GSS_S_NO_CONTEXT;
192     }
193 
194     return gss_verify_mic(minor_status,
195 			  ctx->negotiated_ctx_id,
196 			  message_buffer,
197 			  token_buffer,
198 			  qop_state);
199 }
200 
201 OM_uint32 GSSAPI_CALLCONV _gss_spnego_wrap
202            (OM_uint32 * minor_status,
203             const gss_ctx_id_t context_handle,
204             int conf_req_flag,
205             gss_qop_t qop_req,
206             const gss_buffer_t input_message_buffer,
207             int * conf_state,
208             gss_buffer_t output_message_buffer
209            )
210 {
211     gssspnego_ctx ctx;
212 
213     *minor_status = 0;
214 
215     if (context_handle == GSS_C_NO_CONTEXT) {
216 	return GSS_S_NO_CONTEXT;
217     }
218 
219     ctx = (gssspnego_ctx)context_handle;
220 
221     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
222 	return GSS_S_NO_CONTEXT;
223     }
224 
225     return gss_wrap(minor_status,
226 		    ctx->negotiated_ctx_id,
227 		    conf_req_flag,
228 		    qop_req,
229 		    input_message_buffer,
230 		    conf_state,
231 		    output_message_buffer);
232 }
233 
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,
239             int * conf_state,
240             gss_qop_t * qop_state
241            )
242 {
243     gssspnego_ctx ctx;
244 
245     *minor_status = 0;
246 
247     if (context_handle == GSS_C_NO_CONTEXT) {
248 	return GSS_S_NO_CONTEXT;
249     }
250 
251     ctx = (gssspnego_ctx)context_handle;
252 
253     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
254 	return GSS_S_NO_CONTEXT;
255     }
256 
257     return gss_unwrap(minor_status,
258 		      ctx->negotiated_ctx_id,
259 		      input_message_buffer,
260 		      output_message_buffer,
261 		      conf_state,
262 		      qop_state);
263 }
264 
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,
269             int * name_equal
270            )
271 {
272     spnego_name n1 = (spnego_name)name1;
273     spnego_name n2 = (spnego_name)name2;
274 
275     *name_equal = 0;
276 
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;
283 
284     *name_equal = 1;
285 
286     return GSS_S_COMPLETE;
287 }
288 
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
294            )
295 {
296     spnego_name name = (spnego_name)input_name;
297 
298     *minor_status = 0;
299 
300     if (name == NULL || name->mech == GSS_C_NO_NAME)
301 	return GSS_S_FAILURE;
302 
303     return gss_display_name(minor_status, name->mech,
304 			    output_name_buffer, output_name_type);
305 }
306 
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
312            )
313 {
314     spnego_name name;
315     OM_uint32 maj_stat;
316 
317     *minor_status = 0;
318 
319     name = calloc(1, sizeof(*name));
320     if (name == NULL) {
321 	*minor_status = ENOMEM;
322 	return GSS_S_FAILURE;
323     }
324 
325     maj_stat = _gss_copy_oid(minor_status, name_type, &name->type);
326     if (maj_stat) {
327 	free(name);
328 	return GSS_S_FAILURE;
329     }
330 
331     maj_stat = _gss_copy_buffer(minor_status, name_buffer, &name->value);
332     if (maj_stat) {
333 	gss_name_t rname = (gss_name_t)name;
334 	_gss_spnego_release_name(minor_status, &rname);
335 	return GSS_S_FAILURE;
336     }
337     name->mech = GSS_C_NO_NAME;
338     *output_name = (gss_name_t)name;
339 
340     return GSS_S_COMPLETE;
341 }
342 
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
347            )
348 {
349     spnego_name name;
350     *minor_status = 0;
351 
352     if (input_name == GSS_C_NO_NAME)
353 	return GSS_S_BAD_NAME;
354 
355     name = (spnego_name)input_name;
356     if (name->mech == GSS_C_NO_NAME)
357 	return GSS_S_BAD_NAME;
358 
359     return gss_export_name(minor_status, name->mech, exported_name);
360 }
361 
362 OM_uint32 GSSAPI_CALLCONV _gss_spnego_release_name
363            (OM_uint32 * minor_status,
364             gss_name_t * input_name
365            )
366 {
367     *minor_status = 0;
368 
369     if (*input_name != GSS_C_NO_NAME) {
370 	OM_uint32 junk;
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);
376 	free(name);
377 
378 	*input_name = GSS_C_NO_NAME;
379     }
380     return GSS_S_COMPLETE;
381 }
382 
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,
389             gss_OID * mech_type,
390             OM_uint32 * ctx_flags,
391             int * locally_initiated,
392             int * open_context
393            )
394 {
395     gssspnego_ctx ctx;
396     OM_uint32 maj_stat, junk;
397     gss_name_t src_mn, targ_mn;
398 
399     *minor_status = 0;
400 
401     if (context_handle == GSS_C_NO_CONTEXT)
402 	return GSS_S_NO_CONTEXT;
403 
404     ctx = (gssspnego_ctx)context_handle;
405 
406     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
407 	return GSS_S_NO_CONTEXT;
408 
409     maj_stat = gss_inquire_context(minor_status,
410 				   ctx->negotiated_ctx_id,
411 				   &src_mn,
412 				   &targ_mn,
413 				   lifetime_rec,
414 				   mech_type,
415 				   ctx_flags,
416 				   locally_initiated,
417 				   open_context);
418     if (maj_stat != GSS_S_COMPLETE)
419 	return maj_stat;
420 
421     if (src_name) {
422 	spnego_name name = calloc(1, sizeof(*name));
423 	if (name == NULL)
424 	    goto enomem;
425 	name->mech = src_mn;
426 	*src_name = (gss_name_t)name;
427     } else
428 	gss_release_name(&junk, &src_mn);
429 
430     if (targ_name) {
431 	spnego_name name = calloc(1, sizeof(*name));
432 	if (name == NULL) {
433 	    gss_release_name(minor_status, src_name);
434 	    goto enomem;
435 	}
436 	name->mech = targ_mn;
437 	*targ_name = (gss_name_t)name;
438     } else
439 	gss_release_name(&junk, &targ_mn);
440 
441     return GSS_S_COMPLETE;
442 
443 enomem:
444     gss_release_name(&junk, &targ_mn);
445     gss_release_name(&junk, &src_mn);
446     *minor_status = ENOMEM;
447     return GSS_S_FAILURE;
448 }
449 
450 OM_uint32 GSSAPI_CALLCONV _gss_spnego_wrap_size_limit (
451             OM_uint32 * minor_status,
452             const gss_ctx_id_t context_handle,
453             int conf_req_flag,
454             gss_qop_t qop_req,
455             OM_uint32 req_output_size,
456             OM_uint32 * max_input_size
457            )
458 {
459     gssspnego_ctx ctx;
460 
461     *minor_status = 0;
462 
463     if (context_handle == GSS_C_NO_CONTEXT) {
464 	return GSS_S_NO_CONTEXT;
465     }
466 
467     ctx = (gssspnego_ctx)context_handle;
468 
469     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
470 	return GSS_S_NO_CONTEXT;
471     }
472 
473     return gss_wrap_size_limit(minor_status,
474 			       ctx->negotiated_ctx_id,
475 			       conf_req_flag,
476 			       qop_req,
477 			       req_output_size,
478 			       max_input_size);
479 }
480 
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
485            )
486 {
487     gssspnego_ctx ctx;
488     OM_uint32 ret;
489 
490     *minor_status = 0;
491 
492     if (context_handle == NULL) {
493 	return GSS_S_NO_CONTEXT;
494     }
495 
496     ctx = (gssspnego_ctx)*context_handle;
497 
498     if (ctx == NULL)
499 	return GSS_S_NO_CONTEXT;
500 
501     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
502 
503     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
504 	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
505 	return GSS_S_NO_CONTEXT;
506     }
507 
508     ret = gss_export_sec_context(minor_status,
509 				 &ctx->negotiated_ctx_id,
510 				 interprocess_token);
511     if (ret == GSS_S_COMPLETE) {
512 	ret = _gss_spnego_internal_delete_sec_context(minor_status,
513 					     context_handle,
514 					     GSS_C_NO_BUFFER);
515 	if (ret == GSS_S_COMPLETE)
516 	    return GSS_S_COMPLETE;
517     }
518 
519     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
520 
521     return ret;
522 }
523 
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
528            )
529 {
530     OM_uint32 ret, minor;
531     gss_ctx_id_t context;
532     gssspnego_ctx ctx;
533 
534     ret = _gss_spnego_alloc_sec_context(minor_status, &context);
535     if (ret != GSS_S_COMPLETE) {
536 	return ret;
537     }
538     ctx = (gssspnego_ctx)context;
539 
540     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
541 
542     ret = gss_import_sec_context(minor_status,
543 				 interprocess_token,
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);
547 	return ret;
548     }
549 
550     ctx->open = 1;
551     /* don't bother filling in the rest of the fields */
552 
553     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
554 
555     *context_handle = (gss_ctx_id_t)ctx;
556 
557     return GSS_S_COMPLETE;
558 }
559 
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
564            )
565 {
566     gss_OID_set mechs, names, n;
567     OM_uint32 ret, junk;
568     size_t i, j;
569 
570     *name_types = NULL;
571 
572     ret = spnego_supported_mechs(minor_status, &mechs);
573     if (ret != GSS_S_COMPLETE)
574 	return ret;
575 
576     ret = gss_create_empty_oid_set(minor_status, &names);
577     if (ret != GSS_S_COMPLETE)
578 	goto out;
579 
580     for (i = 0; i < mechs->count; i++) {
581 	ret = gss_inquire_names_for_mech(minor_status,
582 					 &mechs->elements[i],
583 					 &n);
584 	if (ret)
585 	    continue;
586 
587 	for (j = 0; j < n->count; j++)
588 	    gss_add_oid_set_member(minor_status,
589 				   &n->elements[j],
590 				   &names);
591 	gss_release_oid_set(&junk, &n);
592     }
593 
594     ret = GSS_S_COMPLETE;
595     *name_types = names;
596 out:
597 
598     gss_release_oid_set(&junk, &mechs);
599 
600     return ret;
601 }
602 
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
607            )
608 {
609     OM_uint32 ret, junk;
610 
611     ret = gss_create_empty_oid_set(minor_status, mech_types);
612     if (ret)
613 	return ret;
614 
615     ret = gss_add_oid_set_member(minor_status,
616 				 GSS_SPNEGO_MECHANISM,
617 				 mech_types);
618     if (ret)
619 	gss_release_oid_set(&junk, mech_types);
620 
621     return ret;
622 }
623 
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
629            )
630 {
631     /* XXX */
632     return gss_duplicate_name(minor_status, input_name, output_name);
633 }
634 
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
639            )
640 {
641     return gss_duplicate_name(minor_status, src_name, dest_name);
642 }
643 
644 #if 0
645 OM_uint32 GSSAPI_CALLCONV
646 _gss_spnego_wrap_iov(OM_uint32 * minor_status,
647 		     gss_ctx_id_t  context_handle,
648 		     int conf_req_flag,
649 		     gss_qop_t qop_req,
650 		     int * conf_state,
651 		     gss_iov_buffer_desc *iov,
652 		     int iov_count)
653 {
654     gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
655 
656     *minor_status = 0;
657 
658     if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
659 	return GSS_S_NO_CONTEXT;
660 
661     return gss_wrap_iov(minor_status, ctx->negotiated_ctx_id,
662 			conf_req_flag, qop_req, conf_state,
663 			iov, iov_count);
664 }
665 
666 OM_uint32 GSSAPI_CALLCONV
667 _gss_spnego_unwrap_iov(OM_uint32 *minor_status,
668 		       gss_ctx_id_t context_handle,
669 		       int *conf_state,
670 		       gss_qop_t *qop_state,
671 		       gss_iov_buffer_desc *iov,
672 		       int iov_count)
673 {
674     gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
675 
676     *minor_status = 0;
677 
678     if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
679 	return GSS_S_NO_CONTEXT;
680 
681     return gss_unwrap_iov(minor_status,
682 			  ctx->negotiated_ctx_id,
683 			  conf_state, qop_state,
684 			  iov, iov_count);
685 }
686 
687 OM_uint32 GSSAPI_CALLCONV
688 _gss_spnego_wrap_iov_length(OM_uint32 * minor_status,
689 			    gss_ctx_id_t context_handle,
690 			    int conf_req_flag,
691 			    gss_qop_t qop_req,
692 			    int *conf_state,
693 			    gss_iov_buffer_desc *iov,
694 			    int iov_count)
695 {
696     gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
697 
698     *minor_status = 0;
699 
700     if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
701 	return GSS_S_NO_CONTEXT;
702 
703     return gss_wrap_iov_length(minor_status, ctx->negotiated_ctx_id,
704 			       conf_req_flag, qop_req, conf_state,
705 			       iov, iov_count);
706 }
707 
708 #endif
709 
710 #if 0
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)
715 {
716     gssspnego_ctx ctx;
717 
718     *minor_status = 0;
719 
720     if (context_handle == GSS_C_NO_CONTEXT) {
721 	return GSS_S_NO_CONTEXT;
722     }
723 
724     ctx = (gssspnego_ctx)context_handle;
725 
726     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
727 	return GSS_S_NO_CONTEXT;
728     }
729 
730     return gss_complete_auth_token(minor_status,
731 				   ctx->negotiated_ctx_id,
732 				   input_message_buffer);
733 }
734 #endif
735 
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)
741 {
742     gssspnego_ctx ctx;
743 
744     *minor_status = 0;
745 
746     if (context_handle == GSS_C_NO_CONTEXT) {
747 	return GSS_S_NO_CONTEXT;
748     }
749 
750     ctx = (gssspnego_ctx)context_handle;
751 
752     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
753 	return GSS_S_NO_CONTEXT;
754     }
755 
756     return gss_inquire_sec_context_by_oid(minor_status,
757 					  ctx->negotiated_ctx_id,
758 					  desired_object,
759 					  data_set);
760 }
761 
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)
767 {
768     gssspnego_ctx ctx;
769 
770     *minor_status = 0;
771 
772     if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) {
773 	return GSS_S_NO_CONTEXT;
774     }
775 
776     ctx = (gssspnego_ctx)*context_handle;
777 
778     if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
779 	return GSS_S_NO_CONTEXT;
780     }
781 
782     return gss_set_sec_context_option(minor_status,
783 				      &ctx->negotiated_ctx_id,
784 				      desired_object,
785 				      value);
786 }
787 
788 
789 OM_uint32 GSSAPI_CALLCONV
790 _gss_spnego_pseudo_random(OM_uint32 *minor_status,
791 			  gss_ctx_id_t context_handle,
792 			  int prf_key,
793 			  const gss_buffer_t prf_in,
794 			  ssize_t desired_output_len,
795 			  gss_buffer_t prf_out)
796 {
797     gssspnego_ctx ctx;
798 
799     *minor_status = 0;
800 
801     if (context_handle == GSS_C_NO_CONTEXT)
802 	return GSS_S_NO_CONTEXT;
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     return gss_pseudo_random(minor_status,
810 			     ctx->negotiated_ctx_id,
811 			     prf_key,
812 			     prf_in,
813 			     desired_output_len,
814 			     prf_out);
815 }
816