]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - kerberos5/lib/libgssapi_krb5/gss_krb5.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / kerberos5 / lib / libgssapi_krb5 / gss_krb5.c
1 /*-
2  * Copyright (c) 2005 Doug Rabson
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  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *      $FreeBSD$
27  */
28
29 #include <gssapi/gssapi.h>
30 #include <gssapi/gssapi_krb5.h>
31
32 /* RCSID("$Id: gss_krb5.c 21889 2007-08-09 07:43:24Z lha $"); */
33
34 #include <krb5.h>
35 #include <roken.h>
36 #include <der.h>
37
38 OM_uint32
39 gss_krb5_copy_ccache(OM_uint32 *minor_status,
40                      gss_cred_id_t cred,
41                      krb5_ccache out)
42 {
43     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
44     krb5_context context;
45     krb5_error_code kret;
46     krb5_ccache id;
47     OM_uint32 ret;
48     char *str;
49
50     ret = gss_inquire_cred_by_oid(minor_status,
51                                   cred,
52                                   GSS_KRB5_COPY_CCACHE_X,
53                                   &data_set);
54     if (ret)
55         return ret;
56
57     if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
58         gss_release_buffer_set(minor_status, &data_set);
59         *minor_status = EINVAL;
60         return GSS_S_FAILURE;
61     }
62
63     kret = krb5_init_context(&context);
64     if (kret) {
65         *minor_status = kret;
66         gss_release_buffer_set(minor_status, &data_set);
67         return GSS_S_FAILURE;
68     }
69
70     kret = asprintf(&str, "%.*s", (int)data_set->elements[0].length,
71                     (char *)data_set->elements[0].value);
72     gss_release_buffer_set(minor_status, &data_set);
73     if (kret == -1) {
74         *minor_status = ENOMEM;
75         return GSS_S_FAILURE;
76     }
77
78     kret = krb5_cc_resolve(context, str, &id);
79     free(str);
80     if (kret) {
81         *minor_status = kret;
82         return GSS_S_FAILURE;
83     }
84
85     kret = krb5_cc_copy_cache(context, id, out);
86     krb5_cc_close(context, id);
87     krb5_free_context(context);
88     if (kret) {
89         *minor_status = kret;
90         return GSS_S_FAILURE;
91     }
92
93     return ret;
94 }
95
96 OM_uint32
97 gss_krb5_import_cred(OM_uint32 *minor_status,
98                      krb5_ccache id,
99                      krb5_principal keytab_principal,
100                      krb5_keytab keytab,
101                      gss_cred_id_t *cred)
102 {
103     gss_buffer_desc buffer;
104     OM_uint32 major_status;
105     krb5_context context;
106     krb5_error_code ret;
107     krb5_storage *sp;
108     krb5_data data;
109     char *str;
110
111     *cred = GSS_C_NO_CREDENTIAL;
112
113     ret = krb5_init_context(&context);
114     if (ret) {
115         *minor_status = ret;
116         return GSS_S_FAILURE;
117     }
118
119     sp = krb5_storage_emem();
120     if (sp == NULL) {
121         *minor_status = ENOMEM;
122         major_status = GSS_S_FAILURE;
123         goto out;
124     }
125
126     if (id) {
127         ret = krb5_cc_get_full_name(context, id, &str);
128         if (ret == 0) {
129             ret = krb5_store_string(sp, str);
130             free(str);
131         }
132     } else
133         ret = krb5_store_string(sp, "");
134     if (ret) {
135         *minor_status = ret;
136         major_status = GSS_S_FAILURE;
137         goto out;
138     }
139
140     if (keytab_principal) {
141         ret = krb5_unparse_name(context, keytab_principal, &str);
142         if (ret == 0) {
143             ret = krb5_store_string(sp, str);
144             free(str);
145         }
146     } else
147         krb5_store_string(sp, "");
148     if (ret) {
149         *minor_status = ret;
150         major_status = GSS_S_FAILURE;
151         goto out;
152     }
153
154
155     if (keytab) {
156         ret = krb5_kt_get_full_name(context, keytab, &str);
157         if (ret == 0) {
158             ret = krb5_store_string(sp, str);
159             free(str);
160         }
161     } else
162         krb5_store_string(sp, "");
163     if (ret) {
164         *minor_status = ret;
165         major_status = GSS_S_FAILURE;
166         goto out;
167     }
168
169     ret = krb5_storage_to_data(sp, &data);
170     if (ret) {
171         *minor_status = ret;
172         major_status = GSS_S_FAILURE;
173         goto out;
174     }
175
176     buffer.value = data.data;
177     buffer.length = data.length;
178     
179     major_status = gss_set_cred_option(minor_status,
180                                        cred,
181                                        GSS_KRB5_IMPORT_CRED_X,
182                                        &buffer);
183     krb5_data_free(&data);
184 out:
185     if (sp)
186         krb5_storage_free(sp);
187     krb5_free_context(context);
188     return major_status;
189 }
190
191 OM_uint32
192 gsskrb5_register_acceptor_identity(const char *identity)
193 {
194         gss_buffer_desc buffer;
195         OM_uint32 junk;
196
197         buffer.value = rk_UNCONST(identity);
198         buffer.length = strlen(identity);
199
200         gss_set_sec_context_option(&junk, NULL,
201             GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X, &buffer);
202
203         return (GSS_S_COMPLETE);
204 }
205
206 OM_uint32
207 gsskrb5_set_dns_canonicalize(int flag)
208 {
209         gss_buffer_desc buffer;
210         OM_uint32 junk;
211         char b = (flag != 0);
212
213         buffer.value = &b;
214         buffer.length = sizeof(b);
215
216         gss_set_sec_context_option(&junk, NULL,
217             GSS_KRB5_SET_DNS_CANONICALIZE_X, &buffer);
218
219         return (GSS_S_COMPLETE);
220 }
221
222
223
224 static krb5_error_code
225 set_key(krb5_keyblock *keyblock, gss_krb5_lucid_key_t *key)
226 {
227     key->type = keyblock->keytype;
228     key->length = keyblock->keyvalue.length;
229     key->data = malloc(key->length);
230     if (key->data == NULL && key->length != 0)
231         return ENOMEM;
232     memcpy(key->data, keyblock->keyvalue.data, key->length);
233     return 0;
234 }
235
236 static void
237 free_key(gss_krb5_lucid_key_t *key)
238 {
239     memset(key->data, 0, key->length);
240     free(key->data);
241     memset(key, 0, sizeof(*key));
242 }
243
244 OM_uint32
245 gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,
246                                   gss_ctx_id_t *context_handle,
247                                   OM_uint32 version,
248                                   void **rctx)
249 {
250     krb5_context context = NULL;
251     krb5_error_code ret;
252     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
253     OM_uint32 major_status;
254     gss_krb5_lucid_context_v1_t *ctx = NULL;
255     krb5_storage *sp = NULL;
256     uint32_t num;
257
258     if (context_handle == NULL
259         || *context_handle == GSS_C_NO_CONTEXT
260         || version != 1)
261     {
262         ret = EINVAL;
263         return GSS_S_FAILURE;
264     }
265     
266     major_status =
267         gss_inquire_sec_context_by_oid (minor_status,
268                                         *context_handle,
269                                         GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X,
270                                         &data_set);
271     if (major_status)
272         return major_status;
273     
274     if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
275         gss_release_buffer_set(minor_status, &data_set);
276         *minor_status = EINVAL;
277         return GSS_S_FAILURE;
278     }
279
280     ret = krb5_init_context(&context);
281     if (ret)
282         goto out;
283
284     ctx = calloc(1, sizeof(*ctx));
285     if (ctx == NULL) {
286         ret = ENOMEM;
287         goto out;
288     }
289
290     sp = krb5_storage_from_mem(data_set->elements[0].value,
291                                data_set->elements[0].length);
292     if (sp == NULL) {
293         ret = ENOMEM;
294         goto out;
295     }
296     
297     ret = krb5_ret_uint32(sp, &num);
298     if (ret) goto out;
299     if (num != 1) {
300         ret = EINVAL;
301         goto out;
302     }
303     ctx->version = 1;
304     /* initiator */
305     ret = krb5_ret_uint32(sp, &ctx->initiate);
306     if (ret) goto out;
307     /* endtime */
308     ret = krb5_ret_uint32(sp, &ctx->endtime);
309     if (ret) goto out;
310     /* send_seq */
311     ret = krb5_ret_uint32(sp, &num);
312     if (ret) goto out;
313     ctx->send_seq = ((uint64_t)num) << 32;
314     ret = krb5_ret_uint32(sp, &num);
315     if (ret) goto out;
316     ctx->send_seq |= num;
317     /* recv_seq */
318     ret = krb5_ret_uint32(sp, &num);
319     if (ret) goto out;
320     ctx->recv_seq = ((uint64_t)num) << 32;
321     ret = krb5_ret_uint32(sp, &num);
322     if (ret) goto out;
323     ctx->recv_seq |= num;
324     /* protocol */
325     ret = krb5_ret_uint32(sp, &ctx->protocol);
326     if (ret) goto out;
327     if (ctx->protocol == 0) {
328         krb5_keyblock key;
329
330         /* sign_alg */
331         ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg);
332         if (ret) goto out;
333         /* seal_alg */
334         ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg);
335         if (ret) goto out;
336         /* ctx_key */
337         ret = krb5_ret_keyblock(sp, &key);
338         if (ret) goto out;
339         ret = set_key(&key, &ctx->rfc1964_kd.ctx_key);
340         krb5_free_keyblock_contents(context, &key);
341         if (ret) goto out;
342     } else if (ctx->protocol == 1) {
343         krb5_keyblock key;
344
345         /* acceptor_subkey */
346         ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey);
347         if (ret) goto out;
348         /* ctx_key */
349         ret = krb5_ret_keyblock(sp, &key);
350         if (ret) goto out;
351         ret = set_key(&key, &ctx->cfx_kd.ctx_key);
352         krb5_free_keyblock_contents(context, &key);
353         if (ret) goto out;
354         /* acceptor_subkey */
355         if (ctx->cfx_kd.have_acceptor_subkey) {
356             ret = krb5_ret_keyblock(sp, &key);
357             if (ret) goto out;
358             ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey);
359             krb5_free_keyblock_contents(context, &key);
360             if (ret) goto out;
361         }
362     } else {
363         ret = EINVAL;
364         goto out;
365     }
366
367     *rctx = ctx;
368
369 out:
370     gss_release_buffer_set(minor_status, &data_set);
371     if (sp)
372         krb5_storage_free(sp);
373     if (context)
374         krb5_free_context(context);
375
376     if (ret) {
377         if (ctx)
378             gss_krb5_free_lucid_sec_context(NULL, ctx);
379
380         *minor_status = ret;
381         return GSS_S_FAILURE;
382     }
383     *minor_status = 0;
384     return GSS_S_COMPLETE;
385 }
386
387 OM_uint32
388 gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c)
389 {
390     gss_krb5_lucid_context_v1_t *ctx = c;
391
392     if (ctx->version != 1) {
393         if (minor_status)
394             *minor_status = 0;
395         return GSS_S_FAILURE;
396     }
397
398     if (ctx->protocol == 0) {
399         free_key(&ctx->rfc1964_kd.ctx_key);
400     } else if (ctx->protocol == 1) {
401         free_key(&ctx->cfx_kd.ctx_key);
402         if (ctx->cfx_kd.have_acceptor_subkey)
403             free_key(&ctx->cfx_kd.acceptor_subkey);
404     }
405     free(ctx);
406     if (minor_status)
407         *minor_status = 0;
408     return GSS_S_COMPLETE;
409 }
410
411 /*
412  *
413  */
414
415 OM_uint32
416 gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, 
417                                 gss_cred_id_t cred,
418                                 OM_uint32 num_enctypes,
419                                 int32_t *enctypes)
420 {
421     krb5_error_code ret;
422     OM_uint32 maj_status;
423     gss_buffer_desc buffer;
424     krb5_storage *sp;
425     krb5_data data;
426     int i;
427
428     sp = krb5_storage_emem();
429     if (sp == NULL) {
430         *minor_status = ENOMEM;
431         maj_status = GSS_S_FAILURE;
432         goto out;
433     }
434
435     for (i = 0; i < num_enctypes; i++) {
436         ret = krb5_store_int32(sp, enctypes[i]);
437         if (ret) {
438             *minor_status = ret;
439             maj_status = GSS_S_FAILURE;
440             goto out;
441         }
442     }
443
444     ret = krb5_storage_to_data(sp, &data);
445     if (ret) {
446         *minor_status = ret;
447         maj_status = GSS_S_FAILURE;
448         goto out;
449     }
450
451     buffer.value = data.data;
452     buffer.length = data.length;
453
454     maj_status = gss_set_cred_option(minor_status,
455                                      &cred,
456                                      GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X,
457                                      &buffer);
458     krb5_data_free(&data);
459 out:
460     if (sp)
461         krb5_storage_free(sp);
462     return maj_status;
463 }
464
465 /*
466  *
467  */
468
469 OM_uint32
470 gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c)
471 {
472     gss_buffer_desc buffer;
473     OM_uint32 junk;
474
475     if (c) {
476         buffer.value = c;
477         buffer.length = sizeof(*c);
478     } else {
479         buffer.value = NULL;
480         buffer.length = 0;
481     }
482
483     gss_set_sec_context_option(&junk, NULL,
484             GSS_KRB5_SEND_TO_KDC_X, &buffer);
485
486     return (GSS_S_COMPLETE);
487 }
488
489 /*
490  *
491  */
492
493 OM_uint32
494 gss_krb5_ccache_name(OM_uint32 *minor_status, 
495                      const char *name,
496                      const char **out_name)
497 {
498     gss_buffer_desc buffer;
499     OM_uint32 junk;
500
501     if (out_name)
502         *out_name = NULL;
503
504     buffer.value = rk_UNCONST(name);
505     buffer.length = strlen(name);
506
507     gss_set_sec_context_option(&junk, NULL,
508             GSS_KRB5_CCACHE_NAME_X, &buffer);
509
510     return (GSS_S_COMPLETE);
511 }
512
513
514 /*
515  *
516  */
517
518 OM_uint32
519 gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
520                                           gss_ctx_id_t context_handle,
521                                           time_t *authtime)
522 {
523     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
524     OM_uint32 maj_stat;
525
526     if (context_handle == GSS_C_NO_CONTEXT) {
527         *minor_status = EINVAL;
528         return GSS_S_FAILURE;
529     }
530     
531     maj_stat =
532         gss_inquire_sec_context_by_oid (minor_status,
533                                         context_handle,
534                                         GSS_KRB5_GET_AUTHTIME_X,
535                                         &data_set);
536     if (maj_stat)
537         return maj_stat;
538     
539     if (data_set == GSS_C_NO_BUFFER_SET) {
540         gss_release_buffer_set(minor_status, &data_set);
541         *minor_status = EINVAL;
542         return GSS_S_FAILURE;
543     }
544
545     if (data_set->count != 1) {
546         gss_release_buffer_set(minor_status, &data_set);
547         *minor_status = EINVAL;
548         return GSS_S_FAILURE;
549     }
550
551     if (data_set->elements[0].length != 4) {
552         gss_release_buffer_set(minor_status, &data_set);
553         *minor_status = EINVAL;
554         return GSS_S_FAILURE;
555     }
556
557     {
558         unsigned char *buf = data_set->elements[0].value;
559         *authtime = (buf[3] <<24) | (buf[2] << 16) | 
560             (buf[1] << 8) | (buf[0] << 0);
561     }
562
563     gss_release_buffer_set(minor_status, &data_set);
564
565     *minor_status = 0;
566     return GSS_S_COMPLETE;
567 }
568
569 /*
570  *
571  */
572
573 OM_uint32
574 gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
575                                             gss_ctx_id_t context_handle,
576                                             int ad_type,
577                                             gss_buffer_t ad_data)
578 {
579     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
580     OM_uint32 maj_stat;
581     gss_OID_desc oid_flat;
582     heim_oid baseoid, oid;
583     size_t size;
584
585     if (context_handle == GSS_C_NO_CONTEXT) {
586         *minor_status = EINVAL;
587         return GSS_S_FAILURE;
588     }
589
590     /* All this to append an integer to an oid... */
591
592     if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,
593                     GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,
594                     &baseoid, NULL) != 0) {
595         *minor_status = EINVAL;
596         return GSS_S_FAILURE;
597     }
598     
599     oid.length = baseoid.length + 1;
600     oid.components = calloc(oid.length, sizeof(*oid.components));
601     if (oid.components == NULL) {
602         der_free_oid(&baseoid);
603
604         *minor_status = ENOMEM;
605         return GSS_S_FAILURE;
606     }
607
608     memcpy(oid.components, baseoid.components, 
609            baseoid.length * sizeof(*baseoid.components));
610     
611     der_free_oid(&baseoid);
612
613     oid.components[oid.length - 1] = ad_type;
614
615     oid_flat.length = der_length_oid(&oid);
616     oid_flat.elements = malloc(oid_flat.length);
617     if (oid_flat.elements == NULL) {
618         free(oid.components);
619         *minor_status = ENOMEM;
620         return GSS_S_FAILURE;
621     }
622
623     if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1, 
624                     oid_flat.length, &oid, &size) != 0) {
625         free(oid.components);
626         free(oid_flat.elements);
627         *minor_status = EINVAL;
628         return GSS_S_FAILURE;
629     }
630     if (oid_flat.length != size)
631         abort();
632
633     free(oid.components);
634
635     /* FINALLY, we have the OID */
636
637     maj_stat = gss_inquire_sec_context_by_oid (minor_status,
638                                                context_handle,
639                                                &oid_flat,
640                                                &data_set);
641
642     free(oid_flat.elements);
643
644     if (maj_stat)
645         return maj_stat;
646     
647     if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
648         gss_release_buffer_set(minor_status, &data_set);
649         *minor_status = EINVAL;
650         return GSS_S_FAILURE;
651     }
652
653     ad_data->value = malloc(data_set->elements[0].length);
654     if (ad_data->value == NULL) {
655         gss_release_buffer_set(minor_status, &data_set);
656         *minor_status = ENOMEM;
657         return GSS_S_FAILURE;
658     }
659
660     ad_data->length = data_set->elements[0].length;
661     memcpy(ad_data->value, data_set->elements[0].value, ad_data->length);
662     gss_release_buffer_set(minor_status, &data_set);
663     
664     *minor_status = 0;
665     return GSS_S_COMPLETE;
666 }
667
668 /*
669  *
670  */
671
672 static OM_uint32
673 gsskrb5_extract_key(OM_uint32 *minor_status,
674                     gss_ctx_id_t context_handle,
675                     const gss_OID oid, 
676                     krb5_keyblock **keyblock)
677 {
678     krb5_error_code ret;
679     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
680     OM_uint32 major_status;
681     krb5_context context = NULL;
682     krb5_storage *sp = NULL;
683
684     if (context_handle == GSS_C_NO_CONTEXT) {
685         ret = EINVAL;
686         return GSS_S_FAILURE;
687     }
688     
689     ret = krb5_init_context(&context);
690     if(ret) {
691         *minor_status = ret;
692         return GSS_S_FAILURE;
693     }
694
695     major_status =
696         gss_inquire_sec_context_by_oid (minor_status,
697                                         context_handle,
698                                         oid,
699                                         &data_set);
700     if (major_status)
701         return major_status;
702     
703     if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
704         gss_release_buffer_set(minor_status, &data_set);
705         *minor_status = EINVAL;
706         return GSS_S_FAILURE;
707     }
708
709     sp = krb5_storage_from_mem(data_set->elements[0].value,
710                                data_set->elements[0].length);
711     if (sp == NULL) {
712         ret = ENOMEM;
713         goto out;
714     }
715     
716     *keyblock = calloc(1, sizeof(**keyblock));
717     if (keyblock == NULL) {
718         ret = ENOMEM;
719         goto out;
720     }
721
722     ret = krb5_ret_keyblock(sp, *keyblock);
723
724 out: 
725     gss_release_buffer_set(minor_status, &data_set);
726     if (sp)
727         krb5_storage_free(sp);
728     if (ret && keyblock) {
729         krb5_free_keyblock(context, *keyblock);
730         *keyblock = NULL;
731     }
732     if (context)
733         krb5_free_context(context);
734
735     *minor_status = ret;
736     if (ret)
737         return GSS_S_FAILURE;
738
739     return GSS_S_COMPLETE;
740 }
741
742 /*
743  *
744  */
745
746 OM_uint32
747 gsskrb5_extract_service_keyblock(OM_uint32 *minor_status,
748                                  gss_ctx_id_t context_handle,
749                                  krb5_keyblock **keyblock)
750 {
751     return gsskrb5_extract_key(minor_status,
752                                context_handle,
753                                GSS_KRB5_GET_SERVICE_KEYBLOCK_X,
754                                keyblock);
755 }
756
757 OM_uint32
758 gsskrb5_get_initiator_subkey(OM_uint32 *minor_status,
759                              gss_ctx_id_t context_handle,
760                              krb5_keyblock **keyblock)
761 {
762     return gsskrb5_extract_key(minor_status,
763                                context_handle,
764                                GSS_KRB5_GET_INITIATOR_SUBKEY_X,
765                                keyblock);
766 }
767
768 OM_uint32
769 gsskrb5_get_subkey(OM_uint32 *minor_status,
770                    gss_ctx_id_t context_handle,
771                    krb5_keyblock **keyblock)
772 {
773     return gsskrb5_extract_key(minor_status,
774                                context_handle,
775                                GSS_KRB5_GET_SUBKEY_X,
776                                keyblock);
777 }
778
779 OM_uint32
780 gsskrb5_set_default_realm(const char *realm)
781 {
782         gss_buffer_desc buffer;
783         OM_uint32 junk;
784
785         buffer.value = rk_UNCONST(realm);
786         buffer.length = strlen(realm);
787
788         gss_set_sec_context_option(&junk, NULL,
789             GSS_KRB5_SET_DEFAULT_REALM_X, &buffer);
790
791         return (GSS_S_COMPLETE);
792 }
793
794 OM_uint32
795 gss_krb5_get_tkt_flags(OM_uint32 *minor_status,
796                        gss_ctx_id_t context_handle,
797                        OM_uint32 *tkt_flags)
798 {
799
800     OM_uint32 major_status;
801     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
802
803     if (context_handle == GSS_C_NO_CONTEXT) {
804         *minor_status = EINVAL;
805         return GSS_S_FAILURE;
806     }
807     
808     major_status =
809         gss_inquire_sec_context_by_oid (minor_status,
810                                         context_handle,
811                                         GSS_KRB5_GET_TKT_FLAGS_X,
812                                         &data_set);
813     if (major_status)
814         return major_status;
815     
816     if (data_set == GSS_C_NO_BUFFER_SET || 
817         data_set->count != 1 ||
818         data_set->elements[0].length < 4) {
819         gss_release_buffer_set(minor_status, &data_set);
820         *minor_status = EINVAL;
821         return GSS_S_FAILURE;
822     }
823
824     {
825         const u_char *p = data_set->elements[0].value;
826         *tkt_flags = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
827     }
828
829     gss_release_buffer_set(minor_status, &data_set);
830     return GSS_S_COMPLETE;
831 }
832