kdc: Provide extended error information in AS-REP error replies.
[tprouty/samba.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 21123 2007-06-18 20:05:26Z 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
257 OM_uint32
258 gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,
259                                   gss_ctx_id_t *context_handle,
260                                   OM_uint32 version,
261                                   void **rctx)
262 {
263     krb5_context context = NULL;
264     krb5_error_code ret;
265     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
266     OM_uint32 major_status;
267     gss_krb5_lucid_context_v1_t *ctx = NULL;
268     krb5_storage *sp = NULL;
269     uint32_t num;
270
271     if (context_handle == NULL
272         || *context_handle == GSS_C_NO_CONTEXT
273         || version != 1)
274     {
275         ret = EINVAL;
276         return GSS_S_FAILURE;
277     }
278     
279     major_status =
280         gss_inquire_sec_context_by_oid (minor_status,
281                                         *context_handle,
282                                         GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X,
283                                         &data_set);
284     if (major_status)
285         return major_status;
286     
287     if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
288         gss_release_buffer_set(minor_status, &data_set);
289         *minor_status = EINVAL;
290         return GSS_S_FAILURE;
291     }
292
293     ret = krb5_init_context(&context);
294     if (ret)
295         goto out;
296
297     ctx = calloc(1, sizeof(*ctx));
298     if (ctx == NULL) {
299         ret = ENOMEM;
300         goto out;
301     }
302
303     sp = krb5_storage_from_mem(data_set->elements[0].value,
304                                data_set->elements[0].length);
305     if (sp == NULL) {
306         ret = ENOMEM;
307         goto out;
308     }
309     
310     ret = krb5_ret_uint32(sp, &num);
311     if (ret) goto out;
312     if (num != 1) {
313         ret = EINVAL;
314         goto out;
315     }
316     ctx->version = 1;
317     /* initiator */
318     ret = krb5_ret_uint32(sp, &ctx->initiate);
319     if (ret) goto out;
320     /* endtime */
321     ret = krb5_ret_uint32(sp, &ctx->endtime);
322     if (ret) goto out;
323     /* send_seq */
324     ret = krb5_ret_uint32(sp, &num);
325     if (ret) goto out;
326     ctx->send_seq = ((uint64_t)num) << 32;
327     ret = krb5_ret_uint32(sp, &num);
328     if (ret) goto out;
329     ctx->send_seq |= num;
330     /* recv_seq */
331     ret = krb5_ret_uint32(sp, &num);
332     if (ret) goto out;
333     ctx->recv_seq = ((uint64_t)num) << 32;
334     ret = krb5_ret_uint32(sp, &num);
335     if (ret) goto out;
336     ctx->recv_seq |= num;
337     /* protocol */
338     ret = krb5_ret_uint32(sp, &ctx->protocol);
339     if (ret) goto out;
340     if (ctx->protocol == 0) {
341         krb5_keyblock key;
342
343         /* sign_alg */
344         ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg);
345         if (ret) goto out;
346         /* seal_alg */
347         ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg);
348         if (ret) goto out;
349         /* ctx_key */
350         ret = krb5_ret_keyblock(sp, &key);
351         if (ret) goto out;
352         ret = set_key(&key, &ctx->rfc1964_kd.ctx_key);
353         krb5_free_keyblock_contents(context, &key);
354         if (ret) goto out;
355     } else if (ctx->protocol == 1) {
356         krb5_keyblock key;
357
358         /* acceptor_subkey */
359         ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey);
360         if (ret) goto out;
361         /* ctx_key */
362         ret = krb5_ret_keyblock(sp, &key);
363         if (ret) goto out;
364         ret = set_key(&key, &ctx->cfx_kd.ctx_key);
365         krb5_free_keyblock_contents(context, &key);
366         if (ret) goto out;
367         /* acceptor_subkey */
368         if (ctx->cfx_kd.have_acceptor_subkey) {
369             ret = krb5_ret_keyblock(sp, &key);
370             if (ret) goto out;
371             ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey);
372             krb5_free_keyblock_contents(context, &key);
373             if (ret) goto out;
374         }
375     } else {
376         ret = EINVAL;
377         goto out;
378     }
379
380     *rctx = ctx;
381
382 out:
383     gss_release_buffer_set(minor_status, &data_set);
384     if (sp)
385         krb5_storage_free(sp);
386     if (context)
387         krb5_free_context(context);
388
389     if (ret) {
390         if (ctx)
391             gss_krb5_free_lucid_sec_context(NULL, ctx);
392
393         *minor_status = ret;
394         return GSS_S_FAILURE;
395     }
396     *minor_status = 0;
397     return GSS_S_COMPLETE;
398 }
399
400 OM_uint32
401 gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c)
402 {
403     gss_krb5_lucid_context_v1_t *ctx = c;
404
405     if (ctx->version != 1) {
406         if (minor_status)
407             *minor_status = 0;
408         return GSS_S_FAILURE;
409     }
410
411     if (ctx->protocol == 0) {
412         free_key(&ctx->rfc1964_kd.ctx_key);
413     } else if (ctx->protocol == 1) {
414         free_key(&ctx->cfx_kd.ctx_key);
415         if (ctx->cfx_kd.have_acceptor_subkey)
416             free_key(&ctx->cfx_kd.acceptor_subkey);
417     }
418     free(ctx);
419     if (minor_status)
420         *minor_status = 0;
421     return GSS_S_COMPLETE;
422 }
423
424 /*
425  *
426  */
427
428 OM_uint32
429 gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, 
430                                 gss_cred_id_t cred,
431                                 OM_uint32 num_enctypes,
432                                 int32_t *enctypes)
433 {
434     krb5_error_code ret;
435     OM_uint32 maj_status;
436     gss_buffer_desc buffer;
437     krb5_storage *sp;
438     krb5_data data;
439     int i;
440
441     sp = krb5_storage_emem();
442     if (sp == NULL) {
443         *minor_status = ENOMEM;
444         maj_status = GSS_S_FAILURE;
445         goto out;
446     }
447
448     for (i = 0; i < num_enctypes; i++) {
449         ret = krb5_store_int32(sp, enctypes[i]);
450         if (ret) {
451             *minor_status = ret;
452             maj_status = GSS_S_FAILURE;
453             goto out;
454         }
455     }
456
457     ret = krb5_storage_to_data(sp, &data);
458     if (ret) {
459         *minor_status = ret;
460         maj_status = GSS_S_FAILURE;
461         goto out;
462     }
463
464     buffer.value = data.data;
465     buffer.length = data.length;
466
467     maj_status = gss_set_cred_option(minor_status,
468                                      &cred,
469                                      GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X,
470                                      &buffer);
471     krb5_data_free(&data);
472 out:
473     if (sp)
474         krb5_storage_free(sp);
475     return maj_status;
476 }
477
478 /*
479  *
480  */
481
482 OM_uint32
483 gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c)
484 {
485     struct _gss_mech_switch *m;
486     gss_buffer_desc buffer;
487     OM_uint32 junk;
488
489     _gss_load_mech();
490
491     if (c) {
492         buffer.value = c;
493         buffer.length = sizeof(*c);
494     } else {
495         buffer.value = NULL;
496         buffer.length = 0;
497     }
498
499     SLIST_FOREACH(m, &_gss_mechs, gm_link) {
500         if (m->gm_mech.gm_set_sec_context_option == NULL)
501             continue;
502         m->gm_mech.gm_set_sec_context_option(&junk, NULL,
503             GSS_KRB5_SEND_TO_KDC_X, &buffer);
504     }
505
506     return (GSS_S_COMPLETE);
507 }
508
509 /*
510  *
511  */
512
513 OM_uint32
514 gss_krb5_ccache_name(OM_uint32 *minor_status, 
515                      const char *name,
516                      const char **out_name)
517 {
518     struct _gss_mech_switch *m;
519     gss_buffer_desc buffer;
520     OM_uint32 junk;
521
522     _gss_load_mech();
523
524     if (out_name)
525         *out_name = NULL;
526
527     buffer.value = rk_UNCONST(name);
528     buffer.length = strlen(name);
529
530     SLIST_FOREACH(m, &_gss_mechs, gm_link) {
531         if (m->gm_mech.gm_set_sec_context_option == NULL)
532             continue;
533         m->gm_mech.gm_set_sec_context_option(&junk, NULL,
534             GSS_KRB5_CCACHE_NAME_X, &buffer);
535     }
536
537     return (GSS_S_COMPLETE);
538 }
539
540
541 /*
542  *
543  */
544
545 OM_uint32
546 gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
547                                           gss_ctx_id_t context_handle,
548                                           time_t *authtime)
549 {
550     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
551     OM_uint32 maj_stat;
552
553     if (context_handle == GSS_C_NO_CONTEXT) {
554         *minor_status = EINVAL;
555         return GSS_S_FAILURE;
556     }
557     
558     maj_stat =
559         gss_inquire_sec_context_by_oid (minor_status,
560                                         context_handle,
561                                         GSS_KRB5_GET_AUTHTIME_X,
562                                         &data_set);
563     if (maj_stat)
564         return maj_stat;
565     
566     if (data_set == GSS_C_NO_BUFFER_SET) {
567         gss_release_buffer_set(minor_status, &data_set);
568         *minor_status = EINVAL;
569         return GSS_S_FAILURE;
570     }
571
572     if (data_set->count != 1) {
573         gss_release_buffer_set(minor_status, &data_set);
574         *minor_status = EINVAL;
575         return GSS_S_FAILURE;
576     }
577
578     if (data_set->elements[0].length != 4) {
579         gss_release_buffer_set(minor_status, &data_set);
580         *minor_status = EINVAL;
581         return GSS_S_FAILURE;
582     }
583
584     {
585         unsigned char *buf = data_set->elements[0].value;
586         *authtime = (buf[3] <<24) | (buf[2] << 16) | 
587             (buf[1] << 8) | (buf[0] << 0);
588     }
589
590     gss_release_buffer_set(minor_status, &data_set);
591
592     *minor_status = 0;
593     return GSS_S_COMPLETE;
594 }
595
596 /*
597  *
598  */
599
600 OM_uint32
601 gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
602                                             gss_ctx_id_t context_handle,
603                                             int ad_type,
604                                             gss_buffer_t ad_data)
605 {
606     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
607     OM_uint32 maj_stat;
608     gss_OID_desc oid_flat;
609     heim_oid baseoid, oid;
610     size_t size;
611
612     if (context_handle == GSS_C_NO_CONTEXT) {
613         *minor_status = EINVAL;
614         return GSS_S_FAILURE;
615     }
616
617     /* All this to append an integer to an oid... */
618
619     if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,
620                     GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,
621                     &baseoid, NULL) != 0) {
622         *minor_status = EINVAL;
623         return GSS_S_FAILURE;
624     }
625     
626     oid.length = baseoid.length + 1;
627     oid.components = calloc(oid.length, sizeof(*oid.components));
628     if (oid.components == NULL) {
629         der_free_oid(&baseoid);
630
631         *minor_status = ENOMEM;
632         return GSS_S_FAILURE;
633     }
634
635     memcpy(oid.components, baseoid.components, 
636            baseoid.length * sizeof(*baseoid.components));
637     
638     der_free_oid(&baseoid);
639
640     oid.components[oid.length - 1] = ad_type;
641
642     oid_flat.length = der_length_oid(&oid);
643     oid_flat.elements = malloc(oid_flat.length);
644     if (oid_flat.elements == NULL) {
645         free(oid.components);
646         *minor_status = ENOMEM;
647         return GSS_S_FAILURE;
648     }
649
650     if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1, 
651                     oid_flat.length, &oid, &size) != 0) {
652         free(oid.components);
653         free(oid_flat.elements);
654         *minor_status = EINVAL;
655         return GSS_S_FAILURE;
656     }
657     if (oid_flat.length != size)
658         abort();
659
660     free(oid.components);
661
662     /* FINALLY, we have the OID */
663
664     maj_stat = gss_inquire_sec_context_by_oid (minor_status,
665                                                context_handle,
666                                                &oid_flat,
667                                                &data_set);
668
669     free(oid_flat.elements);
670
671     if (maj_stat)
672         return maj_stat;
673     
674     if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
675         gss_release_buffer_set(minor_status, &data_set);
676         *minor_status = EINVAL;
677         return GSS_S_FAILURE;
678     }
679
680     ad_data->value = malloc(data_set->elements[0].length);
681     if (ad_data->value == NULL) {
682         gss_release_buffer_set(minor_status, &data_set);
683         *minor_status = ENOMEM;
684         return GSS_S_FAILURE;
685     }
686
687     ad_data->length = data_set->elements[0].length;
688     memcpy(ad_data->value, data_set->elements[0].value, ad_data->length);
689     gss_release_buffer_set(minor_status, &data_set);
690     
691     *minor_status = 0;
692     return GSS_S_COMPLETE;
693 }
694
695 /*
696  *
697  */
698
699 static OM_uint32
700 gsskrb5_extract_key(OM_uint32 *minor_status,
701                     gss_ctx_id_t context_handle,
702                     const gss_OID oid, 
703                     krb5_keyblock **keyblock)
704 {
705     krb5_error_code ret;
706     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
707     OM_uint32 major_status;
708     krb5_context context = NULL;
709     krb5_storage *sp = NULL;
710
711     if (context_handle == GSS_C_NO_CONTEXT) {
712         ret = EINVAL;
713         return GSS_S_FAILURE;
714     }
715     
716     ret = krb5_init_context(&context);
717     if(ret) {
718         *minor_status = ret;
719         return GSS_S_FAILURE;
720     }
721
722     major_status =
723         gss_inquire_sec_context_by_oid (minor_status,
724                                         context_handle,
725                                         oid,
726                                         &data_set);
727     if (major_status)
728         return major_status;
729     
730     if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
731         gss_release_buffer_set(minor_status, &data_set);
732         *minor_status = EINVAL;
733         return GSS_S_FAILURE;
734     }
735
736     sp = krb5_storage_from_mem(data_set->elements[0].value,
737                                data_set->elements[0].length);
738     if (sp == NULL) {
739         ret = ENOMEM;
740         goto out;
741     }
742     
743     *keyblock = calloc(1, sizeof(**keyblock));
744     if (keyblock == NULL) {
745         ret = ENOMEM;
746         goto out;
747     }
748
749     ret = krb5_ret_keyblock(sp, *keyblock);
750
751 out: 
752     gss_release_buffer_set(minor_status, &data_set);
753     if (sp)
754         krb5_storage_free(sp);
755     if (ret && keyblock) {
756         krb5_free_keyblock(context, *keyblock);
757         *keyblock = NULL;
758     }
759     if (context)
760         krb5_free_context(context);
761
762     *minor_status = ret;
763     if (ret)
764         return GSS_S_FAILURE;
765
766     return GSS_S_COMPLETE;
767 }
768
769 /*
770  *
771  */
772
773 OM_uint32
774 gsskrb5_extract_service_keyblock(OM_uint32 *minor_status,
775                                  gss_ctx_id_t context_handle,
776                                  krb5_keyblock **keyblock)
777 {
778     return gsskrb5_extract_key(minor_status,
779                                context_handle,
780                                GSS_KRB5_GET_SERVICE_KEYBLOCK_X,
781                                keyblock);
782 }
783
784 OM_uint32
785 gsskrb5_get_initiator_subkey(OM_uint32 *minor_status,
786                              gss_ctx_id_t context_handle,
787                              krb5_keyblock **keyblock)
788 {
789     return gsskrb5_extract_key(minor_status,
790                                context_handle,
791                                GSS_KRB5_GET_INITIATOR_SUBKEY_X,
792                                keyblock);
793 }
794
795 OM_uint32
796 gsskrb5_get_subkey(OM_uint32 *minor_status,
797                    gss_ctx_id_t context_handle,
798                    krb5_keyblock **keyblock)
799 {
800     return gsskrb5_extract_key(minor_status,
801                                context_handle,
802                                GSS_KRB5_GET_SUBKEY_X,
803                                keyblock);
804 }
805
806 OM_uint32
807 gsskrb5_set_default_realm(const char *realm)
808 {
809         struct _gss_mech_switch *m;
810         gss_buffer_desc buffer;
811         OM_uint32 junk;
812
813         _gss_load_mech();
814
815         buffer.value = rk_UNCONST(realm);
816         buffer.length = strlen(realm);
817
818         SLIST_FOREACH(m, &_gss_mechs, gm_link) {
819                 if (m->gm_mech.gm_set_sec_context_option == NULL)
820                         continue;
821                 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
822                     GSS_KRB5_SET_DEFAULT_REALM_X, &buffer);
823         }
824
825         return (GSS_S_COMPLETE);
826 }