s4:heimdal: import lorikeet-heimdal-201009250123 (commit 42cabfb5b683dbcb97d583c397b8...
[samba.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 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     int 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     int 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 OM_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
665 OM_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
686 OM_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
708 OM_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
733 OM_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
759 OM_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
786 OM_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 }