1 /* $NetBSD: creds.c,v 1.2 2017/01/28 21:31:46 christos Exp $ */
2
3 /*
4 * Copyright (c) 2009 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "gsskrb5_locl.h"
37
38 OM_uint32 GSSAPI_CALLCONV
_gsskrb5_export_cred(OM_uint32 * minor_status,gss_cred_id_t cred_handle,gss_buffer_t cred_token)39 _gsskrb5_export_cred(OM_uint32 *minor_status,
40 gss_cred_id_t cred_handle,
41 gss_buffer_t cred_token)
42 {
43 gsskrb5_cred handle = (gsskrb5_cred)cred_handle;
44 krb5_context context;
45 krb5_error_code ret;
46 krb5_storage *sp;
47 krb5_data data, mech;
48 const char *type;
49 char *str;
50
51 GSSAPI_KRB5_INIT (&context);
52
53 if (handle->usage != GSS_C_INITIATE && handle->usage != GSS_C_BOTH) {
54 *minor_status = GSS_KRB5_S_G_BAD_USAGE;
55 return GSS_S_FAILURE;
56 }
57
58 sp = krb5_storage_emem();
59 if (sp == NULL) {
60 *minor_status = ENOMEM;
61 return GSS_S_FAILURE;
62 }
63
64 type = krb5_cc_get_type(context, handle->ccache);
65 if (strcmp(type, "MEMORY") == 0) {
66 krb5_creds *creds;
67 krb5_data config_start_realm;
68 char *start_realm;
69
70 ret = krb5_store_uint32(sp, 0);
71 if (ret) {
72 krb5_storage_free(sp);
73 *minor_status = ret;
74 return GSS_S_FAILURE;
75 }
76
77 ret = krb5_cc_get_config(context, handle->ccache, NULL, "start_realm",
78 &config_start_realm);
79 if (ret == 0) {
80 start_realm = strndup(config_start_realm.data,
81 config_start_realm.length);
82 krb5_data_free(&config_start_realm);
83 } else {
84 start_realm = strdup(krb5_principal_get_realm(context,
85 handle->principal));
86 }
87 if (start_realm == NULL) {
88 *minor_status = krb5_enomem(context);
89 krb5_storage_free(sp);
90 return GSS_S_FAILURE;
91 }
92
93 ret = _krb5_get_krbtgt(context, handle->ccache, start_realm, &creds);
94 free(start_realm);
95 start_realm = NULL;
96 if (ret) {
97 krb5_storage_free(sp);
98 *minor_status = ret;
99 return GSS_S_FAILURE;
100 }
101
102 ret = krb5_store_creds(sp, creds);
103 krb5_free_creds(context, creds);
104 if (ret) {
105 krb5_storage_free(sp);
106 *minor_status = ret;
107 return GSS_S_FAILURE;
108 }
109
110 } else {
111 ret = krb5_store_uint32(sp, 1);
112 if (ret) {
113 krb5_storage_free(sp);
114 *minor_status = ret;
115 return GSS_S_FAILURE;
116 }
117
118 ret = krb5_cc_get_full_name(context, handle->ccache, &str);
119 if (ret) {
120 krb5_storage_free(sp);
121 *minor_status = ret;
122 return GSS_S_FAILURE;
123 }
124
125 ret = krb5_store_string(sp, str);
126 free(str);
127 if (ret) {
128 krb5_storage_free(sp);
129 *minor_status = ret;
130 return GSS_S_FAILURE;
131 }
132 }
133 ret = krb5_storage_to_data(sp, &data);
134 krb5_storage_free(sp);
135 if (ret) {
136 *minor_status = ret;
137 return GSS_S_FAILURE;
138 }
139 sp = krb5_storage_emem();
140 if (sp == NULL) {
141 krb5_data_free(&data);
142 *minor_status = ENOMEM;
143 return GSS_S_FAILURE;
144 }
145
146 mech.data = GSS_KRB5_MECHANISM->elements;
147 mech.length = GSS_KRB5_MECHANISM->length;
148
149 ret = krb5_store_data(sp, mech);
150 if (ret) {
151 krb5_data_free(&data);
152 krb5_storage_free(sp);
153 *minor_status = ret;
154 return GSS_S_FAILURE;
155 }
156
157 ret = krb5_store_data(sp, data);
158 krb5_data_free(&data);
159 if (ret) {
160 krb5_storage_free(sp);
161 *minor_status = ret;
162 return GSS_S_FAILURE;
163 }
164
165 ret = krb5_storage_to_data(sp, &data);
166 krb5_storage_free(sp);
167 if (ret) {
168 *minor_status = ret;
169 return GSS_S_FAILURE;
170 }
171
172 cred_token->value = data.data;
173 cred_token->length = data.length;
174
175 return GSS_S_COMPLETE;
176 }
177
178 OM_uint32 GSSAPI_CALLCONV
_gsskrb5_import_cred(OM_uint32 * minor_status,gss_buffer_t cred_token,gss_cred_id_t * cred_handle)179 _gsskrb5_import_cred(OM_uint32 * minor_status,
180 gss_buffer_t cred_token,
181 gss_cred_id_t * cred_handle)
182 {
183 krb5_context context;
184 krb5_error_code ret;
185 gsskrb5_cred handle;
186 krb5_ccache id;
187 krb5_storage *sp;
188 char *str;
189 uint32_t type;
190 int flags = 0;
191
192 *cred_handle = GSS_C_NO_CREDENTIAL;
193
194 GSSAPI_KRB5_INIT (&context);
195
196 sp = krb5_storage_from_mem(cred_token->value, cred_token->length);
197 if (sp == NULL) {
198 *minor_status = ENOMEM;
199 return GSS_S_FAILURE;
200 }
201
202 ret = krb5_ret_uint32(sp, &type);
203 if (ret) {
204 krb5_storage_free(sp);
205 *minor_status = ret;
206 return GSS_S_FAILURE;
207 }
208 switch (type) {
209 case 0: {
210 krb5_creds creds;
211
212 ret = krb5_ret_creds(sp, &creds);
213 krb5_storage_free(sp);
214 if (ret) {
215 *minor_status = ret;
216 return GSS_S_FAILURE;
217 }
218
219 ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
220 if (ret) {
221 *minor_status = ret;
222 return GSS_S_FAILURE;
223 }
224
225 ret = krb5_cc_initialize(context, id, creds.client);
226 if (ret) {
227 krb5_cc_destroy(context, id);
228 *minor_status = ret;
229 return GSS_S_FAILURE;
230 }
231
232 ret = krb5_cc_store_cred(context, id, &creds);
233 krb5_free_cred_contents(context, &creds);
234 if (ret) {
235 *minor_status = ret;
236 return GSS_S_FAILURE;
237 }
238
239 flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
240
241 break;
242 }
243 case 1:
244 ret = krb5_ret_string(sp, &str);
245 krb5_storage_free(sp);
246 if (ret) {
247 *minor_status = ret;
248 return GSS_S_FAILURE;
249 }
250
251 ret = krb5_cc_resolve(context, str, &id);
252 krb5_xfree(str);
253 if (ret) {
254 *minor_status = ret;
255 return GSS_S_FAILURE;
256 }
257 break;
258
259 default:
260 krb5_storage_free(sp);
261 *minor_status = 0;
262 return GSS_S_NO_CRED;
263 }
264
265 handle = calloc(1, sizeof(*handle));
266 if (handle == NULL) {
267 krb5_cc_close(context, id);
268 *minor_status = ENOMEM;
269 return GSS_S_FAILURE;
270 }
271
272 handle->usage = GSS_C_INITIATE;
273 krb5_cc_get_principal(context, id, &handle->principal);
274 handle->ccache = id;
275 handle->cred_flags = flags;
276
277 *cred_handle = (gss_cred_id_t)handle;
278
279 return GSS_S_COMPLETE;
280 }
281