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
35GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
36gss_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
93GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
94gss_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);
181out:
182    if (sp)
183	krb5_storage_free(sp);
184    krb5_free_context(context);
185    return major_status;
186}
187
188GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
189gsskrb5_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
208GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
209krb5_gss_register_acceptor_identity(const char *identity)
210{
211    return gsskrb5_register_acceptor_identity(identity);
212}
213
214
215GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
216gsskrb5_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
240static krb5_error_code
241set_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
252static void
253free_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
260GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
261gss_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
385out:
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
403GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
404gss_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
431GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
432gss_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);
475out:
476    if (sp)
477	krb5_storage_free(sp);
478    return maj_status;
479}
480
481/*
482 *
483 */
484
485GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
486gsskrb5_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
516GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
517gss_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
548GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
549gsskrb5_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
603GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
604gsskrb5_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
702static OM_uint32
703gsskrb5_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
754out:
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
776GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
777gsskrb5_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
787GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
788gsskrb5_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
798GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
799gsskrb5_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
809GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
810gsskrb5_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
831GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
832gss_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
870GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
871gsskrb5_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
893GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
894gsskrb5_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
921GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
922gsskrb5_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}
942