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