1178825Sdfr/*
2178825Sdfr * Copyright (c) 2004, PADL Software Pty Ltd.
3178825Sdfr * All rights reserved.
4178825Sdfr *
5178825Sdfr * Redistribution and use in source and binary forms, with or without
6178825Sdfr * modification, are permitted provided that the following conditions
7178825Sdfr * are met:
8178825Sdfr *
9178825Sdfr * 1. Redistributions of source code must retain the above copyright
10178825Sdfr *    notice, this list of conditions and the following disclaimer.
11178825Sdfr *
12178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
13178825Sdfr *    notice, this list of conditions and the following disclaimer in the
14178825Sdfr *    documentation and/or other materials provided with the distribution.
15178825Sdfr *
16178825Sdfr * 3. Neither the name of PADL Software nor the names of its contributors
17178825Sdfr *    may be used to endorse or promote products derived from this software
18178825Sdfr *    without specific prior written permission.
19178825Sdfr *
20178825Sdfr * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
24178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30178825Sdfr * SUCH DAMAGE.
31178825Sdfr */
32178825Sdfr
33233294Sstas#include "gsskrb5_locl.h"
34178825Sdfr
35178825Sdfrstatic int
36178825Sdfroid_prefix_equal(gss_OID oid_enc, gss_OID prefix_enc, unsigned *suffix)
37178825Sdfr{
38178825Sdfr    int ret;
39178825Sdfr    heim_oid oid;
40178825Sdfr    heim_oid prefix;
41233294Sstas
42178825Sdfr    *suffix = 0;
43178825Sdfr
44178825Sdfr    ret = der_get_oid(oid_enc->elements, oid_enc->length,
45178825Sdfr		      &oid, NULL);
46178825Sdfr    if (ret) {
47178825Sdfr	return 0;
48178825Sdfr    }
49178825Sdfr
50178825Sdfr    ret = der_get_oid(prefix_enc->elements, prefix_enc->length,
51178825Sdfr		      &prefix, NULL);
52178825Sdfr    if (ret) {
53178825Sdfr	der_free_oid(&oid);
54178825Sdfr	return 0;
55178825Sdfr    }
56178825Sdfr
57178825Sdfr    ret = 0;
58178825Sdfr
59178825Sdfr    if (oid.length - 1 == prefix.length) {
60178825Sdfr	*suffix = oid.components[oid.length - 1];
61178825Sdfr	oid.length--;
62178825Sdfr	ret = (der_heim_oid_cmp(&oid, &prefix) == 0);
63178825Sdfr	oid.length++;
64178825Sdfr    }
65178825Sdfr
66178825Sdfr    der_free_oid(&oid);
67178825Sdfr    der_free_oid(&prefix);
68178825Sdfr
69178825Sdfr    return ret;
70178825Sdfr}
71178825Sdfr
72178825Sdfrstatic OM_uint32 inquire_sec_context_tkt_flags
73178825Sdfr           (OM_uint32 *minor_status,
74178825Sdfr            const gsskrb5_ctx context_handle,
75178825Sdfr            gss_buffer_set_t *data_set)
76178825Sdfr{
77178825Sdfr    OM_uint32 tkt_flags;
78178825Sdfr    unsigned char buf[4];
79178825Sdfr    gss_buffer_desc value;
80178825Sdfr
81178825Sdfr    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
82178825Sdfr
83178825Sdfr    if (context_handle->ticket == NULL) {
84178825Sdfr	HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
85233294Sstas	_gsskrb5_set_status(EINVAL, "No ticket from which to obtain flags");
86178825Sdfr	*minor_status = EINVAL;
87178825Sdfr	return GSS_S_BAD_MECH;
88178825Sdfr    }
89178825Sdfr
90178825Sdfr    tkt_flags = TicketFlags2int(context_handle->ticket->ticket.flags);
91178825Sdfr    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
92178825Sdfr
93178825Sdfr    _gsskrb5_encode_om_uint32(tkt_flags, buf);
94178825Sdfr    value.length = sizeof(buf);
95178825Sdfr    value.value = buf;
96178825Sdfr
97178825Sdfr    return gss_add_buffer_set_member(minor_status,
98178825Sdfr				     &value,
99178825Sdfr				     data_set);
100178825Sdfr}
101178825Sdfr
102178825Sdfrenum keytype { ACCEPTOR_KEY, INITIATOR_KEY, TOKEN_KEY };
103178825Sdfr
104178825Sdfrstatic OM_uint32 inquire_sec_context_get_subkey
105178825Sdfr           (OM_uint32 *minor_status,
106178825Sdfr            const gsskrb5_ctx context_handle,
107178825Sdfr	    krb5_context context,
108178825Sdfr	    enum keytype keytype,
109178825Sdfr            gss_buffer_set_t *data_set)
110178825Sdfr{
111178825Sdfr    krb5_keyblock *key = NULL;
112178825Sdfr    krb5_storage *sp = NULL;
113178825Sdfr    krb5_data data;
114178825Sdfr    OM_uint32 maj_stat = GSS_S_COMPLETE;
115178825Sdfr    krb5_error_code ret;
116178825Sdfr
117178825Sdfr    krb5_data_zero(&data);
118178825Sdfr
119178825Sdfr    sp = krb5_storage_emem();
120178825Sdfr    if (sp == NULL) {
121178825Sdfr	_gsskrb5_clear_status();
122178825Sdfr	ret = ENOMEM;
123178825Sdfr	goto out;
124178825Sdfr    }
125178825Sdfr
126178825Sdfr    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
127178825Sdfr    switch(keytype) {
128178825Sdfr    case ACCEPTOR_KEY:
129178825Sdfr	ret = _gsskrb5i_get_acceptor_subkey(context_handle, context, &key);
130178825Sdfr	break;
131178825Sdfr    case INITIATOR_KEY:
132178825Sdfr	ret = _gsskrb5i_get_initiator_subkey(context_handle, context, &key);
133178825Sdfr	break;
134178825Sdfr    case TOKEN_KEY:
135178825Sdfr	ret = _gsskrb5i_get_token_key(context_handle, context, &key);
136178825Sdfr	break;
137178825Sdfr    default:
138233294Sstas	_gsskrb5_set_status(EINVAL, "%d is not a valid subkey type", keytype);
139178825Sdfr	ret = EINVAL;
140178825Sdfr	break;
141178825Sdfr   }
142178825Sdfr    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
143233294Sstas    if (ret)
144178825Sdfr	goto out;
145178825Sdfr    if (key == NULL) {
146233294Sstas	_gsskrb5_set_status(EINVAL, "have no subkey of type %d", keytype);
147178825Sdfr	ret = EINVAL;
148178825Sdfr	goto out;
149178825Sdfr    }
150178825Sdfr
151178825Sdfr    ret = krb5_store_keyblock(sp, *key);
152178825Sdfr    krb5_free_keyblock (context, key);
153178825Sdfr    if (ret)
154178825Sdfr	goto out;
155178825Sdfr
156178825Sdfr    ret = krb5_storage_to_data(sp, &data);
157178825Sdfr    if (ret)
158178825Sdfr	goto out;
159178825Sdfr
160178825Sdfr    {
161178825Sdfr	gss_buffer_desc value;
162233294Sstas
163178825Sdfr	value.length = data.length;
164178825Sdfr	value.value = data.data;
165233294Sstas
166178825Sdfr	maj_stat = gss_add_buffer_set_member(minor_status,
167178825Sdfr					     &value,
168178825Sdfr					     data_set);
169178825Sdfr    }
170178825Sdfr
171178825Sdfrout:
172178825Sdfr    krb5_data_free(&data);
173178825Sdfr    if (sp)
174178825Sdfr	krb5_storage_free(sp);
175178825Sdfr    if (ret) {
176178825Sdfr	*minor_status = ret;
177178825Sdfr	maj_stat = GSS_S_FAILURE;
178178825Sdfr    }
179178825Sdfr    return maj_stat;
180178825Sdfr}
181178825Sdfr
182233294Sstasstatic OM_uint32 inquire_sec_context_get_sspi_session_key
183233294Sstas            (OM_uint32 *minor_status,
184233294Sstas             const gsskrb5_ctx context_handle,
185233294Sstas             krb5_context context,
186233294Sstas             gss_buffer_set_t *data_set)
187233294Sstas{
188233294Sstas    krb5_keyblock *key;
189233294Sstas    OM_uint32 maj_stat = GSS_S_COMPLETE;
190233294Sstas    krb5_error_code ret;
191233294Sstas    gss_buffer_desc value;
192233294Sstas
193233294Sstas    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
194233294Sstas    ret = _gsskrb5i_get_token_key(context_handle, context, &key);
195233294Sstas    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
196233294Sstas
197233294Sstas    if (ret)
198233294Sstas        goto out;
199233294Sstas    if (key == NULL) {
200233294Sstas        ret = EINVAL;
201233294Sstas        goto out;
202233294Sstas    }
203233294Sstas
204233294Sstas    value.length = key->keyvalue.length;
205233294Sstas    value.value = key->keyvalue.data;
206233294Sstas
207233294Sstas    maj_stat = gss_add_buffer_set_member(minor_status,
208233294Sstas                                         &value,
209233294Sstas                                         data_set);
210233294Sstas    krb5_free_keyblock(context, key);
211233294Sstas
212233294Sstas    /* MIT also returns the enctype encoded as an OID in data_set[1] */
213233294Sstas
214233294Sstasout:
215233294Sstas    if (ret) {
216233294Sstas        *minor_status = ret;
217233294Sstas        maj_stat = GSS_S_FAILURE;
218233294Sstas    }
219233294Sstas    return maj_stat;
220233294Sstas}
221233294Sstas
222178825Sdfrstatic OM_uint32 inquire_sec_context_authz_data
223178825Sdfr           (OM_uint32 *minor_status,
224178825Sdfr            const gsskrb5_ctx context_handle,
225178825Sdfr	    krb5_context context,
226178825Sdfr            unsigned ad_type,
227178825Sdfr            gss_buffer_set_t *data_set)
228178825Sdfr{
229178825Sdfr    krb5_data data;
230178825Sdfr    gss_buffer_desc ad_data;
231178825Sdfr    OM_uint32 ret;
232178825Sdfr
233178825Sdfr    *minor_status = 0;
234178825Sdfr    *data_set = GSS_C_NO_BUFFER_SET;
235178825Sdfr
236178825Sdfr    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
237178825Sdfr    if (context_handle->ticket == NULL) {
238178825Sdfr	HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
239178825Sdfr	*minor_status = EINVAL;
240233294Sstas	_gsskrb5_set_status(EINVAL, "No ticket to obtain authz data from");
241178825Sdfr	return GSS_S_NO_CONTEXT;
242178825Sdfr    }
243178825Sdfr
244178825Sdfr    ret = krb5_ticket_get_authorization_data_type(context,
245178825Sdfr						  context_handle->ticket,
246178825Sdfr						  ad_type,
247178825Sdfr						  &data);
248178825Sdfr    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
249178825Sdfr    if (ret) {
250178825Sdfr	*minor_status = ret;
251178825Sdfr	return GSS_S_FAILURE;
252178825Sdfr    }
253178825Sdfr
254178825Sdfr    ad_data.value = data.data;
255178825Sdfr    ad_data.length = data.length;
256178825Sdfr
257178825Sdfr    ret = gss_add_buffer_set_member(minor_status,
258178825Sdfr				    &ad_data,
259178825Sdfr				    data_set);
260178825Sdfr
261178825Sdfr    krb5_data_free(&data);
262178825Sdfr
263178825Sdfr    return ret;
264178825Sdfr}
265178825Sdfr
266178825Sdfrstatic OM_uint32 inquire_sec_context_has_updated_spnego
267178825Sdfr           (OM_uint32 *minor_status,
268178825Sdfr            const gsskrb5_ctx context_handle,
269178825Sdfr            gss_buffer_set_t *data_set)
270178825Sdfr{
271178825Sdfr    int is_updated = 0;
272178825Sdfr
273178825Sdfr    *minor_status = 0;
274178825Sdfr    *data_set = GSS_C_NO_BUFFER_SET;
275178825Sdfr
276178825Sdfr    /*
277178825Sdfr     * For Windows SPNEGO implementations, both the initiator and the
278178825Sdfr     * acceptor are assumed to have been updated if a "newer" [CLAR] or
279178825Sdfr     * different enctype is negotiated for use by the Kerberos GSS-API
280178825Sdfr     * mechanism.
281178825Sdfr     */
282178825Sdfr    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
283233294Sstas    is_updated = (context_handle->more_flags & IS_CFX);
284178825Sdfr    if (is_updated == 0) {
285178825Sdfr	krb5_keyblock *acceptor_subkey;
286178825Sdfr
287178825Sdfr	if (context_handle->more_flags & LOCAL)
288178825Sdfr	    acceptor_subkey = context_handle->auth_context->remote_subkey;
289178825Sdfr	else
290178825Sdfr	    acceptor_subkey = context_handle->auth_context->local_subkey;
291178825Sdfr
292178825Sdfr	if (acceptor_subkey != NULL)
293178825Sdfr	    is_updated = (acceptor_subkey->keytype !=
294178825Sdfr			  context_handle->auth_context->keyblock->keytype);
295178825Sdfr    }
296178825Sdfr    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
297178825Sdfr
298178825Sdfr    return is_updated ? GSS_S_COMPLETE : GSS_S_FAILURE;
299178825Sdfr}
300178825Sdfr
301178825Sdfr/*
302178825Sdfr *
303178825Sdfr */
304178825Sdfr
305178825Sdfrstatic OM_uint32
306178825Sdfrexport_lucid_sec_context_v1(OM_uint32 *minor_status,
307178825Sdfr			    gsskrb5_ctx context_handle,
308178825Sdfr			    krb5_context context,
309178825Sdfr			    gss_buffer_set_t *data_set)
310178825Sdfr{
311178825Sdfr    krb5_storage *sp = NULL;
312178825Sdfr    OM_uint32 major_status = GSS_S_COMPLETE;
313178825Sdfr    krb5_error_code ret;
314178825Sdfr    krb5_keyblock *key = NULL;
315178825Sdfr    int32_t number;
316178825Sdfr    int is_cfx;
317178825Sdfr    krb5_data data;
318233294Sstas
319178825Sdfr    *minor_status = 0;
320178825Sdfr
321178825Sdfr    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
322178825Sdfr
323233294Sstas    is_cfx = (context_handle->more_flags & IS_CFX);
324178825Sdfr
325178825Sdfr    sp = krb5_storage_emem();
326178825Sdfr    if (sp == NULL) {
327178825Sdfr	_gsskrb5_clear_status();
328178825Sdfr	ret = ENOMEM;
329178825Sdfr	goto out;
330178825Sdfr    }
331178825Sdfr
332178825Sdfr    ret = krb5_store_int32(sp, 1);
333178825Sdfr    if (ret) goto out;
334178825Sdfr    ret = krb5_store_int32(sp, (context_handle->more_flags & LOCAL) ? 1 : 0);
335178825Sdfr    if (ret) goto out;
336178825Sdfr    ret = krb5_store_int32(sp, context_handle->lifetime);
337178825Sdfr    if (ret) goto out;
338178825Sdfr    krb5_auth_con_getlocalseqnumber (context,
339178825Sdfr				     context_handle->auth_context,
340178825Sdfr				     &number);
341178825Sdfr    ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */
342233294Sstas    if (ret) goto out;
343178825Sdfr    ret = krb5_store_uint32(sp, (uint32_t)number);
344233294Sstas    if (ret) goto out;
345233294Sstas    krb5_auth_con_getremoteseqnumber (context,
346233294Sstas				      context_handle->auth_context,
347233294Sstas				      &number);
348178825Sdfr    ret = krb5_store_uint32(sp, (uint32_t)0); /* store top half as zero */
349233294Sstas    if (ret) goto out;
350178825Sdfr    ret = krb5_store_uint32(sp, (uint32_t)number);
351233294Sstas    if (ret) goto out;
352178825Sdfr    ret = krb5_store_int32(sp, (is_cfx) ? 1 : 0);
353178825Sdfr    if (ret) goto out;
354178825Sdfr
355178825Sdfr    ret = _gsskrb5i_get_token_key(context_handle, context, &key);
356178825Sdfr    if (ret) goto out;
357178825Sdfr
358178825Sdfr    if (is_cfx == 0) {
359178825Sdfr	int sign_alg, seal_alg;
360178825Sdfr
361178825Sdfr	switch (key->keytype) {
362178825Sdfr	case ETYPE_DES_CBC_CRC:
363178825Sdfr	case ETYPE_DES_CBC_MD4:
364178825Sdfr	case ETYPE_DES_CBC_MD5:
365178825Sdfr	    sign_alg = 0;
366178825Sdfr	    seal_alg = 0;
367178825Sdfr	    break;
368178825Sdfr	case ETYPE_DES3_CBC_MD5:
369178825Sdfr	case ETYPE_DES3_CBC_SHA1:
370178825Sdfr	    sign_alg = 4;
371178825Sdfr	    seal_alg = 2;
372178825Sdfr	    break;
373178825Sdfr	case ETYPE_ARCFOUR_HMAC_MD5:
374178825Sdfr	case ETYPE_ARCFOUR_HMAC_MD5_56:
375178825Sdfr	    sign_alg = 17;
376178825Sdfr	    seal_alg = 16;
377178825Sdfr	    break;
378178825Sdfr	default:
379178825Sdfr	    sign_alg = -1;
380178825Sdfr	    seal_alg = -1;
381178825Sdfr	    break;
382178825Sdfr	}
383178825Sdfr	ret = krb5_store_int32(sp, sign_alg);
384178825Sdfr	if (ret) goto out;
385178825Sdfr	ret = krb5_store_int32(sp, seal_alg);
386178825Sdfr	if (ret) goto out;
387178825Sdfr	/* ctx_key */
388178825Sdfr	ret = krb5_store_keyblock(sp, *key);
389178825Sdfr	if (ret) goto out;
390178825Sdfr    } else {
391178825Sdfr	int subkey_p = (context_handle->more_flags & ACCEPTOR_SUBKEY) ? 1 : 0;
392178825Sdfr
393178825Sdfr	/* have_acceptor_subkey */
394178825Sdfr	ret = krb5_store_int32(sp, subkey_p);
395178825Sdfr	if (ret) goto out;
396178825Sdfr	/* ctx_key */
397178825Sdfr	ret = krb5_store_keyblock(sp, *key);
398178825Sdfr	if (ret) goto out;
399178825Sdfr	/* acceptor_subkey */
400178825Sdfr	if (subkey_p) {
401178825Sdfr	    ret = krb5_store_keyblock(sp, *key);
402178825Sdfr	    if (ret) goto out;
403178825Sdfr	}
404178825Sdfr    }
405178825Sdfr    ret = krb5_storage_to_data(sp, &data);
406178825Sdfr    if (ret) goto out;
407178825Sdfr
408178825Sdfr    {
409178825Sdfr	gss_buffer_desc ad_data;
410178825Sdfr
411178825Sdfr	ad_data.value = data.data;
412178825Sdfr	ad_data.length = data.length;
413178825Sdfr
414178825Sdfr	ret = gss_add_buffer_set_member(minor_status, &ad_data, data_set);
415178825Sdfr	krb5_data_free(&data);
416178825Sdfr	if (ret)
417178825Sdfr	    goto out;
418178825Sdfr    }
419178825Sdfr
420178825Sdfrout:
421178825Sdfr    if (key)
422178825Sdfr	krb5_free_keyblock (context, key);
423178825Sdfr    if (sp)
424178825Sdfr	krb5_storage_free(sp);
425178825Sdfr    if (ret) {
426178825Sdfr	*minor_status = ret;
427178825Sdfr	major_status = GSS_S_FAILURE;
428178825Sdfr    }
429178825Sdfr    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
430178825Sdfr    return major_status;
431178825Sdfr}
432178825Sdfr
433178825Sdfrstatic OM_uint32
434178825Sdfrget_authtime(OM_uint32 *minor_status,
435233294Sstas	     gsskrb5_ctx ctx,
436178825Sdfr	     gss_buffer_set_t *data_set)
437178825Sdfr
438178825Sdfr{
439178825Sdfr    gss_buffer_desc value;
440178825Sdfr    unsigned char buf[4];
441178825Sdfr    OM_uint32 authtime;
442178825Sdfr
443178825Sdfr    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
444178825Sdfr    if (ctx->ticket == NULL) {
445178825Sdfr	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
446233294Sstas	_gsskrb5_set_status(EINVAL, "No ticket to obtain auth time from");
447178825Sdfr	*minor_status = EINVAL;
448178825Sdfr	return GSS_S_FAILURE;
449178825Sdfr    }
450233294Sstas
451178825Sdfr    authtime = ctx->ticket->ticket.authtime;
452233294Sstas
453178825Sdfr    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
454178825Sdfr
455178825Sdfr    _gsskrb5_encode_om_uint32(authtime, buf);
456178825Sdfr    value.length = sizeof(buf);
457178825Sdfr    value.value = buf;
458178825Sdfr
459178825Sdfr    return gss_add_buffer_set_member(minor_status,
460178825Sdfr				     &value,
461178825Sdfr				     data_set);
462178825Sdfr}
463178825Sdfr
464178825Sdfr
465233294Sstasstatic OM_uint32
466178825Sdfrget_service_keyblock
467178825Sdfr        (OM_uint32 *minor_status,
468233294Sstas	 gsskrb5_ctx ctx,
469178825Sdfr	 gss_buffer_set_t *data_set)
470178825Sdfr{
471178825Sdfr    krb5_storage *sp = NULL;
472178825Sdfr    krb5_data data;
473178825Sdfr    OM_uint32 maj_stat = GSS_S_COMPLETE;
474178825Sdfr    krb5_error_code ret = EINVAL;
475233294Sstas
476178825Sdfr    sp = krb5_storage_emem();
477178825Sdfr    if (sp == NULL) {
478178825Sdfr	_gsskrb5_clear_status();
479178825Sdfr	*minor_status = ENOMEM;
480178825Sdfr	return GSS_S_FAILURE;
481178825Sdfr    }
482178825Sdfr
483178825Sdfr    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
484178825Sdfr    if (ctx->service_keyblock == NULL) {
485178825Sdfr	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
486233294Sstas	krb5_storage_free(sp);
487233294Sstas	_gsskrb5_set_status(EINVAL, "No service keyblock on gssapi context");
488178825Sdfr	*minor_status = EINVAL;
489233294Sstas	return GSS_S_FAILURE;
490178825Sdfr    }
491178825Sdfr
492178825Sdfr    krb5_data_zero(&data);
493178825Sdfr
494178825Sdfr    ret = krb5_store_keyblock(sp, *ctx->service_keyblock);
495178825Sdfr
496178825Sdfr    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
497178825Sdfr
498178825Sdfr    if (ret)
499178825Sdfr	goto out;
500178825Sdfr
501178825Sdfr    ret = krb5_storage_to_data(sp, &data);
502178825Sdfr    if (ret)
503178825Sdfr	goto out;
504178825Sdfr
505178825Sdfr    {
506178825Sdfr	gss_buffer_desc value;
507233294Sstas
508178825Sdfr	value.length = data.length;
509178825Sdfr	value.value = data.data;
510233294Sstas
511178825Sdfr	maj_stat = gss_add_buffer_set_member(minor_status,
512178825Sdfr					     &value,
513178825Sdfr					     data_set);
514178825Sdfr    }
515178825Sdfr
516178825Sdfrout:
517178825Sdfr    krb5_data_free(&data);
518178825Sdfr    if (sp)
519178825Sdfr	krb5_storage_free(sp);
520178825Sdfr    if (ret) {
521178825Sdfr	*minor_status = ret;
522178825Sdfr	maj_stat = GSS_S_FAILURE;
523178825Sdfr    }
524178825Sdfr    return maj_stat;
525178825Sdfr}
526178825Sdfr/*
527178825Sdfr *
528178825Sdfr */
529178825Sdfr
530233294SstasOM_uint32 GSSAPI_CALLCONV _gsskrb5_inquire_sec_context_by_oid
531178825Sdfr           (OM_uint32 *minor_status,
532178825Sdfr            const gss_ctx_id_t context_handle,
533178825Sdfr            const gss_OID desired_object,
534178825Sdfr            gss_buffer_set_t *data_set)
535178825Sdfr{
536178825Sdfr    krb5_context context;
537178825Sdfr    const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
538178825Sdfr    unsigned suffix;
539178825Sdfr
540178825Sdfr    if (ctx == NULL) {
541178825Sdfr	*minor_status = EINVAL;
542178825Sdfr	return GSS_S_NO_CONTEXT;
543178825Sdfr    }
544178825Sdfr
545178825Sdfr    GSSAPI_KRB5_INIT (&context);
546178825Sdfr
547178825Sdfr    if (gss_oid_equal(desired_object, GSS_KRB5_GET_TKT_FLAGS_X)) {
548178825Sdfr	return inquire_sec_context_tkt_flags(minor_status,
549178825Sdfr					     ctx,
550178825Sdfr					     data_set);
551178825Sdfr    } else if (gss_oid_equal(desired_object, GSS_C_PEER_HAS_UPDATED_SPNEGO)) {
552178825Sdfr	return inquire_sec_context_has_updated_spnego(minor_status,
553178825Sdfr						      ctx,
554178825Sdfr						      data_set);
555178825Sdfr    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SUBKEY_X)) {
556178825Sdfr	return inquire_sec_context_get_subkey(minor_status,
557178825Sdfr					      ctx,
558178825Sdfr					      context,
559178825Sdfr					      TOKEN_KEY,
560178825Sdfr					      data_set);
561178825Sdfr    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_INITIATOR_SUBKEY_X)) {
562178825Sdfr	return inquire_sec_context_get_subkey(minor_status,
563178825Sdfr					      ctx,
564178825Sdfr					      context,
565178825Sdfr					      INITIATOR_KEY,
566178825Sdfr					      data_set);
567178825Sdfr    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_ACCEPTOR_SUBKEY_X)) {
568178825Sdfr	return inquire_sec_context_get_subkey(minor_status,
569178825Sdfr					      ctx,
570178825Sdfr					      context,
571178825Sdfr					      ACCEPTOR_KEY,
572178825Sdfr					      data_set);
573233294Sstas    } else if (gss_oid_equal(desired_object, GSS_C_INQ_SSPI_SESSION_KEY)) {
574233294Sstas        return inquire_sec_context_get_sspi_session_key(minor_status,
575233294Sstas                                                        ctx,
576233294Sstas                                                        context,
577233294Sstas                                                        data_set);
578178825Sdfr    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_AUTHTIME_X)) {
579178825Sdfr	return get_authtime(minor_status, ctx, data_set);
580178825Sdfr    } else if (oid_prefix_equal(desired_object,
581178825Sdfr				GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X,
582178825Sdfr				&suffix)) {
583178825Sdfr	return inquire_sec_context_authz_data(minor_status,
584178825Sdfr					      ctx,
585178825Sdfr					      context,
586178825Sdfr					      suffix,
587178825Sdfr					      data_set);
588178825Sdfr    } else if (oid_prefix_equal(desired_object,
589178825Sdfr				GSS_KRB5_EXPORT_LUCID_CONTEXT_X,
590178825Sdfr				&suffix)) {
591178825Sdfr	if (suffix == 1)
592178825Sdfr	    return export_lucid_sec_context_v1(minor_status,
593178825Sdfr					       ctx,
594178825Sdfr					       context,
595178825Sdfr					       data_set);
596178825Sdfr	*minor_status = 0;
597178825Sdfr	return GSS_S_FAILURE;
598178825Sdfr    } else if (gss_oid_equal(desired_object, GSS_KRB5_GET_SERVICE_KEYBLOCK_X)) {
599178825Sdfr	return get_service_keyblock(minor_status, ctx, data_set);
600178825Sdfr    } else {
601178825Sdfr	*minor_status = 0;
602178825Sdfr	return GSS_S_FAILURE;
603178825Sdfr    }
604178825Sdfr}
605178825Sdfr
606