gss: use _gss_secure_release_buffer_[set]
[metze/heimdal/wip.git] / 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_TAILQ_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_secure_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         OM_uint32 junk;
394         if (ctx)
395             gss_krb5_free_lucid_sec_context(&junk, ctx);
396
397         *minor_status = ret;
398         return GSS_S_FAILURE;
399     }
400     *minor_status = 0;
401     return GSS_S_COMPLETE;
402 }
403
404 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
405 gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c)
406 {
407     gss_krb5_lucid_context_v1_t *ctx = c;
408
409     if (ctx->version != 1) {
410         if (minor_status)
411             *minor_status = 0;
412         return GSS_S_FAILURE;
413     }
414
415     if (ctx->protocol == 0) {
416         free_key(&ctx->rfc1964_kd.ctx_key);
417     } else if (ctx->protocol == 1) {
418         free_key(&ctx->cfx_kd.ctx_key);
419         if (ctx->cfx_kd.have_acceptor_subkey)
420             free_key(&ctx->cfx_kd.acceptor_subkey);
421     }
422     free(ctx);
423     if (minor_status)
424         *minor_status = 0;
425     return GSS_S_COMPLETE;
426 }
427
428 /*
429  *
430  */
431
432 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
433 gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,
434                                 gss_cred_id_t cred,
435                                 OM_uint32 num_enctypes,
436                                 int32_t *enctypes)
437 {
438     krb5_error_code ret;
439     OM_uint32 maj_status;
440     gss_buffer_desc buffer;
441     krb5_storage *sp;
442     krb5_data data;
443     size_t i;
444
445     sp = krb5_storage_emem();
446     if (sp == NULL) {
447         *minor_status = ENOMEM;
448         maj_status = GSS_S_FAILURE;
449         goto out;
450     }
451
452     for (i = 0; i < num_enctypes; i++) {
453         ret = krb5_store_int32(sp, enctypes[i]);
454         if (ret) {
455             *minor_status = ret;
456             maj_status = GSS_S_FAILURE;
457             goto out;
458         }
459     }
460
461     ret = krb5_storage_to_data(sp, &data);
462     if (ret) {
463         *minor_status = ret;
464         maj_status = GSS_S_FAILURE;
465         goto out;
466     }
467
468     buffer.value = data.data;
469     buffer.length = data.length;
470
471     maj_status = gss_set_cred_option(minor_status,
472                                      &cred,
473                                      GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X,
474                                      &buffer);
475     krb5_data_free(&data);
476 out:
477     if (sp)
478         krb5_storage_free(sp);
479     return maj_status;
480 }
481
482 /*
483  *
484  */
485
486 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
487 gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c)
488 {
489     struct _gss_mech_switch *m;
490     gss_buffer_desc buffer;
491     OM_uint32 junk;
492
493     _gss_load_mech();
494
495     if (c) {
496         buffer.value = c;
497         buffer.length = sizeof(*c);
498     } else {
499         buffer.value = NULL;
500         buffer.length = 0;
501     }
502
503     HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) {
504         if (m->gm_mech.gm_set_sec_context_option == NULL)
505             continue;
506         m->gm_mech.gm_set_sec_context_option(&junk, NULL,
507             GSS_KRB5_SEND_TO_KDC_X, &buffer);
508     }
509
510     return (GSS_S_COMPLETE);
511 }
512
513 /*
514  *
515  */
516
517 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
518 gss_krb5_ccache_name(OM_uint32 *minor_status,
519                      const char *name,
520                      const char **out_name)
521 {
522     struct _gss_mech_switch *m;
523     gss_buffer_desc buffer;
524     OM_uint32 junk;
525
526     _gss_load_mech();
527
528     if (out_name)
529         *out_name = NULL;
530
531     if (name) {
532         buffer.value = rk_UNCONST(name);
533         buffer.length = strlen(name);
534     } else {
535         _mg_buffer_zero(&buffer);
536     }
537
538     HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) {
539         if (m->gm_mech.gm_set_sec_context_option == NULL)
540             continue;
541         m->gm_mech.gm_set_sec_context_option(&junk, NULL,
542             GSS_KRB5_CCACHE_NAME_X, &buffer);
543     }
544
545     return (GSS_S_COMPLETE);
546 }
547
548
549 /*
550  *
551  */
552
553 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
554 gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
555                                           gss_ctx_id_t context_handle,
556                                           time_t *authtime)
557 {
558     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
559     OM_uint32 maj_stat;
560
561     if (context_handle == GSS_C_NO_CONTEXT) {
562         *minor_status = EINVAL;
563         return GSS_S_FAILURE;
564     }
565
566     maj_stat =
567         gss_inquire_sec_context_by_oid (minor_status,
568                                         context_handle,
569                                         GSS_KRB5_GET_AUTHTIME_X,
570                                         &data_set);
571     if (maj_stat)
572         return maj_stat;
573
574     if (data_set == GSS_C_NO_BUFFER_SET) {
575         gss_release_buffer_set(minor_status, &data_set);
576         *minor_status = EINVAL;
577         return GSS_S_FAILURE;
578     }
579
580     if (data_set->count != 1) {
581         gss_release_buffer_set(minor_status, &data_set);
582         *minor_status = EINVAL;
583         return GSS_S_FAILURE;
584     }
585
586     if (data_set->elements[0].length != 4) {
587         gss_release_buffer_set(minor_status, &data_set);
588         *minor_status = EINVAL;
589         return GSS_S_FAILURE;
590     }
591
592     {
593         unsigned char *buf = data_set->elements[0].value;
594         *authtime = (buf[3] <<24) | (buf[2] << 16) |
595             (buf[1] << 8) | (buf[0] << 0);
596     }
597
598     gss_release_buffer_set(minor_status, &data_set);
599
600     *minor_status = 0;
601     return GSS_S_COMPLETE;
602 }
603
604 /*
605  *
606  */
607
608 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
609 gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
610                                             gss_ctx_id_t context_handle,
611                                             int ad_type,
612                                             gss_buffer_t ad_data)
613 {
614     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
615     OM_uint32 maj_stat, tmp;
616     gss_OID_desc oid_flat;
617     heim_oid baseoid, oid;
618     size_t size;
619
620     if (context_handle == GSS_C_NO_CONTEXT) {
621         *minor_status = EINVAL;
622         return GSS_S_FAILURE;
623     }
624
625     /* All this to append an integer to an oid... */
626
627     if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,
628                     GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,
629                     &baseoid, NULL) != 0) {
630         *minor_status = EINVAL;
631         return GSS_S_FAILURE;
632     }
633
634     oid.length = baseoid.length + 1;
635     oid.components = calloc(oid.length, sizeof(*oid.components));
636     if (oid.components == NULL) {
637         der_free_oid(&baseoid);
638
639         *minor_status = ENOMEM;
640         return GSS_S_FAILURE;
641     }
642
643     memcpy(oid.components, baseoid.components,
644            baseoid.length * sizeof(*baseoid.components));
645
646     der_free_oid(&baseoid);
647
648     oid.components[oid.length - 1] = ad_type;
649
650     oid_flat.length = (OM_uint32)der_length_oid(&oid);
651     oid_flat.elements = malloc(oid_flat.length);
652     if (oid_flat.elements == NULL) {
653         free(oid.components);
654         *minor_status = ENOMEM;
655         return GSS_S_FAILURE;
656     }
657
658     if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1,
659                     oid_flat.length, &oid, &size) != 0) {
660         free(oid.components);
661         _gss_free_oid(&tmp, &oid_flat);
662         *minor_status = EINVAL;
663         return GSS_S_FAILURE;
664     }
665     if (oid_flat.length != size)
666         abort();
667
668     free(oid.components);
669
670     /* FINALLY, we have the OID */
671
672     maj_stat = gss_inquire_sec_context_by_oid (minor_status,
673                                                context_handle,
674                                                &oid_flat,
675                                                &data_set);
676
677     _gss_free_oid(&tmp, &oid_flat);
678
679     if (maj_stat)
680         return maj_stat;
681
682     if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
683         gss_release_buffer_set(minor_status, &data_set);
684         *minor_status = EINVAL;
685         return GSS_S_FAILURE;
686     }
687
688     ad_data->value = malloc(data_set->elements[0].length);
689     if (ad_data->value == NULL) {
690         gss_release_buffer_set(minor_status, &data_set);
691         *minor_status = ENOMEM;
692         return GSS_S_FAILURE;
693     }
694
695     ad_data->length = data_set->elements[0].length;
696     memcpy(ad_data->value, data_set->elements[0].value, ad_data->length);
697     gss_release_buffer_set(minor_status, &data_set);
698
699     *minor_status = 0;
700     return GSS_S_COMPLETE;
701 }
702
703 /*
704  *
705  */
706
707 static OM_uint32
708 gsskrb5_extract_key(OM_uint32 *minor_status,
709                     gss_ctx_id_t context_handle,
710                     const gss_OID oid,
711                     krb5_keyblock **keyblock)
712 {
713     krb5_error_code ret;
714     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
715     OM_uint32 major_status;
716     krb5_context context = NULL;
717     krb5_storage *sp = NULL;
718
719     if (context_handle == GSS_C_NO_CONTEXT) {
720         *minor_status = EINVAL;
721         return GSS_S_FAILURE;
722     }
723
724     ret = krb5_init_context(&context);
725     if(ret) {
726         *minor_status = ret;
727         return GSS_S_FAILURE;
728     }
729
730     major_status =
731         gss_inquire_sec_context_by_oid (minor_status,
732                                         context_handle,
733                                         oid,
734                                         &data_set);
735     if (major_status)
736         return major_status;
737
738     if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
739         _gss_secure_release_buffer_set(minor_status, &data_set);
740         *minor_status = EINVAL;
741         return GSS_S_FAILURE;
742     }
743
744     sp = krb5_storage_from_mem(data_set->elements[0].value,
745                                data_set->elements[0].length);
746     if (sp == NULL) {
747         ret = ENOMEM;
748         goto out;
749     }
750
751     *keyblock = calloc(1, sizeof(**keyblock));
752     if (keyblock == NULL) {
753         ret = ENOMEM;
754         goto out;
755     }
756
757     ret = krb5_ret_keyblock(sp, *keyblock);
758
759 out:
760     _gss_secure_release_buffer_set(minor_status, &data_set);
761     if (sp)
762         krb5_storage_free(sp);
763     if (ret && keyblock) {
764         krb5_free_keyblock(context, *keyblock);
765         *keyblock = NULL;
766     }
767     if (context)
768         krb5_free_context(context);
769
770     *minor_status = ret;
771     if (ret)
772         return GSS_S_FAILURE;
773
774     return GSS_S_COMPLETE;
775 }
776
777 /*
778  *
779  */
780
781 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
782 gsskrb5_extract_service_keyblock(OM_uint32 *minor_status,
783                                  gss_ctx_id_t context_handle,
784                                  krb5_keyblock **keyblock)
785 {
786     return gsskrb5_extract_key(minor_status,
787                                context_handle,
788                                GSS_KRB5_GET_SERVICE_KEYBLOCK_X,
789                                keyblock);
790 }
791
792 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
793 gsskrb5_get_initiator_subkey(OM_uint32 *minor_status,
794                              gss_ctx_id_t context_handle,
795                              krb5_keyblock **keyblock)
796 {
797     return gsskrb5_extract_key(minor_status,
798                                context_handle,
799                                GSS_KRB5_GET_INITIATOR_SUBKEY_X,
800                                keyblock);
801 }
802
803 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
804 gsskrb5_get_subkey(OM_uint32 *minor_status,
805                    gss_ctx_id_t context_handle,
806                    krb5_keyblock **keyblock)
807 {
808     return gsskrb5_extract_key(minor_status,
809                                context_handle,
810                                GSS_KRB5_GET_SUBKEY_X,
811                                keyblock);
812 }
813
814 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
815 gsskrb5_set_default_realm(const char *realm)
816 {
817         struct _gss_mech_switch *m;
818         gss_buffer_desc buffer;
819         OM_uint32 junk;
820
821         _gss_load_mech();
822
823         buffer.value = rk_UNCONST(realm);
824         buffer.length = strlen(realm);
825
826         HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) {
827                 if (m->gm_mech.gm_set_sec_context_option == NULL)
828                         continue;
829                 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
830                     GSS_KRB5_SET_DEFAULT_REALM_X, &buffer);
831         }
832
833         return (GSS_S_COMPLETE);
834 }
835
836 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
837 gss_krb5_get_tkt_flags(OM_uint32 *minor_status,
838                        gss_ctx_id_t context_handle,
839                        OM_uint32 *tkt_flags)
840 {
841
842     OM_uint32 major_status;
843     gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
844
845     if (context_handle == GSS_C_NO_CONTEXT) {
846         *minor_status = EINVAL;
847         return GSS_S_FAILURE;
848     }
849
850     major_status =
851         gss_inquire_sec_context_by_oid (minor_status,
852                                         context_handle,
853                                         GSS_KRB5_GET_TKT_FLAGS_X,
854                                         &data_set);
855     if (major_status)
856         return major_status;
857
858     if (data_set == GSS_C_NO_BUFFER_SET ||
859         data_set->count != 1 ||
860         data_set->elements[0].length < 4) {
861         gss_release_buffer_set(minor_status, &data_set);
862         *minor_status = EINVAL;
863         return GSS_S_FAILURE;
864     }
865
866     {
867         const u_char *p = data_set->elements[0].value;
868         *tkt_flags = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
869     }
870
871     gss_release_buffer_set(minor_status, &data_set);
872     return GSS_S_COMPLETE;
873 }
874
875 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
876 gsskrb5_set_time_offset(int offset)
877 {
878         struct _gss_mech_switch *m;
879         gss_buffer_desc buffer;
880         OM_uint32 junk;
881         int32_t o = offset;
882
883         _gss_load_mech();
884
885         buffer.value = &o;
886         buffer.length = sizeof(o);
887
888         HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) {
889                 if (m->gm_mech.gm_set_sec_context_option == NULL)
890                         continue;
891                 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
892                     GSS_KRB5_SET_TIME_OFFSET_X, &buffer);
893         }
894
895         return (GSS_S_COMPLETE);
896 }
897
898 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
899 gsskrb5_get_time_offset(int *offset)
900 {
901         struct _gss_mech_switch *m;
902         gss_buffer_desc buffer;
903         OM_uint32 maj_stat, junk;
904         int32_t o;
905
906         _gss_load_mech();
907
908         buffer.value = &o;
909         buffer.length = sizeof(o);
910
911         HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) {
912                 if (m->gm_mech.gm_set_sec_context_option == NULL)
913                         continue;
914                 maj_stat = m->gm_mech.gm_set_sec_context_option(&junk, NULL,
915                     GSS_KRB5_GET_TIME_OFFSET_X, &buffer);
916
917                 if (maj_stat == GSS_S_COMPLETE) {
918                         *offset = o;
919                         return maj_stat;
920                 }
921         }
922
923         return (GSS_S_UNAVAILABLE);
924 }
925
926 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
927 gsskrb5_plugin_register(struct gsskrb5_krb5_plugin *c)
928 {
929     struct _gss_mech_switch *m;
930     gss_buffer_desc buffer;
931     OM_uint32 junk;
932
933     _gss_load_mech();
934
935     buffer.value = c;
936     buffer.length = sizeof(*c);
937
938     HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) {
939         if (m->gm_mech.gm_set_sec_context_option == NULL)
940             continue;
941         m->gm_mech.gm_set_sec_context_option(&junk, NULL,
942             GSS_KRB5_PLUGIN_REGISTER_X, &buffer);
943     }
944
945     return (GSS_S_COMPLETE);
946 }