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