1/*
2 * Copyright (c) 1999 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "gsskrb5_locl.h"
35
36OM_uint32 GSSAPI_CALLCONV
37_gsskrb5_export_sec_context (
38    OM_uint32 * minor_status,
39    gss_ctx_id_t * context_handle,
40    gss_buffer_t interprocess_token
41    )
42{
43    krb5_context context;
44    const gsskrb5_ctx ctx = (const gsskrb5_ctx) *context_handle;
45    krb5_storage *sp;
46    krb5_auth_context ac;
47    OM_uint32 ret = GSS_S_COMPLETE;
48    krb5_data data;
49    gss_buffer_desc buffer;
50    int flags;
51    OM_uint32 minor;
52    krb5_error_code kret;
53
54    GSSAPI_KRB5_INIT (&context);
55
56    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
57
58    if (!(ctx->flags & GSS_C_TRANS_FLAG)) {
59	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
60	*minor_status = 0;
61	return GSS_S_UNAVAILABLE;
62    }
63
64    sp = krb5_storage_emem ();
65    if (sp == NULL) {
66	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
67	*minor_status = ENOMEM;
68	return GSS_S_FAILURE;
69    }
70    ac = ctx->auth_context;
71
72    /* flagging included fields */
73
74    flags = 0;
75    if (ac->local_address)
76	flags |= SC_LOCAL_ADDRESS;
77    if (ac->remote_address)
78	flags |= SC_REMOTE_ADDRESS;
79    if (ac->keyblock)
80	flags |= SC_KEYBLOCK;
81    if (ac->local_subkey)
82	flags |= SC_LOCAL_SUBKEY;
83    if (ac->remote_subkey)
84	flags |= SC_REMOTE_SUBKEY;
85
86    kret = krb5_store_int32 (sp, flags);
87    if (kret) {
88	*minor_status = kret;
89	goto failure;
90    }
91
92    /* marshall auth context */
93
94    kret = krb5_store_int32 (sp, ac->flags);
95    if (kret) {
96	*minor_status = kret;
97	goto failure;
98    }
99    if (ac->local_address) {
100	kret = krb5_store_address (sp, *ac->local_address);
101	if (kret) {
102	    *minor_status = kret;
103	    goto failure;
104	}
105    }
106    if (ac->remote_address) {
107	kret = krb5_store_address (sp, *ac->remote_address);
108	if (kret) {
109	    *minor_status = kret;
110	    goto failure;
111	}
112    }
113    kret = krb5_store_int16 (sp, ac->local_port);
114    if (kret) {
115	*minor_status = kret;
116	goto failure;
117    }
118    kret = krb5_store_int16 (sp, ac->remote_port);
119    if (kret) {
120	*minor_status = kret;
121	goto failure;
122    }
123    if (ac->keyblock) {
124	kret = krb5_store_keyblock (sp, *ac->keyblock);
125	if (kret) {
126	    *minor_status = kret;
127	    goto failure;
128	}
129    }
130    if (ac->local_subkey) {
131	kret = krb5_store_keyblock (sp, *ac->local_subkey);
132	if (kret) {
133	    *minor_status = kret;
134	    goto failure;
135	}
136    }
137    if (ac->remote_subkey) {
138	kret = krb5_store_keyblock (sp, *ac->remote_subkey);
139	if (kret) {
140	    *minor_status = kret;
141	    goto failure;
142	}
143    }
144    kret = krb5_store_int32 (sp, ac->local_seqnumber);
145	if (kret) {
146	    *minor_status = kret;
147	    goto failure;
148	}
149    kret = krb5_store_int32 (sp, ac->remote_seqnumber);
150	if (kret) {
151	    *minor_status = kret;
152	    goto failure;
153	}
154
155    kret = krb5_store_int32 (sp, ac->keytype);
156    if (kret) {
157	*minor_status = kret;
158	goto failure;
159    }
160    kret = krb5_store_int32 (sp, ac->cksumtype);
161    if (kret) {
162	*minor_status = kret;
163	goto failure;
164    }
165
166    /* names */
167
168    ret = _gsskrb5_export_name (minor_status,
169				(gss_name_t)ctx->source, &buffer);
170    if (ret)
171	goto failure;
172    data.data   = buffer.value;
173    data.length = buffer.length;
174    kret = krb5_store_data (sp, data);
175    _gsskrb5_release_buffer (&minor, &buffer);
176    if (kret) {
177	*minor_status = kret;
178	goto failure;
179    }
180
181    ret = _gsskrb5_export_name (minor_status,
182				(gss_name_t)ctx->target, &buffer);
183    if (ret)
184	goto failure;
185    data.data   = buffer.value;
186    data.length = buffer.length;
187
188    ret = GSS_S_FAILURE;
189
190    kret = krb5_store_data (sp, data);
191    _gsskrb5_release_buffer (&minor, &buffer);
192    if (kret) {
193	*minor_status = kret;
194	goto failure;
195    }
196
197    kret = krb5_store_int32 (sp, ctx->flags);
198    if (kret) {
199	*minor_status = kret;
200	goto failure;
201    }
202    kret = krb5_store_int32 (sp, ctx->more_flags);
203    if (kret) {
204	*minor_status = kret;
205	goto failure;
206    }
207    kret = krb5_store_int32 (sp, ctx->lifetime);
208    if (kret) {
209	*minor_status = kret;
210	goto failure;
211    }
212    kret = _gssapi_msg_order_export(sp, ctx->order);
213    if (kret ) {
214        *minor_status = kret;
215        goto failure;
216    }
217
218    kret = krb5_storage_to_data (sp, &data);
219    krb5_storage_free (sp);
220    if (kret) {
221	HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
222	*minor_status = kret;
223	return GSS_S_FAILURE;
224    }
225    interprocess_token->length = data.length;
226    interprocess_token->value  = data.data;
227    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
228    ret = _gsskrb5_delete_sec_context (minor_status, context_handle,
229				       GSS_C_NO_BUFFER);
230    if (ret != GSS_S_COMPLETE)
231	_gsskrb5_release_buffer (NULL, interprocess_token);
232    *minor_status = 0;
233    return ret;
234 failure:
235    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
236    krb5_storage_free (sp);
237    return ret;
238}
239