76a2c2b637b91ba222304b4c043f1b515118277c
[tprouty/samba.git] / source / 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,v 1.21 2006/11/10 00:57:27 lha Exp $");
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     krb5_storage_to_data(sp, &data);
168
169     buffer.value = data.data;
170     buffer.length = data.length;
171     
172     major_status = gss_set_cred_option(minor_status,
173                                        cred,
174                                        GSS_KRB5_IMPORT_CRED_X,
175                                        &buffer);
176     krb5_data_free(&data);
177 out:
178     if (sp)
179         krb5_storage_free(sp);
180     krb5_free_context(context);
181     return major_status;
182 }
183
184 OM_uint32
185 gsskrb5_register_acceptor_identity(const char *identity)
186 {
187         struct _gss_mech_switch *m;
188         gss_buffer_desc buffer;
189         OM_uint32 junk;
190
191         _gss_load_mech();
192
193         buffer.value = rk_UNCONST(identity);
194         buffer.length = strlen(identity);
195
196         SLIST_FOREACH(m, &_gss_mechs, gm_link) {
197                 if (m->gm_mech.gm_set_sec_context_option == NULL)
198                         continue;
199                 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
200                     GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X, &buffer);
201         }
202
203         return (GSS_S_COMPLETE);
204 }
205
206 OM_uint32
207 gsskrb5_set_dns_canonicalize(int flag)
208 {
209         struct _gss_mech_switch *m;
210         gss_buffer_desc buffer;
211         OM_uint32 junk;
212         char b = (flag != 0);
213
214         _gss_load_mech();
215
216         buffer.value = &b;
217         buffer.length = sizeof(b);
218
219         SLIST_FOREACH(m, &_gss_mechs, gm_link) {
220                 if (m->gm_mech.gm_set_sec_context_option == NULL)
221                         continue;
222                 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
223                     GSS_KRB5_SET_DNS_CANONICALIZE_X, &buffer);
224         }
225
226         return (GSS_S_COMPLETE);
227 }
228
229
230
231 static krb5_error_code
232 set_key(krb5_keyblock *keyblock, gss_krb5_lucid_key_t *key)
233 {
234     key->type = keyblock->keytype;
235     key->length = keyblock->keyvalue.length;
236     key->data = malloc(key->length);
237     if (key->data == NULL && key->length != 0)
238         return ENOMEM;
239     memcpy(key->data, keyblock->keyvalue.data, key->length);
240     return 0;
241 }
242
243 static void
244 free_key(gss_krb5_lucid_key_t *key)
245 {
246     memset(key->data, 0, key->length);
247     free(key->data);
248     memset(key, 0, sizeof(*key));
249 }
250
251
252 OM_uint32
253 gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,
254                                   gss_ctx_id_t *context_handle,
255                                   OM_uint32 version,
256                                   void **rctx)
257 {
258     krb5_context context = NULL;
259     krb5_error_code ret;
260     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
261     OM_uint32 major_status;
262     gss_krb5_lucid_context_v1_t *ctx = NULL;
263     krb5_storage *sp = NULL;
264     uint32_t num;
265
266     if (context_handle == NULL
267         || *context_handle == GSS_C_NO_CONTEXT
268         || version != 1)
269     {
270         ret = EINVAL;
271         return GSS_S_FAILURE;
272     }
273     
274     major_status =
275         gss_inquire_sec_context_by_oid (minor_status,
276                                         *context_handle,
277                                         GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X,
278                                         &data_set);
279     if (major_status)
280         return major_status;
281     
282     if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
283         gss_release_buffer_set(minor_status, &data_set);
284         *minor_status = EINVAL;
285         return GSS_S_FAILURE;
286     }
287
288     ret = krb5_init_context(&context);
289     if (ret)
290         goto out;
291
292     ctx = calloc(1, sizeof(*ctx));
293     if (ctx == NULL) {
294         ret = ENOMEM;
295         goto out;
296     }
297
298     sp = krb5_storage_from_mem(data_set->elements[0].value,
299                                data_set->elements[0].length);
300     if (sp == NULL) {
301         ret = ENOMEM;
302         goto out;
303     }
304     
305     ret = krb5_ret_uint32(sp, &num);
306     if (ret) goto out;
307     if (num != 1) {
308         ret = EINVAL;
309         goto out;
310     }
311     ctx->version = 1;
312     /* initiator */
313     ret = krb5_ret_uint32(sp, &ctx->initiate);
314     if (ret) goto out;
315     /* endtime */
316     ret = krb5_ret_uint32(sp, &ctx->endtime);
317     if (ret) goto out;
318     /* send_seq */
319     ret = krb5_ret_uint32(sp, &num);
320     if (ret) goto out;
321     ctx->send_seq = ((uint64_t)num) << 32;
322     ret = krb5_ret_uint32(sp, &num);
323     if (ret) goto out;
324     ctx->send_seq |= num;
325     /* recv_seq */
326     ret = krb5_ret_uint32(sp, &num);
327     if (ret) goto out;
328     ctx->recv_seq = ((uint64_t)num) << 32;
329     ret = krb5_ret_uint32(sp, &num);
330     if (ret) goto out;
331     ctx->recv_seq |= num;
332     /* protocol */
333     ret = krb5_ret_uint32(sp, &ctx->protocol);
334     if (ret) goto out;
335     if (ctx->protocol == 0) {
336         krb5_keyblock key;
337
338         /* sign_alg */
339         ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg);
340         if (ret) goto out;
341         /* seal_alg */
342         ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg);
343         if (ret) goto out;
344         /* ctx_key */
345         ret = krb5_ret_keyblock(sp, &key);
346         if (ret) goto out;
347         ret = set_key(&key, &ctx->rfc1964_kd.ctx_key);
348         krb5_free_keyblock_contents(context, &key);
349         if (ret) goto out;
350     } else if (ctx->protocol == 1) {
351         krb5_keyblock key;
352
353         /* acceptor_subkey */
354         ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey);
355         if (ret) goto out;
356         /* ctx_key */
357         ret = krb5_ret_keyblock(sp, &key);
358         if (ret) goto out;
359         ret = set_key(&key, &ctx->cfx_kd.ctx_key);
360         krb5_free_keyblock_contents(context, &key);
361         if (ret) goto out;
362         /* acceptor_subkey */
363         if (ctx->cfx_kd.have_acceptor_subkey) {
364             ret = krb5_ret_keyblock(sp, &key);
365             if (ret) goto out;
366             ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey);
367             krb5_free_keyblock_contents(context, &key);
368             if (ret) goto out;
369         }
370     } else {
371         ret = EINVAL;
372         goto out;
373     }
374
375     *rctx = ctx;
376
377 out:
378     gss_release_buffer_set(minor_status, &data_set);
379     if (sp)
380         krb5_storage_free(sp);
381     if (context)
382         krb5_free_context(context);
383
384     if (ret) {
385         if (ctx)
386             gss_krb5_free_lucid_sec_context(NULL, ctx);
387
388         *minor_status = ret;
389         return GSS_S_FAILURE;
390     }
391     *minor_status = 0;
392     return GSS_S_COMPLETE;
393 }
394
395 OM_uint32
396 gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c)
397 {
398     gss_krb5_lucid_context_v1_t *ctx = c;
399
400     if (ctx->version != 1) {
401         if (minor_status)
402             *minor_status = 0;
403         return GSS_S_FAILURE;
404     }
405
406     if (ctx->protocol == 0) {
407         free_key(&ctx->rfc1964_kd.ctx_key);
408     } else if (ctx->protocol == 1) {
409         free_key(&ctx->cfx_kd.ctx_key);
410         if (ctx->cfx_kd.have_acceptor_subkey)
411             free_key(&ctx->cfx_kd.acceptor_subkey);
412     }
413     free(ctx);
414     if (minor_status)
415         *minor_status = 0;
416     return GSS_S_COMPLETE;
417 }
418
419 /*
420  *
421  */
422
423 OM_uint32
424 gss_krb5_set_allowable_enctypes(OM_uint32 *min_status, 
425                                 gss_cred_id_t cred,
426                                 OM_uint32 num_enctypes,
427                                 int32_t *enctypes)
428 {
429     OM_uint32 maj_status;
430     gss_buffer_desc buffer;
431     krb5_storage *sp;
432     krb5_data data;
433
434     sp = krb5_storage_emem();
435     if (sp == NULL) {
436         *min_status = ENOMEM;
437         maj_status = GSS_S_FAILURE;
438         goto out;
439     }
440
441     while(*enctypes) {
442         krb5_store_int32(sp, *enctypes);
443         enctypes++;
444     }
445
446     krb5_storage_to_data(sp, &data);
447
448     buffer.value = data.data;
449     buffer.length = data.length;
450
451     maj_status = gss_set_cred_option(min_status,
452                                      &cred,
453                                      GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X,
454                                      &buffer);
455 out:
456     if (sp)
457         krb5_storage_free(sp);
458     return maj_status;
459 }
460
461 /*
462  *
463  */
464
465 OM_uint32
466 gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c)
467 {
468     struct _gss_mech_switch *m;
469     gss_buffer_desc buffer;
470     OM_uint32 junk;
471
472     _gss_load_mech();
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     SLIST_FOREACH(m, &_gss_mechs, gm_link) {
483         if (m->gm_mech.gm_set_sec_context_option == NULL)
484             continue;
485         m->gm_mech.gm_set_sec_context_option(&junk, NULL,
486             GSS_KRB5_SEND_TO_KDC_X, &buffer);
487     }
488
489     return (GSS_S_COMPLETE);
490 }
491
492 /*
493  *
494  */
495
496 OM_uint32
497 gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
498                                           gss_ctx_id_t context_handle,
499                                           time_t *authtime)
500 {
501     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
502     OM_uint32 maj_stat;
503
504     if (context_handle == GSS_C_NO_CONTEXT) {
505         *minor_status = EINVAL;
506         return GSS_S_FAILURE;
507     }
508     
509     maj_stat =
510         gss_inquire_sec_context_by_oid (minor_status,
511                                         context_handle,
512                                         GSS_KRB5_GET_AUTHTIME_X,
513                                         &data_set);
514     if (maj_stat)
515         return maj_stat;
516     
517     if (data_set == GSS_C_NO_BUFFER_SET) {
518         gss_release_buffer_set(minor_status, &data_set);
519         *minor_status = EINVAL;
520         return GSS_S_FAILURE;
521     }
522
523     if (data_set->count != 1) {
524         gss_release_buffer_set(minor_status, &data_set);
525         *minor_status = EINVAL;
526         return GSS_S_FAILURE;
527     }
528
529     if (data_set->elements[0].length != 4) {
530         gss_release_buffer_set(minor_status, &data_set);
531         *minor_status = EINVAL;
532         return GSS_S_FAILURE;
533     }
534
535     {
536         unsigned char *buf = data_set->elements[0].value;
537         *authtime = (buf[3] <<24) | (buf[2] << 16) | 
538             (buf[1] << 8) | (buf[0] << 0);
539     }
540
541     gss_release_buffer_set(minor_status, &data_set);
542
543     *minor_status = 0;
544     return GSS_S_COMPLETE;
545 }
546
547 /*
548  *
549  */
550
551 OM_uint32
552 gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
553                                             gss_ctx_id_t context_handle,
554                                             int ad_type,
555                                             gss_buffer_t ad_data)
556 {
557     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
558     OM_uint32 maj_stat;
559     gss_OID_desc oid_flat;
560     heim_oid baseoid, oid;
561     size_t size;
562
563     if (context_handle == GSS_C_NO_CONTEXT) {
564         *minor_status = EINVAL;
565         return GSS_S_FAILURE;
566     }
567
568     /* All this to append an integer to an oid... */
569
570     if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,
571                     GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,
572                     &baseoid, NULL) != 0) {
573         *minor_status = EINVAL;
574         return GSS_S_FAILURE;
575     }
576     
577     oid.length = baseoid.length + 1;
578     oid.components = calloc(oid.length, sizeof(*oid.components));
579     if (oid.components == NULL) {
580         der_free_oid(&baseoid);
581
582         *minor_status = ENOMEM;
583         return GSS_S_FAILURE;
584     }
585
586     memcpy(oid.components, baseoid.components, 
587            baseoid.length * sizeof(*baseoid.components));
588     
589     der_free_oid(&baseoid);
590
591     oid.components[oid.length - 1] = ad_type;
592
593     oid_flat.length = der_length_oid(&oid);
594     oid_flat.elements = malloc(oid_flat.length);
595     if (oid_flat.elements == NULL) {
596         free(oid.components);
597         *minor_status = ENOMEM;
598         return GSS_S_FAILURE;
599     }
600
601     if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1, 
602                     oid_flat.length, &oid, &size) != 0) {
603         free(oid.components);
604
605         *minor_status = EINVAL;
606         return GSS_S_FAILURE;
607     }
608     if (oid_flat.length != size)
609         abort();
610
611     free(oid.components);
612
613     /* FINALLY, we have the OID */
614
615     maj_stat = gss_inquire_sec_context_by_oid (minor_status,
616                                                context_handle,
617                                                &oid_flat,
618                                                &data_set);
619
620     free(oid_flat.elements);
621
622     if (maj_stat)
623         return maj_stat;
624     
625     if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
626         gss_release_buffer_set(minor_status, &data_set);
627         *minor_status = EINVAL;
628         return GSS_S_FAILURE;
629     }
630
631     ad_data->value = malloc(data_set->elements[0].length);
632     if (ad_data->value == NULL) {
633         gss_release_buffer_set(minor_status, &data_set);
634         *minor_status = ENOMEM;
635         return GSS_S_FAILURE;
636     }
637
638     ad_data->length = data_set->elements[0].length;
639     memcpy(ad_data->value, data_set->elements[0].value, ad_data->length);
640     gss_release_buffer_set(minor_status, &data_set);
641     
642     *minor_status = 0;
643     return GSS_S_COMPLETE;
644 }
645
646 /*
647  *
648  */
649
650 static OM_uint32
651 gsskrb5_extract_key(OM_uint32 *minor_status,
652                     gss_ctx_id_t context_handle,
653                     const gss_OID oid, 
654                     krb5_keyblock **keyblock)
655 {
656     krb5_error_code ret;
657     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
658     OM_uint32 major_status;
659     krb5_context context = NULL;
660     krb5_storage *sp = NULL;
661
662     if (context_handle == GSS_C_NO_CONTEXT) {
663         ret = EINVAL;
664         return GSS_S_FAILURE;
665     }
666     
667     ret = krb5_init_context(&context);
668     if(ret) {
669         *minor_status = ret;
670         return GSS_S_FAILURE;
671     }
672
673     major_status =
674         gss_inquire_sec_context_by_oid (minor_status,
675                                         context_handle,
676                                         oid,
677                                         &data_set);
678     if (major_status)
679         return major_status;
680     
681     if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
682         gss_release_buffer_set(minor_status, &data_set);
683         *minor_status = EINVAL;
684         return GSS_S_FAILURE;
685     }
686
687     sp = krb5_storage_from_mem(data_set->elements[0].value,
688                                data_set->elements[0].length);
689     if (sp == NULL) {
690         ret = ENOMEM;
691         goto out;
692     }
693     
694     *keyblock = calloc(1, sizeof(**keyblock));
695     if (keyblock == NULL) {
696         ret = ENOMEM;
697         goto out;
698     }
699
700     ret = krb5_ret_keyblock(sp, *keyblock);
701
702 out: 
703     gss_release_buffer_set(minor_status, &data_set);
704     if (sp)
705         krb5_storage_free(sp);
706     if (ret && keyblock) {
707         krb5_free_keyblock(context, *keyblock);
708         *keyblock = NULL;
709     }
710     if (context)
711         krb5_free_context(context);
712
713     *minor_status = ret;
714     if (ret)
715         return GSS_S_FAILURE;
716
717     return GSS_S_COMPLETE;
718 }
719
720 /*
721  *
722  */
723
724 OM_uint32
725 gsskrb5_extract_service_keyblock(OM_uint32 *minor_status,
726                                  gss_ctx_id_t context_handle,
727                                  krb5_keyblock **keyblock)
728 {
729     return gsskrb5_extract_key(minor_status,
730                                context_handle,
731                                GSS_KRB5_GET_SERVICE_KEYBLOCK_X,
732                                keyblock);
733 }
734
735 OM_uint32
736 gsskrb5_get_initiator_subkey(OM_uint32 *minor_status,
737                              gss_ctx_id_t context_handle,
738                              krb5_keyblock **keyblock)
739 {
740     return gsskrb5_extract_key(minor_status,
741                                context_handle,
742                                GSS_KRB5_GET_INITIATOR_SUBKEY_X,
743                                keyblock);
744 }
745
746 OM_uint32
747 gsskrb5_get_subkey(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_SUBKEY_X,
754                                keyblock);
755 }
756
757 OM_uint32
758 gsskrb5_set_default_realm(const char *realm)
759 {
760         struct _gss_mech_switch *m;
761         gss_buffer_desc buffer;
762         OM_uint32 junk;
763
764         _gss_load_mech();
765
766         buffer.value = rk_UNCONST(realm);
767         buffer.length = strlen(realm);
768
769         SLIST_FOREACH(m, &_gss_mechs, gm_link) {
770                 if (m->gm_mech.gm_set_sec_context_option == NULL)
771                         continue;
772                 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
773                     GSS_KRB5_SET_DEFAULT_REALM_X, &buffer);
774         }
775
776         return (GSS_S_COMPLETE);
777 }