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