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