1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/ccache/ccapi_util.c - conversion functions for CCAPI creds */
3 /*
4 * Copyright (C) 2022 by the Massachusetts Institute of Technology.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include "cc-int.h"
34 #include "ccapi_util.h"
35
36 #if defined(USE_CCAPI) || defined(USE_CCAPI_MACOS)
37
38 static void
free_cc_data_list(cc_data ** list)39 free_cc_data_list(cc_data **list)
40 {
41 size_t i;
42
43 for (i = 0; list != NULL && list[i] != NULL; i++) {
44 free(list[i]->data);
45 free(list[i]);
46 }
47 free(list);
48 }
49
50 static krb5_error_code
cc_data_list_to_addresses(krb5_context context,cc_data ** list,krb5_address *** addrs_out)51 cc_data_list_to_addresses(krb5_context context, cc_data **list,
52 krb5_address ***addrs_out)
53 {
54 krb5_error_code ret;
55 size_t count, i;
56 krb5_address **addrs = NULL;
57
58 *addrs_out = NULL;
59 if (list == NULL)
60 return 0;
61
62 for (count = 0; list[count]; count++);
63 addrs = k5calloc(count + 1, sizeof(*addrs), &ret);
64 if (addrs == NULL)
65 return ret;
66
67 for (i = 0; i < count; i++) {
68 addrs[i] = k5alloc(sizeof(*addrs[i]), &ret);
69 if (addrs[i] == NULL)
70 goto cleanup;
71
72 addrs[i]->contents = k5memdup(list[i]->data, list[i]->length, &ret);
73 if (addrs[i]->contents == NULL)
74 goto cleanup;
75 addrs[i]->length = list[i]->length;
76 addrs[i]->addrtype = list[i]->type;
77 addrs[i]->magic = KV5M_ADDRESS;
78 }
79
80 *addrs_out = addrs;
81 addrs = NULL;
82
83 cleanup:
84 krb5_free_addresses(context, addrs);
85 return ret;
86 }
87
88 static krb5_error_code
cc_data_list_to_authdata(krb5_context context,cc_data ** list,krb5_authdata *** authdata_out)89 cc_data_list_to_authdata(krb5_context context, cc_data **list,
90 krb5_authdata ***authdata_out)
91 {
92 krb5_error_code ret;
93 size_t count, i;
94 krb5_authdata **authdata = NULL;
95
96 *authdata_out = NULL;
97 if (list == NULL)
98 return 0;
99
100 for (count = 0; list[count]; count++);
101 authdata = k5calloc(count + 1, sizeof(*authdata), &ret);
102 if (authdata == NULL)
103 return ret;
104
105 for (i = 0; i < count; i++) {
106 authdata[i] = k5alloc(sizeof(*authdata[i]), &ret);
107 if (authdata[i] == NULL)
108 goto cleanup;
109
110 authdata[i]->contents = k5memdup(list[i]->data, list[i]->length, &ret);
111 if (authdata[i]->contents == NULL)
112 goto cleanup;
113 authdata[i]->length = list[i]->length;
114 authdata[i]->ad_type = list[i]->type;
115 authdata[i]->magic = KV5M_AUTHDATA;
116 }
117
118 *authdata_out = authdata;
119 authdata = NULL;
120
121 cleanup:
122 krb5_free_authdata(context, authdata);
123 return ret;
124 }
125
126 static krb5_error_code
addresses_to_cc_data_list(krb5_context context,krb5_address ** addrs,cc_data *** list_out)127 addresses_to_cc_data_list(krb5_context context, krb5_address **addrs,
128 cc_data ***list_out)
129 {
130 krb5_error_code ret;
131 size_t count, i;
132 cc_data **list = NULL;
133
134 *list_out = NULL;
135 if (addrs == NULL)
136 return 0;
137
138 for (count = 0; addrs[count]; count++);
139 list = k5calloc(count + 1, sizeof(*list), &ret);
140 if (list == NULL)
141 return ret;
142
143 for (i = 0; i < count; i++) {
144 list[i] = k5alloc(sizeof(*list[i]), &ret);
145 if (list[i] == NULL)
146 goto cleanup;
147
148 list[i]->data = k5memdup(addrs[i]->contents, addrs[i]->length, &ret);
149 if (list[i]->data == NULL)
150 goto cleanup;
151 list[i]->length = addrs[i]->length;
152 list[i]->type = addrs[i]->addrtype;
153 }
154
155 *list_out = list;
156 list = NULL;
157
158 cleanup:
159 free_cc_data_list(list);
160 return ret;
161 }
162
163 static krb5_error_code
authdata_to_cc_data_list(krb5_context context,krb5_authdata ** authdata,cc_data *** list_out)164 authdata_to_cc_data_list(krb5_context context, krb5_authdata **authdata,
165 cc_data ***list_out)
166 {
167 krb5_error_code ret;
168 size_t count, i;
169 cc_data **list = NULL;
170
171 *list_out = NULL;
172 if (authdata == NULL)
173 return 0;
174
175 for (count = 0; authdata[count]; count++);
176 list = k5calloc(count + 1, sizeof(*list), &ret);
177 if (list == NULL)
178 return ret;
179
180 for (i = 0; i < count; i++) {
181 list[i] = k5alloc(sizeof(*list[i]), &ret);
182 if (list[i] == NULL)
183 goto cleanup;
184
185 list[i]->data = k5memdup(authdata[i]->contents, authdata[i]->length,
186 &ret);
187 if (list[i]->data == NULL)
188 goto cleanup;
189 list[i]->length = authdata[i]->length;
190 list[i]->type = authdata[i]->ad_type;
191 }
192
193 *list_out = list;
194 list = NULL;
195
196 cleanup:
197 free_cc_data_list(list);
198 return ret;
199 }
200
201 krb5_error_code
k5_ccapi_to_krb5_creds(krb5_context context,const cc_credentials_union * ccapi_cred,krb5_creds * cred_out)202 k5_ccapi_to_krb5_creds(krb5_context context,
203 const cc_credentials_union *ccapi_cred,
204 krb5_creds *cred_out)
205 {
206 krb5_error_code ret;
207 cc_credentials_v5_t *cv5 = NULL;
208 krb5_principal client = NULL;
209 krb5_principal server = NULL;
210 char *ticket_data = NULL;
211 char *second_ticket_data = NULL;
212 uint8_t *keyblock_contents = NULL;
213 krb5_address **addresses = NULL;
214 krb5_authdata **authdata = NULL;
215
216 if (ccapi_cred->version != cc_credentials_v5)
217 return KRB5_CC_NOT_KTYPE;
218
219 cv5 = ccapi_cred->credentials.credentials_v5;
220
221 ret = krb5_parse_name(context, cv5->client, &client);
222 if (ret)
223 goto cleanup;
224 ret = krb5_parse_name(context, cv5->server, &server);
225 if (ret)
226 goto cleanup;
227
228 if (cv5->keyblock.length > 0) {
229 keyblock_contents = k5memdup(cv5->keyblock.data, cv5->keyblock.length,
230 &ret);
231 if (keyblock_contents == NULL)
232 goto cleanup;
233 }
234
235 if (cv5->ticket.length > 0) {
236 ticket_data = k5memdup(cv5->ticket.data, cv5->ticket.length, &ret);
237 if (ticket_data == NULL)
238 goto cleanup;
239 }
240
241 if (cv5->second_ticket.length > 0) {
242 second_ticket_data = k5memdup(cv5->second_ticket.data,
243 cv5->second_ticket.length, &ret);
244 if (second_ticket_data == NULL)
245 goto cleanup;
246 }
247
248 ret = cc_data_list_to_addresses(context, cv5->addresses, &addresses);
249 if (ret)
250 goto cleanup;
251
252 ret = cc_data_list_to_authdata(context, cv5->authdata, &authdata);
253 if (ret)
254 goto cleanup;
255
256 cred_out->client = client;
257 cred_out->server = server;
258 client = server = NULL;
259
260 cred_out->keyblock.magic = KV5M_KEYBLOCK;
261 cred_out->keyblock.enctype = cv5->keyblock.type;
262 cred_out->keyblock.length = cv5->keyblock.length;
263 cred_out->keyblock.contents = keyblock_contents;
264 keyblock_contents = NULL;
265
266 cred_out->times.authtime = cv5->authtime;
267 cred_out->times.starttime = cv5->starttime;
268 cred_out->times.endtime = cv5->endtime;
269 cred_out->times.renew_till = cv5->renew_till;
270 cred_out->is_skey = cv5->is_skey;
271 cred_out->ticket_flags = cv5->ticket_flags;
272
273 cred_out->ticket = make_data(ticket_data, cv5->ticket.length);
274 cred_out->second_ticket = make_data(second_ticket_data,
275 cv5->second_ticket.length);
276 ticket_data = second_ticket_data = NULL;
277
278 cred_out->addresses = addresses;
279 addresses = NULL;
280
281 cred_out->authdata = authdata;
282 authdata = NULL;
283
284 cred_out->magic = KV5M_CREDS;
285
286 cleanup:
287 krb5_free_principal(context, client);
288 krb5_free_principal(context, server);
289 krb5_free_addresses(context, addresses);
290 krb5_free_authdata(context, authdata);
291 free(keyblock_contents);
292 free(ticket_data);
293 free(second_ticket_data);
294 return ret;
295 }
296
297 krb5_error_code
k5_krb5_to_ccapi_creds(krb5_context context,krb5_creds * cred,cc_credentials_union ** ccapi_cred_out)298 k5_krb5_to_ccapi_creds(krb5_context context, krb5_creds *cred,
299 cc_credentials_union **ccapi_cred_out)
300 {
301 krb5_error_code ret;
302 cc_credentials_union *cred_union = NULL;
303 cc_credentials_v5_t *cv5 = NULL;
304 char *client = NULL, *server = NULL;
305 uint8_t *ticket_data = NULL, *second_ticket_data = NULL;
306 uint8_t *keyblock_data = NULL;
307 cc_data **addr_list = NULL, **authdata_list = NULL;
308
309 cred_union = k5alloc(sizeof(*cred_union), &ret);
310 if (cred_union == NULL)
311 goto cleanup;
312
313 cv5 = k5alloc(sizeof(*cv5), &ret);
314 if (cv5 == NULL)
315 goto cleanup;
316
317 ret = krb5_unparse_name(context, cred->client, &client);
318 if (ret)
319 goto cleanup;
320 ret = krb5_unparse_name(context, cred->server, &server);
321 if (ret)
322 goto cleanup;
323
324 if (cred->keyblock.length > 0) {
325 keyblock_data = k5memdup(cred->keyblock.contents,
326 cred->keyblock.length, &ret);
327 if (keyblock_data == NULL)
328 goto cleanup;
329 }
330
331 if (cred->ticket.length > 0) {
332 ticket_data = k5memdup0(cred->ticket.data, cred->ticket.length, &ret);
333 if (ticket_data == NULL)
334 goto cleanup;
335 }
336
337 if (cred->second_ticket.length > 0) {
338 second_ticket_data = k5memdup0(cred->second_ticket.data,
339 cred->second_ticket.length, &ret);
340 if (second_ticket_data == NULL)
341 goto cleanup;
342 }
343
344 ret = addresses_to_cc_data_list(context, cred->addresses, &addr_list);
345 if (ret)
346 goto cleanup;
347
348 ret = authdata_to_cc_data_list(context, cred->authdata, &authdata_list);
349 if (ret)
350 goto cleanup;
351
352 cv5->client = client;
353 cv5->server = server;
354 client = server = NULL;
355
356 cv5->keyblock.type = cred->keyblock.enctype;
357 cv5->keyblock.length = cred->keyblock.length;
358 cv5->keyblock.data = keyblock_data;
359 keyblock_data = NULL;
360
361 cv5->authtime = cred->times.authtime;
362 cv5->starttime = cred->times.starttime;
363 cv5->endtime = cred->times.endtime;
364 cv5->renew_till = cred->times.renew_till;
365 cv5->is_skey = cred->is_skey;
366 cv5->ticket_flags = cred->ticket_flags;
367
368 cv5->ticket.length = cred->ticket.length;
369 cv5->ticket.data = ticket_data;
370 cv5->second_ticket.length = cred->second_ticket.length;
371 cv5->second_ticket.data = second_ticket_data;
372 ticket_data = second_ticket_data = NULL;
373
374 cv5->addresses = addr_list;
375 addr_list = NULL;
376
377 cv5->authdata = authdata_list;
378 authdata_list = NULL;
379
380 cred_union->version = cc_credentials_v5;
381 cred_union->credentials.credentials_v5 = cv5;
382 cv5 = NULL;
383
384 *ccapi_cred_out = cred_union;
385 cred_union = NULL;
386
387 cleanup:
388 free_cc_data_list(addr_list);
389 free_cc_data_list(authdata_list);
390 free(keyblock_data);
391 free(ticket_data);
392 free(second_ticket_data);
393 krb5_free_unparsed_name(context, client);
394 krb5_free_unparsed_name(context, server);
395 free(cv5);
396 free(cred_union);
397 return ret;
398 }
399
400 void
k5_release_ccapi_cred(cc_credentials_union * ccapi_cred)401 k5_release_ccapi_cred(cc_credentials_union *ccapi_cred)
402 {
403 cc_credentials_v5_t *cv5;
404
405 if (ccapi_cred == NULL)
406 return;
407 if (ccapi_cred->version != cc_credentials_v5)
408 return;
409 if (ccapi_cred->credentials.credentials_v5 == NULL)
410 return;
411
412 cv5 = ccapi_cred->credentials.credentials_v5;
413
414 free(cv5->client);
415 free(cv5->server);
416 free(cv5->keyblock.data);
417 free(cv5->ticket.data);
418 free(cv5->second_ticket.data);
419 free_cc_data_list(cv5->addresses);
420 free_cc_data_list(cv5->authdata);
421 free(cv5);
422 free(ccapi_cred);
423 }
424
425 #endif /* defined(USE_CCAPI) */
426