1178828Sdfr/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
4178828Sdfr * Copyright (c) 2005 Doug Rabson
5178828Sdfr * All rights reserved.
6178828Sdfr *
7178828Sdfr * Redistribution and use in source and binary forms, with or without
8178828Sdfr * modification, are permitted provided that the following conditions
9178828Sdfr * are met:
10178828Sdfr * 1. Redistributions of source code must retain the above copyright
11178828Sdfr *    notice, this list of conditions and the following disclaimer.
12178828Sdfr * 2. Redistributions in binary form must reproduce the above copyright
13178828Sdfr *    notice, this list of conditions and the following disclaimer in the
14178828Sdfr *    documentation and/or other materials provided with the distribution.
15178828Sdfr *
16178828Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17178828Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18178828Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19178828Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20178828Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21178828Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22178828Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23178828Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24178828Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25178828Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26178828Sdfr * SUCH DAMAGE.
27178828Sdfr *
28178828Sdfr *	$FreeBSD: stable/11/kerberos5/lib/libgssapi_krb5/gss_krb5.c 330449 2018-03-05 07:26:05Z eadler $
29178828Sdfr */
30178828Sdfr
31178828Sdfr#include <gssapi/gssapi.h>
32178828Sdfr#include <gssapi/gssapi_krb5.h>
33178828Sdfr
34178828Sdfr/* RCSID("$Id: gss_krb5.c 21889 2007-08-09 07:43:24Z lha $"); */
35178828Sdfr
36178828Sdfr#include <krb5.h>
37178828Sdfr#include <roken.h>
38233294Sstas#include <der.h>
39178828Sdfr
40178828SdfrOM_uint32
41178828Sdfrgss_krb5_copy_ccache(OM_uint32 *minor_status,
42178828Sdfr		     gss_cred_id_t cred,
43178828Sdfr		     krb5_ccache out)
44178828Sdfr{
45178828Sdfr    gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
46178828Sdfr    krb5_context context;
47178828Sdfr    krb5_error_code kret;
48178828Sdfr    krb5_ccache id;
49178828Sdfr    OM_uint32 ret;
50178828Sdfr    char *str;
51178828Sdfr
52178828Sdfr    ret = gss_inquire_cred_by_oid(minor_status,
53178828Sdfr				  cred,
54178828Sdfr				  GSS_KRB5_COPY_CCACHE_X,
55178828Sdfr				  &data_set);
56178828Sdfr    if (ret)
57178828Sdfr	return ret;
58178828Sdfr
59178828Sdfr    if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
60178828Sdfr	gss_release_buffer_set(minor_status, &data_set);
61178828Sdfr	*minor_status = EINVAL;
62178828Sdfr	return GSS_S_FAILURE;
63178828Sdfr    }
64178828Sdfr
65178828Sdfr    kret = krb5_init_context(&context);
66178828Sdfr    if (kret) {
67178828Sdfr	*minor_status = kret;
68178828Sdfr	gss_release_buffer_set(minor_status, &data_set);
69178828Sdfr	return GSS_S_FAILURE;
70178828Sdfr    }
71178828Sdfr
72178828Sdfr    kret = asprintf(&str, "%.*s", (int)data_set->elements[0].length,
73178828Sdfr		    (char *)data_set->elements[0].value);
74178828Sdfr    gss_release_buffer_set(minor_status, &data_set);
75178828Sdfr    if (kret == -1) {
76178828Sdfr	*minor_status = ENOMEM;
77178828Sdfr	return GSS_S_FAILURE;
78178828Sdfr    }
79178828Sdfr
80178828Sdfr    kret = krb5_cc_resolve(context, str, &id);
81178828Sdfr    free(str);
82178828Sdfr    if (kret) {
83178828Sdfr	*minor_status = kret;
84178828Sdfr	return GSS_S_FAILURE;
85178828Sdfr    }
86178828Sdfr
87178828Sdfr    kret = krb5_cc_copy_cache(context, id, out);
88178828Sdfr    krb5_cc_close(context, id);
89178828Sdfr    krb5_free_context(context);
90178828Sdfr    if (kret) {
91178828Sdfr	*minor_status = kret;
92178828Sdfr	return GSS_S_FAILURE;
93178828Sdfr    }
94178828Sdfr
95178828Sdfr    return ret;
96178828Sdfr}
97178828Sdfr
98178828SdfrOM_uint32
99178828Sdfrgss_krb5_import_cred(OM_uint32 *minor_status,
100178828Sdfr		     krb5_ccache id,
101178828Sdfr		     krb5_principal keytab_principal,
102178828Sdfr		     krb5_keytab keytab,
103178828Sdfr		     gss_cred_id_t *cred)
104178828Sdfr{
105178828Sdfr    gss_buffer_desc buffer;
106178828Sdfr    OM_uint32 major_status;
107178828Sdfr    krb5_context context;
108178828Sdfr    krb5_error_code ret;
109178828Sdfr    krb5_storage *sp;
110178828Sdfr    krb5_data data;
111178828Sdfr    char *str;
112178828Sdfr
113178828Sdfr    *cred = GSS_C_NO_CREDENTIAL;
114178828Sdfr
115178828Sdfr    ret = krb5_init_context(&context);
116178828Sdfr    if (ret) {
117178828Sdfr	*minor_status = ret;
118178828Sdfr	return GSS_S_FAILURE;
119178828Sdfr    }
120178828Sdfr
121178828Sdfr    sp = krb5_storage_emem();
122178828Sdfr    if (sp == NULL) {
123178828Sdfr	*minor_status = ENOMEM;
124178828Sdfr	major_status = GSS_S_FAILURE;
125178828Sdfr	goto out;
126178828Sdfr    }
127178828Sdfr
128178828Sdfr    if (id) {
129178828Sdfr	ret = krb5_cc_get_full_name(context, id, &str);
130178828Sdfr	if (ret == 0) {
131178828Sdfr	    ret = krb5_store_string(sp, str);
132178828Sdfr	    free(str);
133178828Sdfr	}
134178828Sdfr    } else
135178828Sdfr	ret = krb5_store_string(sp, "");
136178828Sdfr    if (ret) {
137178828Sdfr	*minor_status = ret;
138178828Sdfr	major_status = GSS_S_FAILURE;
139178828Sdfr	goto out;
140178828Sdfr    }
141178828Sdfr
142178828Sdfr    if (keytab_principal) {
143178828Sdfr	ret = krb5_unparse_name(context, keytab_principal, &str);
144178828Sdfr	if (ret == 0) {
145178828Sdfr	    ret = krb5_store_string(sp, str);
146178828Sdfr	    free(str);
147178828Sdfr	}
148178828Sdfr    } else
149178828Sdfr	krb5_store_string(sp, "");
150178828Sdfr    if (ret) {
151178828Sdfr	*minor_status = ret;
152178828Sdfr	major_status = GSS_S_FAILURE;
153178828Sdfr	goto out;
154178828Sdfr    }
155178828Sdfr
156178828Sdfr
157178828Sdfr    if (keytab) {
158178828Sdfr	ret = krb5_kt_get_full_name(context, keytab, &str);
159178828Sdfr	if (ret == 0) {
160178828Sdfr	    ret = krb5_store_string(sp, str);
161178828Sdfr	    free(str);
162178828Sdfr	}
163178828Sdfr    } else
164178828Sdfr	krb5_store_string(sp, "");
165178828Sdfr    if (ret) {
166178828Sdfr	*minor_status = ret;
167178828Sdfr	major_status = GSS_S_FAILURE;
168178828Sdfr	goto out;
169178828Sdfr    }
170178828Sdfr
171178828Sdfr    ret = krb5_storage_to_data(sp, &data);
172178828Sdfr    if (ret) {
173178828Sdfr	*minor_status = ret;
174178828Sdfr	major_status = GSS_S_FAILURE;
175178828Sdfr	goto out;
176178828Sdfr    }
177178828Sdfr
178178828Sdfr    buffer.value = data.data;
179178828Sdfr    buffer.length = data.length;
180178828Sdfr
181178828Sdfr    major_status = gss_set_cred_option(minor_status,
182178828Sdfr				       cred,
183178828Sdfr				       GSS_KRB5_IMPORT_CRED_X,
184178828Sdfr				       &buffer);
185178828Sdfr    krb5_data_free(&data);
186178828Sdfrout:
187178828Sdfr    if (sp)
188178828Sdfr	krb5_storage_free(sp);
189178828Sdfr    krb5_free_context(context);
190178828Sdfr    return major_status;
191178828Sdfr}
192178828Sdfr
193178828SdfrOM_uint32
194178828Sdfrgsskrb5_register_acceptor_identity(const char *identity)
195178828Sdfr{
196178828Sdfr	gss_buffer_desc buffer;
197178828Sdfr	OM_uint32 junk;
198178828Sdfr
199178828Sdfr	buffer.value = rk_UNCONST(identity);
200178828Sdfr	buffer.length = strlen(identity);
201178828Sdfr
202178828Sdfr	gss_set_sec_context_option(&junk, NULL,
203178828Sdfr	    GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X, &buffer);
204178828Sdfr
205178828Sdfr	return (GSS_S_COMPLETE);
206178828Sdfr}
207178828Sdfr
208178828SdfrOM_uint32
209178828Sdfrgsskrb5_set_dns_canonicalize(int flag)
210178828Sdfr{
211178828Sdfr	gss_buffer_desc buffer;
212178828Sdfr	OM_uint32 junk;
213178828Sdfr	char b = (flag != 0);
214178828Sdfr
215178828Sdfr	buffer.value = &b;
216178828Sdfr	buffer.length = sizeof(b);
217178828Sdfr
218178828Sdfr	gss_set_sec_context_option(&junk, NULL,
219178828Sdfr	    GSS_KRB5_SET_DNS_CANONICALIZE_X, &buffer);
220178828Sdfr
221178828Sdfr	return (GSS_S_COMPLETE);
222178828Sdfr}
223178828Sdfr
224178828Sdfr
225178828Sdfr
226178828Sdfrstatic krb5_error_code
227178828Sdfrset_key(krb5_keyblock *keyblock, gss_krb5_lucid_key_t *key)
228178828Sdfr{
229178828Sdfr    key->type = keyblock->keytype;
230178828Sdfr    key->length = keyblock->keyvalue.length;
231178828Sdfr    key->data = malloc(key->length);
232178828Sdfr    if (key->data == NULL && key->length != 0)
233178828Sdfr	return ENOMEM;
234178828Sdfr    memcpy(key->data, keyblock->keyvalue.data, key->length);
235178828Sdfr    return 0;
236178828Sdfr}
237178828Sdfr
238178828Sdfrstatic void
239178828Sdfrfree_key(gss_krb5_lucid_key_t *key)
240178828Sdfr{
241178828Sdfr    memset(key->data, 0, key->length);
242178828Sdfr    free(key->data);
243178828Sdfr    memset(key, 0, sizeof(*key));
244178828Sdfr}
245178828Sdfr
246178828SdfrOM_uint32
247178828Sdfrgss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,
248178828Sdfr				  gss_ctx_id_t *context_handle,
249178828Sdfr				  OM_uint32 version,
250178828Sdfr				  void **rctx)
251178828Sdfr{
252178828Sdfr    krb5_context context = NULL;
253178828Sdfr    krb5_error_code ret;
254178828Sdfr    gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
255178828Sdfr    OM_uint32 major_status;
256178828Sdfr    gss_krb5_lucid_context_v1_t *ctx = NULL;
257178828Sdfr    krb5_storage *sp = NULL;
258178828Sdfr    uint32_t num;
259178828Sdfr
260178828Sdfr    if (context_handle == NULL
261178828Sdfr	|| *context_handle == GSS_C_NO_CONTEXT
262178828Sdfr	|| version != 1)
263178828Sdfr    {
264178828Sdfr	ret = EINVAL;
265178828Sdfr	return GSS_S_FAILURE;
266178828Sdfr    }
267178828Sdfr
268178828Sdfr    major_status =
269178828Sdfr	gss_inquire_sec_context_by_oid (minor_status,
270178828Sdfr					*context_handle,
271178828Sdfr					GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X,
272178828Sdfr					&data_set);
273178828Sdfr    if (major_status)
274178828Sdfr	return major_status;
275178828Sdfr
276178828Sdfr    if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
277178828Sdfr	gss_release_buffer_set(minor_status, &data_set);
278178828Sdfr	*minor_status = EINVAL;
279178828Sdfr	return GSS_S_FAILURE;
280178828Sdfr    }
281178828Sdfr
282178828Sdfr    ret = krb5_init_context(&context);
283178828Sdfr    if (ret)
284178828Sdfr	goto out;
285178828Sdfr
286178828Sdfr    ctx = calloc(1, sizeof(*ctx));
287178828Sdfr    if (ctx == NULL) {
288178828Sdfr	ret = ENOMEM;
289178828Sdfr	goto out;
290178828Sdfr    }
291178828Sdfr
292178828Sdfr    sp = krb5_storage_from_mem(data_set->elements[0].value,
293178828Sdfr			       data_set->elements[0].length);
294178828Sdfr    if (sp == NULL) {
295178828Sdfr	ret = ENOMEM;
296178828Sdfr	goto out;
297178828Sdfr    }
298178828Sdfr
299178828Sdfr    ret = krb5_ret_uint32(sp, &num);
300178828Sdfr    if (ret) goto out;
301178828Sdfr    if (num != 1) {
302178828Sdfr	ret = EINVAL;
303178828Sdfr	goto out;
304178828Sdfr    }
305178828Sdfr    ctx->version = 1;
306178828Sdfr    /* initiator */
307178828Sdfr    ret = krb5_ret_uint32(sp, &ctx->initiate);
308178828Sdfr    if (ret) goto out;
309178828Sdfr    /* endtime */
310178828Sdfr    ret = krb5_ret_uint32(sp, &ctx->endtime);
311178828Sdfr    if (ret) goto out;
312178828Sdfr    /* send_seq */
313178828Sdfr    ret = krb5_ret_uint32(sp, &num);
314178828Sdfr    if (ret) goto out;
315178828Sdfr    ctx->send_seq = ((uint64_t)num) << 32;
316178828Sdfr    ret = krb5_ret_uint32(sp, &num);
317178828Sdfr    if (ret) goto out;
318178828Sdfr    ctx->send_seq |= num;
319178828Sdfr    /* recv_seq */
320178828Sdfr    ret = krb5_ret_uint32(sp, &num);
321178828Sdfr    if (ret) goto out;
322178828Sdfr    ctx->recv_seq = ((uint64_t)num) << 32;
323178828Sdfr    ret = krb5_ret_uint32(sp, &num);
324178828Sdfr    if (ret) goto out;
325178828Sdfr    ctx->recv_seq |= num;
326178828Sdfr    /* protocol */
327178828Sdfr    ret = krb5_ret_uint32(sp, &ctx->protocol);
328178828Sdfr    if (ret) goto out;
329178828Sdfr    if (ctx->protocol == 0) {
330178828Sdfr	krb5_keyblock key;
331178828Sdfr
332178828Sdfr	/* sign_alg */
333178828Sdfr	ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg);
334178828Sdfr	if (ret) goto out;
335178828Sdfr	/* seal_alg */
336178828Sdfr	ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg);
337178828Sdfr	if (ret) goto out;
338178828Sdfr	/* ctx_key */
339178828Sdfr	ret = krb5_ret_keyblock(sp, &key);
340178828Sdfr	if (ret) goto out;
341178828Sdfr	ret = set_key(&key, &ctx->rfc1964_kd.ctx_key);
342178828Sdfr	krb5_free_keyblock_contents(context, &key);
343178828Sdfr	if (ret) goto out;
344178828Sdfr    } else if (ctx->protocol == 1) {
345178828Sdfr	krb5_keyblock key;
346178828Sdfr
347178828Sdfr	/* acceptor_subkey */
348178828Sdfr	ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey);
349178828Sdfr	if (ret) goto out;
350178828Sdfr	/* ctx_key */
351178828Sdfr	ret = krb5_ret_keyblock(sp, &key);
352178828Sdfr	if (ret) goto out;
353178828Sdfr	ret = set_key(&key, &ctx->cfx_kd.ctx_key);
354178828Sdfr	krb5_free_keyblock_contents(context, &key);
355178828Sdfr	if (ret) goto out;
356178828Sdfr	/* acceptor_subkey */
357178828Sdfr	if (ctx->cfx_kd.have_acceptor_subkey) {
358178828Sdfr	    ret = krb5_ret_keyblock(sp, &key);
359178828Sdfr	    if (ret) goto out;
360178828Sdfr	    ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey);
361178828Sdfr	    krb5_free_keyblock_contents(context, &key);
362178828Sdfr	    if (ret) goto out;
363178828Sdfr	}
364178828Sdfr    } else {
365178828Sdfr	ret = EINVAL;
366178828Sdfr	goto out;
367178828Sdfr    }
368178828Sdfr
369178828Sdfr    *rctx = ctx;
370178828Sdfr
371178828Sdfrout:
372178828Sdfr    gss_release_buffer_set(minor_status, &data_set);
373178828Sdfr    if (sp)
374178828Sdfr	krb5_storage_free(sp);
375178828Sdfr    if (context)
376178828Sdfr	krb5_free_context(context);
377178828Sdfr
378178828Sdfr    if (ret) {
379178828Sdfr	if (ctx)
380178828Sdfr	    gss_krb5_free_lucid_sec_context(NULL, ctx);
381178828Sdfr
382178828Sdfr	*minor_status = ret;
383178828Sdfr	return GSS_S_FAILURE;
384178828Sdfr    }
385178828Sdfr    *minor_status = 0;
386178828Sdfr    return GSS_S_COMPLETE;
387178828Sdfr}
388178828Sdfr
389178828SdfrOM_uint32
390178828Sdfrgss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c)
391178828Sdfr{
392178828Sdfr    gss_krb5_lucid_context_v1_t *ctx = c;
393178828Sdfr
394178828Sdfr    if (ctx->version != 1) {
395178828Sdfr	if (minor_status)
396178828Sdfr	    *minor_status = 0;
397178828Sdfr	return GSS_S_FAILURE;
398178828Sdfr    }
399178828Sdfr
400178828Sdfr    if (ctx->protocol == 0) {
401178828Sdfr	free_key(&ctx->rfc1964_kd.ctx_key);
402178828Sdfr    } else if (ctx->protocol == 1) {
403178828Sdfr	free_key(&ctx->cfx_kd.ctx_key);
404178828Sdfr	if (ctx->cfx_kd.have_acceptor_subkey)
405178828Sdfr	    free_key(&ctx->cfx_kd.acceptor_subkey);
406178828Sdfr    }
407178828Sdfr    free(ctx);
408178828Sdfr    if (minor_status)
409178828Sdfr	*minor_status = 0;
410178828Sdfr    return GSS_S_COMPLETE;
411178828Sdfr}
412178828Sdfr
413178828Sdfr/*
414178828Sdfr *
415178828Sdfr */
416178828Sdfr
417178828SdfrOM_uint32
418178828Sdfrgss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,
419178828Sdfr				gss_cred_id_t cred,
420178828Sdfr				OM_uint32 num_enctypes,
421178828Sdfr				int32_t *enctypes)
422178828Sdfr{
423178828Sdfr    krb5_error_code ret;
424178828Sdfr    OM_uint32 maj_status;
425178828Sdfr    gss_buffer_desc buffer;
426178828Sdfr    krb5_storage *sp;
427178828Sdfr    krb5_data data;
428178828Sdfr    int i;
429178828Sdfr
430178828Sdfr    sp = krb5_storage_emem();
431178828Sdfr    if (sp == NULL) {
432178828Sdfr	*minor_status = ENOMEM;
433178828Sdfr	maj_status = GSS_S_FAILURE;
434178828Sdfr	goto out;
435178828Sdfr    }
436178828Sdfr
437178828Sdfr    for (i = 0; i < num_enctypes; i++) {
438178828Sdfr	ret = krb5_store_int32(sp, enctypes[i]);
439178828Sdfr	if (ret) {
440178828Sdfr	    *minor_status = ret;
441178828Sdfr	    maj_status = GSS_S_FAILURE;
442178828Sdfr	    goto out;
443178828Sdfr	}
444178828Sdfr    }
445178828Sdfr
446178828Sdfr    ret = krb5_storage_to_data(sp, &data);
447178828Sdfr    if (ret) {
448178828Sdfr	*minor_status = ret;
449178828Sdfr	maj_status = GSS_S_FAILURE;
450178828Sdfr	goto out;
451178828Sdfr    }
452178828Sdfr
453178828Sdfr    buffer.value = data.data;
454178828Sdfr    buffer.length = data.length;
455178828Sdfr
456178828Sdfr    maj_status = gss_set_cred_option(minor_status,
457178828Sdfr				     &cred,
458178828Sdfr				     GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X,
459178828Sdfr				     &buffer);
460178828Sdfr    krb5_data_free(&data);
461178828Sdfrout:
462178828Sdfr    if (sp)
463178828Sdfr	krb5_storage_free(sp);
464178828Sdfr    return maj_status;
465178828Sdfr}
466178828Sdfr
467178828Sdfr/*
468178828Sdfr *
469178828Sdfr */
470178828Sdfr
471178828SdfrOM_uint32
472178828Sdfrgsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c)
473178828Sdfr{
474178828Sdfr    gss_buffer_desc buffer;
475178828Sdfr    OM_uint32 junk;
476178828Sdfr
477178828Sdfr    if (c) {
478178828Sdfr	buffer.value = c;
479178828Sdfr	buffer.length = sizeof(*c);
480178828Sdfr    } else {
481178828Sdfr	buffer.value = NULL;
482178828Sdfr	buffer.length = 0;
483178828Sdfr    }
484178828Sdfr
485178828Sdfr    gss_set_sec_context_option(&junk, NULL,
486178828Sdfr	    GSS_KRB5_SEND_TO_KDC_X, &buffer);
487178828Sdfr
488178828Sdfr    return (GSS_S_COMPLETE);
489178828Sdfr}
490178828Sdfr
491178828Sdfr/*
492178828Sdfr *
493178828Sdfr */
494178828Sdfr
495178828SdfrOM_uint32
496178828Sdfrgss_krb5_ccache_name(OM_uint32 *minor_status,
497178828Sdfr		     const char *name,
498178828Sdfr		     const char **out_name)
499178828Sdfr{
500178828Sdfr    gss_buffer_desc buffer;
501178828Sdfr    OM_uint32 junk;
502178828Sdfr
503178828Sdfr    if (out_name)
504178828Sdfr	*out_name = NULL;
505178828Sdfr
506178828Sdfr    buffer.value = rk_UNCONST(name);
507178828Sdfr    buffer.length = strlen(name);
508178828Sdfr
509178828Sdfr    gss_set_sec_context_option(&junk, NULL,
510178828Sdfr	    GSS_KRB5_CCACHE_NAME_X, &buffer);
511178828Sdfr
512178828Sdfr    return (GSS_S_COMPLETE);
513178828Sdfr}
514178828Sdfr
515178828Sdfr
516178828Sdfr/*
517178828Sdfr *
518178828Sdfr */
519178828Sdfr
520178828SdfrOM_uint32
521178828Sdfrgsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
522178828Sdfr					  gss_ctx_id_t context_handle,
523178828Sdfr					  time_t *authtime)
524178828Sdfr{
525178828Sdfr    gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
526178828Sdfr    OM_uint32 maj_stat;
527178828Sdfr
528178828Sdfr    if (context_handle == GSS_C_NO_CONTEXT) {
529178828Sdfr	*minor_status = EINVAL;
530178828Sdfr	return GSS_S_FAILURE;
531178828Sdfr    }
532178828Sdfr
533178828Sdfr    maj_stat =
534178828Sdfr	gss_inquire_sec_context_by_oid (minor_status,
535178828Sdfr					context_handle,
536178828Sdfr					GSS_KRB5_GET_AUTHTIME_X,
537178828Sdfr					&data_set);
538178828Sdfr    if (maj_stat)
539178828Sdfr	return maj_stat;
540178828Sdfr
541178828Sdfr    if (data_set == GSS_C_NO_BUFFER_SET) {
542178828Sdfr	gss_release_buffer_set(minor_status, &data_set);
543178828Sdfr	*minor_status = EINVAL;
544178828Sdfr	return GSS_S_FAILURE;
545178828Sdfr    }
546178828Sdfr
547178828Sdfr    if (data_set->count != 1) {
548178828Sdfr	gss_release_buffer_set(minor_status, &data_set);
549178828Sdfr	*minor_status = EINVAL;
550178828Sdfr	return GSS_S_FAILURE;
551178828Sdfr    }
552178828Sdfr
553178828Sdfr    if (data_set->elements[0].length != 4) {
554178828Sdfr	gss_release_buffer_set(minor_status, &data_set);
555178828Sdfr	*minor_status = EINVAL;
556178828Sdfr	return GSS_S_FAILURE;
557178828Sdfr    }
558178828Sdfr
559178828Sdfr    {
560178828Sdfr	unsigned char *buf = data_set->elements[0].value;
561178828Sdfr	*authtime = (buf[3] <<24) | (buf[2] << 16) |
562178828Sdfr	    (buf[1] << 8) | (buf[0] << 0);
563178828Sdfr    }
564178828Sdfr
565178828Sdfr    gss_release_buffer_set(minor_status, &data_set);
566178828Sdfr
567178828Sdfr    *minor_status = 0;
568178828Sdfr    return GSS_S_COMPLETE;
569178828Sdfr}
570178828Sdfr
571178828Sdfr/*
572178828Sdfr *
573178828Sdfr */
574178828Sdfr
575178828SdfrOM_uint32
576178828Sdfrgsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
577178828Sdfr					    gss_ctx_id_t context_handle,
578178828Sdfr					    int ad_type,
579178828Sdfr					    gss_buffer_t ad_data)
580178828Sdfr{
581178828Sdfr    gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
582178828Sdfr    OM_uint32 maj_stat;
583178828Sdfr    gss_OID_desc oid_flat;
584178828Sdfr    heim_oid baseoid, oid;
585178828Sdfr    size_t size;
586178828Sdfr
587178828Sdfr    if (context_handle == GSS_C_NO_CONTEXT) {
588178828Sdfr	*minor_status = EINVAL;
589178828Sdfr	return GSS_S_FAILURE;
590178828Sdfr    }
591178828Sdfr
592178828Sdfr    /* All this to append an integer to an oid... */
593178828Sdfr
594178828Sdfr    if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,
595178828Sdfr		    GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,
596178828Sdfr		    &baseoid, NULL) != 0) {
597178828Sdfr	*minor_status = EINVAL;
598178828Sdfr	return GSS_S_FAILURE;
599178828Sdfr    }
600178828Sdfr
601178828Sdfr    oid.length = baseoid.length + 1;
602178828Sdfr    oid.components = calloc(oid.length, sizeof(*oid.components));
603178828Sdfr    if (oid.components == NULL) {
604178828Sdfr	der_free_oid(&baseoid);
605178828Sdfr
606178828Sdfr	*minor_status = ENOMEM;
607178828Sdfr	return GSS_S_FAILURE;
608178828Sdfr    }
609178828Sdfr
610178828Sdfr    memcpy(oid.components, baseoid.components,
611178828Sdfr	   baseoid.length * sizeof(*baseoid.components));
612178828Sdfr
613178828Sdfr    der_free_oid(&baseoid);
614178828Sdfr
615178828Sdfr    oid.components[oid.length - 1] = ad_type;
616178828Sdfr
617178828Sdfr    oid_flat.length = der_length_oid(&oid);
618178828Sdfr    oid_flat.elements = malloc(oid_flat.length);
619178828Sdfr    if (oid_flat.elements == NULL) {
620178828Sdfr	free(oid.components);
621178828Sdfr	*minor_status = ENOMEM;
622178828Sdfr	return GSS_S_FAILURE;
623178828Sdfr    }
624178828Sdfr
625178828Sdfr    if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1,
626178828Sdfr		    oid_flat.length, &oid, &size) != 0) {
627178828Sdfr	free(oid.components);
628178828Sdfr	free(oid_flat.elements);
629178828Sdfr	*minor_status = EINVAL;
630178828Sdfr	return GSS_S_FAILURE;
631178828Sdfr    }
632178828Sdfr    if (oid_flat.length != size)
633178828Sdfr	abort();
634178828Sdfr
635178828Sdfr    free(oid.components);
636178828Sdfr
637178828Sdfr    /* FINALLY, we have the OID */
638178828Sdfr
639178828Sdfr    maj_stat = gss_inquire_sec_context_by_oid (minor_status,
640178828Sdfr					       context_handle,
641178828Sdfr					       &oid_flat,
642178828Sdfr					       &data_set);
643178828Sdfr
644178828Sdfr    free(oid_flat.elements);
645178828Sdfr
646178828Sdfr    if (maj_stat)
647178828Sdfr	return maj_stat;
648178828Sdfr
649178828Sdfr    if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
650178828Sdfr	gss_release_buffer_set(minor_status, &data_set);
651178828Sdfr	*minor_status = EINVAL;
652178828Sdfr	return GSS_S_FAILURE;
653178828Sdfr    }
654178828Sdfr
655178828Sdfr    ad_data->value = malloc(data_set->elements[0].length);
656178828Sdfr    if (ad_data->value == NULL) {
657178828Sdfr	gss_release_buffer_set(minor_status, &data_set);
658178828Sdfr	*minor_status = ENOMEM;
659178828Sdfr	return GSS_S_FAILURE;
660178828Sdfr    }
661178828Sdfr
662178828Sdfr    ad_data->length = data_set->elements[0].length;
663178828Sdfr    memcpy(ad_data->value, data_set->elements[0].value, ad_data->length);
664178828Sdfr    gss_release_buffer_set(minor_status, &data_set);
665178828Sdfr
666178828Sdfr    *minor_status = 0;
667178828Sdfr    return GSS_S_COMPLETE;
668178828Sdfr}
669178828Sdfr
670178828Sdfr/*
671178828Sdfr *
672178828Sdfr */
673178828Sdfr
674178828Sdfrstatic OM_uint32
675178828Sdfrgsskrb5_extract_key(OM_uint32 *minor_status,
676178828Sdfr		    gss_ctx_id_t context_handle,
677178828Sdfr		    const gss_OID oid,
678178828Sdfr		    krb5_keyblock **keyblock)
679178828Sdfr{
680178828Sdfr    krb5_error_code ret;
681178828Sdfr    gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
682178828Sdfr    OM_uint32 major_status;
683178828Sdfr    krb5_context context = NULL;
684178828Sdfr    krb5_storage *sp = NULL;
685178828Sdfr
686178828Sdfr    if (context_handle == GSS_C_NO_CONTEXT) {
687178828Sdfr	ret = EINVAL;
688178828Sdfr	return GSS_S_FAILURE;
689178828Sdfr    }
690178828Sdfr
691178828Sdfr    ret = krb5_init_context(&context);
692178828Sdfr    if(ret) {
693178828Sdfr	*minor_status = ret;
694178828Sdfr	return GSS_S_FAILURE;
695178828Sdfr    }
696178828Sdfr
697178828Sdfr    major_status =
698178828Sdfr	gss_inquire_sec_context_by_oid (minor_status,
699178828Sdfr					context_handle,
700178828Sdfr					oid,
701178828Sdfr					&data_set);
702178828Sdfr    if (major_status)
703178828Sdfr	return major_status;
704178828Sdfr
705178828Sdfr    if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
706178828Sdfr	gss_release_buffer_set(minor_status, &data_set);
707178828Sdfr	*minor_status = EINVAL;
708178828Sdfr	return GSS_S_FAILURE;
709178828Sdfr    }
710178828Sdfr
711178828Sdfr    sp = krb5_storage_from_mem(data_set->elements[0].value,
712178828Sdfr			       data_set->elements[0].length);
713178828Sdfr    if (sp == NULL) {
714178828Sdfr	ret = ENOMEM;
715178828Sdfr	goto out;
716178828Sdfr    }
717178828Sdfr
718178828Sdfr    *keyblock = calloc(1, sizeof(**keyblock));
719178828Sdfr    if (keyblock == NULL) {
720178828Sdfr	ret = ENOMEM;
721178828Sdfr	goto out;
722178828Sdfr    }
723178828Sdfr
724178828Sdfr    ret = krb5_ret_keyblock(sp, *keyblock);
725178828Sdfr
726178828Sdfrout:
727178828Sdfr    gss_release_buffer_set(minor_status, &data_set);
728178828Sdfr    if (sp)
729178828Sdfr	krb5_storage_free(sp);
730178828Sdfr    if (ret && keyblock) {
731178828Sdfr	krb5_free_keyblock(context, *keyblock);
732178828Sdfr	*keyblock = NULL;
733178828Sdfr    }
734178828Sdfr    if (context)
735178828Sdfr	krb5_free_context(context);
736178828Sdfr
737178828Sdfr    *minor_status = ret;
738178828Sdfr    if (ret)
739178828Sdfr	return GSS_S_FAILURE;
740178828Sdfr
741178828Sdfr    return GSS_S_COMPLETE;
742178828Sdfr}
743178828Sdfr
744178828Sdfr/*
745178828Sdfr *
746178828Sdfr */
747178828Sdfr
748178828SdfrOM_uint32
749178828Sdfrgsskrb5_extract_service_keyblock(OM_uint32 *minor_status,
750178828Sdfr				 gss_ctx_id_t context_handle,
751178828Sdfr				 krb5_keyblock **keyblock)
752178828Sdfr{
753178828Sdfr    return gsskrb5_extract_key(minor_status,
754178828Sdfr			       context_handle,
755178828Sdfr			       GSS_KRB5_GET_SERVICE_KEYBLOCK_X,
756178828Sdfr			       keyblock);
757178828Sdfr}
758178828Sdfr
759178828SdfrOM_uint32
760178828Sdfrgsskrb5_get_initiator_subkey(OM_uint32 *minor_status,
761178828Sdfr			     gss_ctx_id_t context_handle,
762178828Sdfr			     krb5_keyblock **keyblock)
763178828Sdfr{
764178828Sdfr    return gsskrb5_extract_key(minor_status,
765178828Sdfr			       context_handle,
766178828Sdfr			       GSS_KRB5_GET_INITIATOR_SUBKEY_X,
767178828Sdfr			       keyblock);
768178828Sdfr}
769178828Sdfr
770178828SdfrOM_uint32
771178828Sdfrgsskrb5_get_subkey(OM_uint32 *minor_status,
772178828Sdfr		   gss_ctx_id_t context_handle,
773178828Sdfr		   krb5_keyblock **keyblock)
774178828Sdfr{
775178828Sdfr    return gsskrb5_extract_key(minor_status,
776178828Sdfr			       context_handle,
777178828Sdfr			       GSS_KRB5_GET_SUBKEY_X,
778178828Sdfr			       keyblock);
779178828Sdfr}
780178828Sdfr
781178828SdfrOM_uint32
782178828Sdfrgsskrb5_set_default_realm(const char *realm)
783178828Sdfr{
784178828Sdfr	gss_buffer_desc buffer;
785178828Sdfr	OM_uint32 junk;
786178828Sdfr
787178828Sdfr	buffer.value = rk_UNCONST(realm);
788178828Sdfr	buffer.length = strlen(realm);
789178828Sdfr
790178828Sdfr	gss_set_sec_context_option(&junk, NULL,
791178828Sdfr	    GSS_KRB5_SET_DEFAULT_REALM_X, &buffer);
792178828Sdfr
793178828Sdfr	return (GSS_S_COMPLETE);
794178828Sdfr}
795178828Sdfr
796178828SdfrOM_uint32
797178828Sdfrgss_krb5_get_tkt_flags(OM_uint32 *minor_status,
798178828Sdfr		       gss_ctx_id_t context_handle,
799178828Sdfr		       OM_uint32 *tkt_flags)
800178828Sdfr{
801178828Sdfr
802178828Sdfr    OM_uint32 major_status;
803178828Sdfr    gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
804178828Sdfr
805178828Sdfr    if (context_handle == GSS_C_NO_CONTEXT) {
806178828Sdfr	*minor_status = EINVAL;
807178828Sdfr	return GSS_S_FAILURE;
808178828Sdfr    }
809178828Sdfr
810178828Sdfr    major_status =
811178828Sdfr	gss_inquire_sec_context_by_oid (minor_status,
812178828Sdfr					context_handle,
813178828Sdfr					GSS_KRB5_GET_TKT_FLAGS_X,
814178828Sdfr					&data_set);
815178828Sdfr    if (major_status)
816178828Sdfr	return major_status;
817178828Sdfr
818178828Sdfr    if (data_set == GSS_C_NO_BUFFER_SET ||
819178828Sdfr	data_set->count != 1 ||
820178828Sdfr	data_set->elements[0].length < 4) {
821178828Sdfr	gss_release_buffer_set(minor_status, &data_set);
822178828Sdfr	*minor_status = EINVAL;
823178828Sdfr	return GSS_S_FAILURE;
824178828Sdfr    }
825178828Sdfr
826178828Sdfr    {
827178828Sdfr	const u_char *p = data_set->elements[0].value;
828178828Sdfr	*tkt_flags = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
829178828Sdfr    }
830178828Sdfr
831178828Sdfr    gss_release_buffer_set(minor_status, &data_set);
832178828Sdfr    return GSS_S_COMPLETE;
833178828Sdfr}
834178828Sdfr
835