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
35static OM_uint32
36spnego_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
69OM_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
102OM_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
122OM_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
146OM_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
172OM_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
201OM_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
234OM_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
265OM_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
289OM_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
307OM_uint32 GSSAPI_CALLCONV _gss_spnego_import_name
308           (OM_uint32 * minor_status,
309            const gss_buffer_t name_buffer,
310            gss_const_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
343OM_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
362OM_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
383OM_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
443enomem:
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
450OM_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
481OM_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
524OM_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->flags.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
560OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_names_for_mech (
561            OM_uint32 * minor_status,
562            gss_const_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;
596out:
597
598    gss_release_oid_set(&junk, &mechs);
599
600    return ret;
601}
602
603OM_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
624OM_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
635OM_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
644OM_uint32 GSSAPI_CALLCONV
645_gss_spnego_wrap_iov(OM_uint32 * minor_status,
646		     gss_ctx_id_t  context_handle,
647		     int conf_req_flag,
648		     gss_qop_t qop_req,
649		     int * conf_state,
650		     gss_iov_buffer_desc *iov,
651		     int iov_count)
652{
653    gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
654
655    *minor_status = 0;
656
657    if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
658	return GSS_S_NO_CONTEXT;
659
660    return gss_wrap_iov(minor_status, ctx->negotiated_ctx_id,
661			conf_req_flag, qop_req, conf_state,
662			iov, iov_count);
663}
664
665OM_uint32 GSSAPI_CALLCONV
666_gss_spnego_unwrap_iov(OM_uint32 *minor_status,
667		       gss_ctx_id_t context_handle,
668		       int *conf_state,
669		       gss_qop_t *qop_state,
670		       gss_iov_buffer_desc *iov,
671		       int iov_count)
672{
673    gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
674
675    *minor_status = 0;
676
677    if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
678	return GSS_S_NO_CONTEXT;
679
680    return gss_unwrap_iov(minor_status,
681			  ctx->negotiated_ctx_id,
682			  conf_state, qop_state,
683			  iov, iov_count);
684}
685
686OM_uint32 GSSAPI_CALLCONV
687_gss_spnego_wrap_iov_length(OM_uint32 * minor_status,
688			    gss_ctx_id_t context_handle,
689			    int conf_req_flag,
690			    gss_qop_t qop_req,
691			    int *conf_state,
692			    gss_iov_buffer_desc *iov,
693			    int iov_count)
694{
695    gssspnego_ctx ctx = (gssspnego_ctx)context_handle;
696
697    *minor_status = 0;
698
699    if (ctx == NULL || ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
700	return GSS_S_NO_CONTEXT;
701
702    return gss_wrap_iov_length(minor_status, ctx->negotiated_ctx_id,
703			       conf_req_flag, qop_req, conf_state,
704			       iov, iov_count);
705}
706
707#if 0
708OM_uint32 GSSAPI_CALLCONV _gss_spnego_complete_auth_token
709           (OM_uint32 * minor_status,
710            const gss_ctx_id_t context_handle,
711	    gss_buffer_t input_message_buffer)
712{
713    gssspnego_ctx ctx;
714
715    *minor_status = 0;
716
717    if (context_handle == GSS_C_NO_CONTEXT) {
718	return GSS_S_NO_CONTEXT;
719    }
720
721    ctx = (gssspnego_ctx)context_handle;
722
723    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
724	return GSS_S_NO_CONTEXT;
725    }
726
727    return gss_complete_auth_token(minor_status,
728				   ctx->negotiated_ctx_id,
729				   input_message_buffer);
730}
731#endif
732
733OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_sec_context_by_oid
734           (OM_uint32 * minor_status,
735            const gss_ctx_id_t context_handle,
736            const gss_OID desired_object,
737            gss_buffer_set_t *data_set)
738{
739    gssspnego_ctx ctx;
740
741    *minor_status = 0;
742
743    if (context_handle == GSS_C_NO_CONTEXT) {
744	return GSS_S_NO_CONTEXT;
745    }
746
747    ctx = (gssspnego_ctx)context_handle;
748
749    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
750	return GSS_S_NO_CONTEXT;
751    }
752
753    return gss_inquire_sec_context_by_oid(minor_status,
754					  ctx->negotiated_ctx_id,
755					  desired_object,
756					  data_set);
757}
758
759OM_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)
764{
765    gssspnego_ctx ctx;
766
767    *minor_status = 0;
768
769    if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) {
770	return GSS_S_NO_CONTEXT;
771    }
772
773    ctx = (gssspnego_ctx)*context_handle;
774
775    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT) {
776	return GSS_S_NO_CONTEXT;
777    }
778
779    return gss_set_sec_context_option(minor_status,
780				      &ctx->negotiated_ctx_id,
781				      desired_object,
782				      value);
783}
784
785
786OM_uint32 GSSAPI_CALLCONV
787_gss_spnego_pseudo_random(OM_uint32 *minor_status,
788			  gss_ctx_id_t context_handle,
789			  int prf_key,
790			  const gss_buffer_t prf_in,
791			  ssize_t desired_output_len,
792			  gss_buffer_t prf_out)
793{
794    gssspnego_ctx ctx;
795
796    *minor_status = 0;
797
798    if (context_handle == GSS_C_NO_CONTEXT)
799	return GSS_S_NO_CONTEXT;
800
801    ctx = (gssspnego_ctx)context_handle;
802
803    if (ctx->negotiated_ctx_id == GSS_C_NO_CONTEXT)
804	return GSS_S_NO_CONTEXT;
805
806    return gss_pseudo_random(minor_status,
807			     ctx->negotiated_ctx_id,
808			     prf_key,
809			     prf_in,
810			     desired_output_len,
811			     prf_out);
812}
813