1178825Sdfr/*
2233294Sstas * Copyright (c) 1999 - 2003 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34233294Sstas#include "gsskrb5_locl.h"
35178825Sdfr
36233294SstasOM_uint32 GSSAPI_CALLCONV
37178825Sdfr_gsskrb5_export_sec_context (
38178825Sdfr    OM_uint32 * minor_status,
39178825Sdfr    gss_ctx_id_t * context_handle,
40178825Sdfr    gss_buffer_t interprocess_token
41178825Sdfr    )
42178825Sdfr{
43178825Sdfr    krb5_context context;
44178825Sdfr    const gsskrb5_ctx ctx = (const gsskrb5_ctx) *context_handle;
45178825Sdfr    krb5_storage *sp;
46178825Sdfr    krb5_auth_context ac;
47178825Sdfr    OM_uint32 ret = GSS_S_COMPLETE;
48178825Sdfr    krb5_data data;
49178825Sdfr    gss_buffer_desc buffer;
50178825Sdfr    int flags;
51178825Sdfr    OM_uint32 minor;
52178825Sdfr    krb5_error_code kret;
53178825Sdfr
54178825Sdfr    GSSAPI_KRB5_INIT (&context);
55178825Sdfr
56178825Sdfr    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
57178825Sdfr
58178825Sdfr    if (!(ctx->flags & GSS_C_TRANS_FLAG)) {
59178825Sdfr	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
60178825Sdfr	*minor_status = 0;
61178825Sdfr	return GSS_S_UNAVAILABLE;
62178825Sdfr    }
63178825Sdfr
64178825Sdfr    sp = krb5_storage_emem ();
65178825Sdfr    if (sp == NULL) {
66178825Sdfr	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
67178825Sdfr	*minor_status = ENOMEM;
68178825Sdfr	return GSS_S_FAILURE;
69178825Sdfr    }
70178825Sdfr    ac = ctx->auth_context;
71178825Sdfr
72178825Sdfr    /* flagging included fields */
73178825Sdfr
74178825Sdfr    flags = 0;
75178825Sdfr    if (ac->local_address)
76178825Sdfr	flags |= SC_LOCAL_ADDRESS;
77178825Sdfr    if (ac->remote_address)
78178825Sdfr	flags |= SC_REMOTE_ADDRESS;
79178825Sdfr    if (ac->keyblock)
80178825Sdfr	flags |= SC_KEYBLOCK;
81178825Sdfr    if (ac->local_subkey)
82178825Sdfr	flags |= SC_LOCAL_SUBKEY;
83178825Sdfr    if (ac->remote_subkey)
84178825Sdfr	flags |= SC_REMOTE_SUBKEY;
85178825Sdfr
86178825Sdfr    kret = krb5_store_int32 (sp, flags);
87178825Sdfr    if (kret) {
88178825Sdfr	*minor_status = kret;
89178825Sdfr	goto failure;
90178825Sdfr    }
91178825Sdfr
92178825Sdfr    /* marshall auth context */
93178825Sdfr
94178825Sdfr    kret = krb5_store_int32 (sp, ac->flags);
95178825Sdfr    if (kret) {
96178825Sdfr	*minor_status = kret;
97178825Sdfr	goto failure;
98178825Sdfr    }
99178825Sdfr    if (ac->local_address) {
100178825Sdfr	kret = krb5_store_address (sp, *ac->local_address);
101178825Sdfr	if (kret) {
102178825Sdfr	    *minor_status = kret;
103178825Sdfr	    goto failure;
104178825Sdfr	}
105178825Sdfr    }
106178825Sdfr    if (ac->remote_address) {
107178825Sdfr	kret = krb5_store_address (sp, *ac->remote_address);
108178825Sdfr	if (kret) {
109178825Sdfr	    *minor_status = kret;
110178825Sdfr	    goto failure;
111178825Sdfr	}
112178825Sdfr    }
113178825Sdfr    kret = krb5_store_int16 (sp, ac->local_port);
114178825Sdfr    if (kret) {
115178825Sdfr	*minor_status = kret;
116178825Sdfr	goto failure;
117178825Sdfr    }
118178825Sdfr    kret = krb5_store_int16 (sp, ac->remote_port);
119178825Sdfr    if (kret) {
120178825Sdfr	*minor_status = kret;
121178825Sdfr	goto failure;
122178825Sdfr    }
123178825Sdfr    if (ac->keyblock) {
124178825Sdfr	kret = krb5_store_keyblock (sp, *ac->keyblock);
125178825Sdfr	if (kret) {
126178825Sdfr	    *minor_status = kret;
127178825Sdfr	    goto failure;
128178825Sdfr	}
129178825Sdfr    }
130178825Sdfr    if (ac->local_subkey) {
131178825Sdfr	kret = krb5_store_keyblock (sp, *ac->local_subkey);
132178825Sdfr	if (kret) {
133178825Sdfr	    *minor_status = kret;
134178825Sdfr	    goto failure;
135178825Sdfr	}
136178825Sdfr    }
137178825Sdfr    if (ac->remote_subkey) {
138178825Sdfr	kret = krb5_store_keyblock (sp, *ac->remote_subkey);
139178825Sdfr	if (kret) {
140178825Sdfr	    *minor_status = kret;
141178825Sdfr	    goto failure;
142178825Sdfr	}
143178825Sdfr    }
144178825Sdfr    kret = krb5_store_int32 (sp, ac->local_seqnumber);
145178825Sdfr	if (kret) {
146178825Sdfr	    *minor_status = kret;
147178825Sdfr	    goto failure;
148178825Sdfr	}
149178825Sdfr    kret = krb5_store_int32 (sp, ac->remote_seqnumber);
150178825Sdfr	if (kret) {
151178825Sdfr	    *minor_status = kret;
152178825Sdfr	    goto failure;
153178825Sdfr	}
154178825Sdfr
155178825Sdfr    kret = krb5_store_int32 (sp, ac->keytype);
156178825Sdfr    if (kret) {
157178825Sdfr	*minor_status = kret;
158178825Sdfr	goto failure;
159178825Sdfr    }
160178825Sdfr    kret = krb5_store_int32 (sp, ac->cksumtype);
161178825Sdfr    if (kret) {
162178825Sdfr	*minor_status = kret;
163178825Sdfr	goto failure;
164178825Sdfr    }
165178825Sdfr
166178825Sdfr    /* names */
167178825Sdfr
168178825Sdfr    ret = _gsskrb5_export_name (minor_status,
169178825Sdfr				(gss_name_t)ctx->source, &buffer);
170178825Sdfr    if (ret)
171178825Sdfr	goto failure;
172178825Sdfr    data.data   = buffer.value;
173178825Sdfr    data.length = buffer.length;
174178825Sdfr    kret = krb5_store_data (sp, data);
175178825Sdfr    _gsskrb5_release_buffer (&minor, &buffer);
176178825Sdfr    if (kret) {
177178825Sdfr	*minor_status = kret;
178178825Sdfr	goto failure;
179178825Sdfr    }
180178825Sdfr
181178825Sdfr    ret = _gsskrb5_export_name (minor_status,
182178825Sdfr				(gss_name_t)ctx->target, &buffer);
183178825Sdfr    if (ret)
184178825Sdfr	goto failure;
185178825Sdfr    data.data   = buffer.value;
186178825Sdfr    data.length = buffer.length;
187178825Sdfr
188178825Sdfr    ret = GSS_S_FAILURE;
189178825Sdfr
190178825Sdfr    kret = krb5_store_data (sp, data);
191178825Sdfr    _gsskrb5_release_buffer (&minor, &buffer);
192178825Sdfr    if (kret) {
193178825Sdfr	*minor_status = kret;
194178825Sdfr	goto failure;
195178825Sdfr    }
196178825Sdfr
197178825Sdfr    kret = krb5_store_int32 (sp, ctx->flags);
198178825Sdfr    if (kret) {
199178825Sdfr	*minor_status = kret;
200178825Sdfr	goto failure;
201178825Sdfr    }
202178825Sdfr    kret = krb5_store_int32 (sp, ctx->more_flags);
203178825Sdfr    if (kret) {
204178825Sdfr	*minor_status = kret;
205178825Sdfr	goto failure;
206178825Sdfr    }
207178825Sdfr    kret = krb5_store_int32 (sp, ctx->lifetime);
208178825Sdfr    if (kret) {
209178825Sdfr	*minor_status = kret;
210178825Sdfr	goto failure;
211178825Sdfr    }
212178825Sdfr    kret = _gssapi_msg_order_export(sp, ctx->order);
213178825Sdfr    if (kret ) {
214178825Sdfr        *minor_status = kret;
215178825Sdfr        goto failure;
216178825Sdfr    }
217178825Sdfr
218178825Sdfr    kret = krb5_storage_to_data (sp, &data);
219178825Sdfr    krb5_storage_free (sp);
220178825Sdfr    if (kret) {
221178825Sdfr	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
222178825Sdfr	*minor_status = kret;
223178825Sdfr	return GSS_S_FAILURE;
224178825Sdfr    }
225178825Sdfr    interprocess_token->length = data.length;
226178825Sdfr    interprocess_token->value  = data.data;
227178825Sdfr    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
228178825Sdfr    ret = _gsskrb5_delete_sec_context (minor_status, context_handle,
229178825Sdfr				       GSS_C_NO_BUFFER);
230178825Sdfr    if (ret != GSS_S_COMPLETE)
231178825Sdfr	_gsskrb5_release_buffer (NULL, interprocess_token);
232178825Sdfr    *minor_status = 0;
233178825Sdfr    return ret;
234178825Sdfr failure:
235178825Sdfr    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
236178825Sdfr    krb5_storage_free (sp);
237178825Sdfr    return ret;
238178825Sdfr}
239