Line data Source code
1 : /*
2 : * Copyright (c) 2017 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 KTH nor the names of its contributors may be
18 : * used to endorse or promote products derived from this software without
19 : * specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22 : * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25 : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 : * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 : */
33 :
34 : #include "mech_locl.h"
35 : #include <krb5.h>
36 :
37 : static OM_uint32
38 0 : store_mech_oid_and_oid_set(OM_uint32 *minor_status,
39 : krb5_storage *sp,
40 : gss_const_OID mech,
41 : gss_const_OID_set oids)
42 : {
43 0 : OM_uint32 ret;
44 0 : size_t i, len;
45 :
46 0 : ret = _gss_mg_store_oid(minor_status, sp, mech);
47 0 : if (ret)
48 0 : return ret;
49 :
50 0 : for (i = 0, len = 0; i < oids->count; i++)
51 0 : len += 4 + oids->elements[i].length;
52 :
53 0 : *minor_status = krb5_store_uint32(sp, len);
54 0 : if (*minor_status)
55 0 : return GSS_S_FAILURE;
56 :
57 0 : for (i = 0; i < oids->count; i++) {
58 0 : ret = _gss_mg_store_oid(minor_status, sp, &oids->elements[i]);
59 0 : if (ret)
60 0 : return ret;
61 : }
62 :
63 0 : return GSS_S_COMPLETE;
64 : }
65 :
66 :
67 : /*
68 : * format: any number of:
69 : * mech-len: int32
70 : * mech-data: char * (not alligned)
71 : * cred-len: int32
72 : * cred-data char * (not alligned)
73 : *
74 : * where neg_mechs is encoded for GSS_SPNEGO_MECHANISM
75 : */
76 :
77 : GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
78 788 : gss_export_cred(OM_uint32 * minor_status,
79 : gss_cred_id_t cred_handle,
80 : gss_buffer_t token)
81 : {
82 788 : struct _gss_cred *cred = (struct _gss_cred *)cred_handle;
83 0 : struct _gss_mechanism_cred *mc;
84 0 : gss_buffer_desc buffer;
85 0 : krb5_error_code ret;
86 0 : krb5_ssize_t bytes;
87 0 : krb5_storage *sp;
88 0 : OM_uint32 major;
89 0 : krb5_data data;
90 :
91 788 : _mg_buffer_zero(token);
92 :
93 788 : if (cred == NULL) {
94 0 : *minor_status = 0;
95 0 : return GSS_S_NO_CRED;
96 : }
97 :
98 1576 : HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) {
99 788 : if (mc->gmc_mech->gm_export_cred == NULL) {
100 0 : *minor_status = 0;
101 0 : gss_mg_set_error_string(&mc->gmc_mech->gm_mech_oid,
102 : GSS_S_NO_CRED, *minor_status,
103 : "Credential doesn't support exporting");
104 0 : return GSS_S_NO_CRED;
105 : }
106 : }
107 :
108 788 : sp = krb5_storage_emem();
109 788 : if (sp == NULL) {
110 0 : *minor_status = ENOMEM;
111 0 : return GSS_S_FAILURE;
112 : }
113 :
114 1576 : HEIM_TAILQ_FOREACH(mc, &cred->gc_mc, gmc_link) {
115 788 : major = mc->gmc_mech->gm_export_cred(minor_status,
116 : mc->gmc_cred, &buffer);
117 788 : if (major) {
118 0 : krb5_storage_free(sp);
119 0 : return major;
120 : }
121 :
122 788 : if (buffer.length) {
123 788 : bytes = krb5_storage_write(sp, buffer.value, buffer.length);
124 788 : if (bytes < 0 || (size_t)bytes != buffer.length) {
125 0 : _gss_secure_release_buffer(minor_status, &buffer);
126 0 : krb5_storage_free(sp);
127 0 : *minor_status = EINVAL;
128 0 : return GSS_S_FAILURE;
129 : }
130 : }
131 788 : _gss_secure_release_buffer(minor_status, &buffer);
132 : }
133 :
134 788 : if (cred->gc_neg_mechs != GSS_C_NO_OID_SET) {
135 0 : major = store_mech_oid_and_oid_set(minor_status, sp,
136 : GSS_SPNEGO_MECHANISM,
137 0 : cred->gc_neg_mechs);
138 0 : if (major != GSS_S_COMPLETE) {
139 0 : krb5_storage_free(sp);
140 0 : return major;
141 : }
142 : }
143 :
144 788 : ret = krb5_storage_to_data(sp, &data);
145 788 : krb5_storage_free(sp);
146 788 : if (ret) {
147 0 : *minor_status = ret;
148 0 : return GSS_S_FAILURE;
149 : }
150 :
151 788 : if (data.length == 0) {
152 0 : *minor_status = 0;
153 0 : gss_mg_set_error_string(GSS_C_NO_OID,
154 : GSS_S_NO_CRED, *minor_status,
155 : "Credential was not exportable");
156 0 : return GSS_S_NO_CRED;
157 : }
158 :
159 788 : token->value = data.data;
160 788 : token->length = data.length;
161 :
162 788 : return GSS_S_COMPLETE;
163 : }
164 :
165 : static OM_uint32
166 0 : import_oid_set(OM_uint32 *minor_status,
167 : gss_const_buffer_t token,
168 : gss_OID_set *oids)
169 : {
170 0 : OM_uint32 major, junk;
171 0 : krb5_storage *sp = NULL;
172 :
173 0 : *oids = GSS_C_NO_OID_SET;
174 :
175 0 : if (token->length == 0)
176 0 : return GSS_S_COMPLETE;
177 :
178 0 : major = gss_create_empty_oid_set(minor_status, oids);
179 0 : if (major != GSS_S_COMPLETE)
180 0 : goto out;
181 :
182 0 : sp = krb5_storage_from_readonly_mem(token->value, token->length);
183 0 : if (sp == NULL) {
184 0 : *minor_status = ENOMEM;
185 0 : major = GSS_S_FAILURE;
186 0 : goto out;
187 : }
188 :
189 0 : while (1) {
190 0 : gss_OID oid;
191 :
192 0 : major = _gss_mg_ret_oid(minor_status, sp, &oid);
193 0 : if (*minor_status == (OM_uint32)HEIM_ERR_EOF)
194 0 : break;
195 0 : else if (major)
196 0 : goto out;
197 :
198 0 : major = gss_add_oid_set_member(minor_status, oid, oids);
199 0 : if (major != GSS_S_COMPLETE)
200 0 : goto out;
201 : }
202 :
203 0 : major = GSS_S_COMPLETE;
204 0 : *minor_status = 0;
205 :
206 0 : out:
207 0 : if (major != GSS_S_COMPLETE)
208 0 : gss_release_oid_set(&junk, oids);
209 0 : krb5_storage_free(sp);
210 :
211 0 : return major;
212 : }
213 :
214 : GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
215 23107 : gss_import_cred(OM_uint32 * minor_status,
216 : gss_buffer_t token,
217 : gss_cred_id_t * cred_handle)
218 : {
219 0 : gssapi_mech_interface m;
220 0 : struct _gss_cred *cred;
221 23107 : krb5_storage *sp = NULL;
222 0 : OM_uint32 major, junk;
223 :
224 23107 : *cred_handle = GSS_C_NO_CREDENTIAL;
225 :
226 23107 : if (token->length == 0) {
227 0 : *minor_status = ENOMEM;
228 0 : return GSS_S_FAILURE;
229 : }
230 :
231 23107 : sp = krb5_storage_from_readonly_mem(token->value, token->length);
232 23107 : if (sp == NULL) {
233 0 : *minor_status = ENOMEM;
234 0 : return GSS_S_FAILURE;
235 : }
236 :
237 23107 : cred = _gss_mg_alloc_cred();
238 23107 : if (cred == NULL) {
239 0 : krb5_storage_free(sp);
240 0 : *minor_status = ENOMEM;
241 0 : return GSS_S_FAILURE;
242 : }
243 :
244 23107 : *cred_handle = (gss_cred_id_t)cred;
245 :
246 23107 : while(1) {
247 0 : struct _gss_mechanism_cred *mc;
248 0 : gss_buffer_desc buffer;
249 0 : gss_cred_id_t mcred;
250 0 : gss_OID oid;
251 :
252 46214 : major = _gss_mg_ret_oid(minor_status, sp, &oid);
253 46214 : if (*minor_status == (OM_uint32)HEIM_ERR_EOF)
254 23107 : break;
255 23107 : else if (major != GSS_S_COMPLETE)
256 0 : goto out;
257 :
258 23107 : m = __gss_get_mechanism(oid);
259 23107 : if (!m) {
260 0 : *minor_status = 0;
261 0 : major = GSS_S_BAD_MECH;
262 0 : goto out;
263 : }
264 :
265 23107 : if (m->gm_import_cred == NULL) {
266 0 : *minor_status = 0;
267 0 : major = GSS_S_BAD_MECH;
268 0 : goto out;
269 : }
270 :
271 23107 : major = _gss_mg_ret_buffer(minor_status, sp, &buffer);
272 23107 : if (major != GSS_S_COMPLETE)
273 0 : goto out;
274 :
275 23107 : if (buffer.value == NULL) {
276 0 : major = GSS_S_DEFECTIVE_TOKEN;
277 0 : goto out;
278 : }
279 :
280 23107 : if (gss_oid_equal(&m->gm_mech_oid, GSS_SPNEGO_MECHANISM)) {
281 0 : major = import_oid_set(minor_status, &buffer, &cred->gc_neg_mechs);
282 0 : gss_release_buffer(&junk, &buffer);
283 0 : if (major != GSS_S_COMPLETE)
284 0 : goto out;
285 : else
286 0 : continue;
287 : }
288 :
289 23107 : major = m->gm_import_cred(minor_status, &buffer, &mcred);
290 23107 : gss_release_buffer(&junk, &buffer);
291 23107 : if (major != GSS_S_COMPLETE)
292 0 : goto out;
293 :
294 23107 : mc = calloc(1, sizeof(struct _gss_mechanism_cred));
295 23107 : if (mc == NULL) {
296 0 : *minor_status = EINVAL;
297 0 : major = GSS_S_FAILURE;
298 0 : goto out;
299 : }
300 :
301 23107 : mc->gmc_mech = m;
302 23107 : mc->gmc_mech_oid = &m->gm_mech_oid;
303 23107 : mc->gmc_cred = mcred;
304 :
305 23107 : HEIM_TAILQ_INSERT_TAIL(&cred->gc_mc, mc, gmc_link);
306 : }
307 23107 : krb5_storage_free(sp);
308 23107 : sp = NULL;
309 :
310 23107 : if (HEIM_TAILQ_EMPTY(&cred->gc_mc)) {
311 0 : major = GSS_S_NO_CRED;
312 0 : goto out;
313 : }
314 :
315 23107 : return GSS_S_COMPLETE;
316 :
317 0 : out:
318 0 : if (sp)
319 0 : krb5_storage_free(sp);
320 :
321 0 : gss_release_cred(&junk, cred_handle);
322 :
323 0 : return major;
324 :
325 : }
326 :
|