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