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