r19604: This is a massive commit, and I appologise in advance for it's size.
[kai/samba.git] / source4 / heimdal / lib / gssapi / krb5 / export_sec_context.c
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 "krb5/gsskrb5_locl.h"
35
36 RCSID("$Id: export_sec_context.c,v 1.11 2006/10/07 22:14:42 lha Exp $");
37
38 OM_uint32
39 _gsskrb5_export_sec_context (
40     OM_uint32 * minor_status,
41     gss_ctx_id_t * context_handle,
42     gss_buffer_t interprocess_token
43     )
44 {
45     const gsskrb5_ctx ctx = (const gsskrb5_ctx) *context_handle;
46     krb5_storage *sp;
47     krb5_auth_context ac;
48     OM_uint32 ret = GSS_S_COMPLETE;
49     krb5_data data;
50     gss_buffer_desc buffer;
51     int flags;
52     OM_uint32 minor;
53     krb5_error_code kret;
54
55     GSSAPI_KRB5_INIT ();
56
57     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
58
59     if (!(ctx->flags & GSS_C_TRANS_FLAG)) {
60         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
61         *minor_status = 0;
62         return GSS_S_UNAVAILABLE;
63     }
64
65     sp = krb5_storage_emem ();
66     if (sp == NULL) {
67         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
68         *minor_status = ENOMEM;
69         return GSS_S_FAILURE;
70     }
71     ac = ctx->auth_context;
72
73     /* flagging included fields */
74
75     flags = 0;
76     if (ac->local_address)
77         flags |= SC_LOCAL_ADDRESS;
78     if (ac->remote_address)
79         flags |= SC_REMOTE_ADDRESS;
80     if (ac->keyblock)
81         flags |= SC_KEYBLOCK;
82     if (ac->local_subkey)
83         flags |= SC_LOCAL_SUBKEY;
84     if (ac->remote_subkey)
85         flags |= SC_REMOTE_SUBKEY;
86
87     kret = krb5_store_int32 (sp, flags);
88     if (kret) {
89         *minor_status = kret;
90         goto failure;
91     }
92
93     /* marshall auth context */
94
95     kret = krb5_store_int32 (sp, ac->flags);
96     if (kret) {
97         *minor_status = kret;
98         goto failure;
99     }
100     if (ac->local_address) {
101         kret = krb5_store_address (sp, *ac->local_address);
102         if (kret) {
103             *minor_status = kret;
104             goto failure;
105         }
106     }
107     if (ac->remote_address) {
108         kret = krb5_store_address (sp, *ac->remote_address);
109         if (kret) {
110             *minor_status = kret;
111             goto failure;
112         }
113     }
114     kret = krb5_store_int16 (sp, ac->local_port);
115     if (kret) {
116         *minor_status = kret;
117         goto failure;
118     }
119     kret = krb5_store_int16 (sp, ac->remote_port);
120     if (kret) {
121         *minor_status = kret;
122         goto failure;
123     }
124     if (ac->keyblock) {
125         kret = krb5_store_keyblock (sp, *ac->keyblock);
126         if (kret) {
127             *minor_status = kret;
128             goto failure;
129         }
130     }
131     if (ac->local_subkey) {
132         kret = krb5_store_keyblock (sp, *ac->local_subkey);
133         if (kret) {
134             *minor_status = kret;
135             goto failure;
136         }
137     }
138     if (ac->remote_subkey) {
139         kret = krb5_store_keyblock (sp, *ac->remote_subkey);
140         if (kret) {
141             *minor_status = kret;
142             goto failure;
143         }
144     }
145     kret = krb5_store_int32 (sp, ac->local_seqnumber);
146         if (kret) {
147             *minor_status = kret;
148             goto failure;
149         }
150     kret = krb5_store_int32 (sp, ac->remote_seqnumber);
151         if (kret) {
152             *minor_status = kret;
153             goto failure;
154         }
155
156     kret = krb5_store_int32 (sp, ac->keytype);
157     if (kret) {
158         *minor_status = kret;
159         goto failure;
160     }
161     kret = krb5_store_int32 (sp, ac->cksumtype);
162     if (kret) {
163         *minor_status = kret;
164         goto failure;
165     }
166
167     /* names */
168
169     ret = _gsskrb5_export_name (minor_status,
170                                 (gss_name_t)ctx->source, &buffer);
171     if (ret)
172         goto failure;
173     data.data   = buffer.value;
174     data.length = buffer.length;
175     kret = krb5_store_data (sp, data);
176     _gsskrb5_release_buffer (&minor, &buffer);
177     if (kret) {
178         *minor_status = kret;
179         goto failure;
180     }
181
182     ret = _gsskrb5_export_name (minor_status,
183                                 (gss_name_t)ctx->target, &buffer);
184     if (ret)
185         goto failure;
186     data.data   = buffer.value;
187     data.length = buffer.length;
188
189     ret = GSS_S_FAILURE;
190
191     kret = krb5_store_data (sp, data);
192     _gsskrb5_release_buffer (&minor, &buffer);
193     if (kret) {
194         *minor_status = kret;
195         goto failure;
196     }
197
198     kret = krb5_store_int32 (sp, ctx->flags);
199     if (kret) {
200         *minor_status = kret;
201         goto failure;
202     }
203     kret = krb5_store_int32 (sp, ctx->more_flags);
204     if (kret) {
205         *minor_status = kret;
206         goto failure;
207     }
208     kret = krb5_store_int32 (sp, ctx->lifetime);
209     if (kret) {
210         *minor_status = kret;
211         goto failure;
212     }
213     kret = _gssapi_msg_order_export(sp, ctx->order);
214     if (kret ) {
215         *minor_status = kret;
216         goto failure;
217     }
218
219     kret = krb5_storage_to_data (sp, &data);
220     krb5_storage_free (sp);
221     if (kret) {
222         HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
223         *minor_status = kret;
224         return GSS_S_FAILURE;
225     }
226     interprocess_token->length = data.length;
227     interprocess_token->value  = data.data;
228     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
229     ret = _gsskrb5_delete_sec_context (minor_status, context_handle,
230                                        GSS_C_NO_BUFFER);
231     if (ret != GSS_S_COMPLETE)
232         _gsskrb5_release_buffer (NULL, interprocess_token);
233     *minor_status = 0;
234     return ret;
235  failure:
236     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
237     krb5_storage_free (sp);
238     return ret;
239 }