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