s4:heimdal: import lorikeet-heimdal-201107150856 (commit 48936803fae4a2fb362c79365d31...
[amitay/samba.git] / source4 / heimdal / lib / gssapi / krb5 / creds.c
1 /*
2  * Copyright (c) 2009 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
36 OM_uint32 GSSAPI_CALLCONV
37 _gsskrb5_export_cred(OM_uint32 *minor_status,
38                      gss_cred_id_t cred_handle,
39                      gss_buffer_t cred_token)
40 {
41     gsskrb5_cred handle = (gsskrb5_cred)cred_handle;
42     krb5_context context;
43     krb5_error_code ret;
44     krb5_storage *sp;
45     krb5_data data, mech;
46     const char *type;
47     char *str;
48
49     GSSAPI_KRB5_INIT (&context);
50
51     if (handle->usage != GSS_C_INITIATE && handle->usage != GSS_C_BOTH) {
52         *minor_status = GSS_KRB5_S_G_BAD_USAGE;
53         return GSS_S_FAILURE;
54     }
55
56     sp = krb5_storage_emem();
57     if (sp == NULL) {
58         *minor_status = ENOMEM;
59         return GSS_S_FAILURE;
60     }
61
62     type = krb5_cc_get_type(context, handle->ccache);
63     if (strcmp(type, "MEMORY") == 0) {
64         krb5_creds *creds;
65         ret = krb5_store_uint32(sp, 0);
66         if (ret) {
67             krb5_storage_free(sp);
68             *minor_status = ret;
69             return GSS_S_FAILURE;
70         }
71
72         ret = _krb5_get_krbtgt(context, handle->ccache,
73                                handle->principal->realm,
74                                &creds);
75         if (ret) {
76             krb5_storage_free(sp);
77             *minor_status = ret;
78             return GSS_S_FAILURE;
79         }
80
81         ret = krb5_store_creds(sp, creds);
82         krb5_free_creds(context, creds);
83         if (ret) {
84             krb5_storage_free(sp);
85             *minor_status = ret;
86             return GSS_S_FAILURE;
87         }
88
89     } else {
90         ret = krb5_store_uint32(sp, 1);
91         if (ret) {
92             krb5_storage_free(sp);
93             *minor_status = ret;
94             return GSS_S_FAILURE;
95         }
96
97         ret = krb5_cc_get_full_name(context, handle->ccache, &str);
98         if (ret) {
99             krb5_storage_free(sp);
100             *minor_status = ret;
101             return GSS_S_FAILURE;
102         }
103
104         ret = krb5_store_string(sp, str);
105         free(str);
106         if (ret) {
107             krb5_storage_free(sp);
108             *minor_status = ret;
109             return GSS_S_FAILURE;
110         }
111     }
112     ret = krb5_storage_to_data(sp, &data);
113     krb5_storage_free(sp);
114     if (ret) {
115         *minor_status = ret;
116         return GSS_S_FAILURE;
117     }
118     sp = krb5_storage_emem();
119     if (sp == NULL) {
120         krb5_data_free(&data);
121         *minor_status = ENOMEM;
122         return GSS_S_FAILURE;
123     }
124
125     mech.data = GSS_KRB5_MECHANISM->elements;
126     mech.length = GSS_KRB5_MECHANISM->length;
127
128     ret = krb5_store_data(sp, mech);
129     if (ret) {
130         krb5_data_free(&data);
131         krb5_storage_free(sp);
132         *minor_status = ret;
133         return GSS_S_FAILURE;
134     }
135
136     ret = krb5_store_data(sp, data);
137     krb5_data_free(&data);
138     if (ret) {
139         krb5_storage_free(sp);
140         *minor_status = ret;
141         return GSS_S_FAILURE;
142     }
143
144     ret = krb5_storage_to_data(sp, &data);
145     krb5_storage_free(sp);
146     if (ret) {
147         *minor_status = ret;
148         return GSS_S_FAILURE;
149     }
150
151     cred_token->value = data.data;
152     cred_token->length = data.length;
153
154     return GSS_S_COMPLETE;
155 }
156
157 OM_uint32 GSSAPI_CALLCONV
158 _gsskrb5_import_cred(OM_uint32 * minor_status,
159                      gss_buffer_t cred_token,
160                      gss_cred_id_t * cred_handle)
161 {
162     krb5_context context;
163     krb5_error_code ret;
164     gsskrb5_cred handle;
165     krb5_ccache id;
166     krb5_storage *sp;
167     char *str;
168     uint32_t type;
169     int flags = 0;
170
171     *cred_handle = GSS_C_NO_CREDENTIAL;
172
173     GSSAPI_KRB5_INIT (&context);
174
175     sp = krb5_storage_from_mem(cred_token->value, cred_token->length);
176     if (sp == NULL) {
177         *minor_status = ENOMEM;
178         return GSS_S_FAILURE;
179     }
180
181     ret = krb5_ret_uint32(sp, &type);
182     if (ret) {
183         krb5_storage_free(sp);
184         *minor_status = ret;
185         return GSS_S_FAILURE;
186     }
187     switch (type) {
188     case 0: {
189         krb5_creds creds;
190
191         ret = krb5_ret_creds(sp, &creds);
192         krb5_storage_free(sp);
193         if (ret) {
194             *minor_status = ret;
195             return GSS_S_FAILURE;
196         }
197
198         ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
199         if (ret) {
200             *minor_status = ret;
201             return GSS_S_FAILURE;
202         }
203
204         ret = krb5_cc_initialize(context, id, creds.client);
205         if (ret) {
206             krb5_cc_destroy(context, id);
207             *minor_status = ret;
208             return GSS_S_FAILURE;
209         }
210
211         ret = krb5_cc_store_cred(context, id, &creds);
212         krb5_free_cred_contents(context, &creds);
213
214         flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
215
216         break;
217     }
218     case 1:
219         ret = krb5_ret_string(sp, &str);
220         krb5_storage_free(sp);
221         if (ret) {
222             *minor_status = ret;
223             return GSS_S_FAILURE;
224         }
225
226         ret = krb5_cc_resolve(context, str, &id);
227         krb5_xfree(str);
228         if (ret) {
229             *minor_status = ret;
230             return GSS_S_FAILURE;
231         }
232         break;
233
234     default:
235         krb5_storage_free(sp);
236         *minor_status = 0;
237         return GSS_S_NO_CRED;
238     }
239
240     handle = calloc(1, sizeof(*handle));
241     if (handle == NULL) {
242         krb5_cc_close(context, id);
243         *minor_status = ENOMEM;
244         return GSS_S_FAILURE;
245     }
246
247     handle->usage = GSS_C_INITIATE;
248     krb5_cc_get_principal(context, id, &handle->principal);
249     handle->ccache = id;
250     handle->cred_flags = flags;
251
252     *cred_handle = (gss_cred_id_t)handle;
253
254     return GSS_S_COMPLETE;
255 }