1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * stdcc_util.c
4 * utility functions used in implementing the ccache api for krb5
5 * not publicly exported
6 * Frank Dabek, July 1998
7 */
8
9 #if defined(_WIN32) || defined(USE_CCAPI)
10
11 #include <stdlib.h>
12 #include <string.h>
13 #include <errno.h>
14
15 #if defined(_WIN32)
16 #include <malloc.h>
17 #endif
18
19 #include "k5-int.h"
20 #include "stdcc_util.h"
21 #ifdef _WIN32 /* it's part of krb5.h everywhere else */
22 #include "kv5m_err.h"
23 #endif
24
25 #define fieldSize 255
26
27 #ifdef USE_CCAPI_V3
28
29
30 static void
free_cc_array(cc_data ** io_cc_array)31 free_cc_array (cc_data **io_cc_array)
32 {
33 if (io_cc_array) {
34 unsigned int i;
35
36 for (i = 0; io_cc_array[i]; i++) {
37 if (io_cc_array[i]->data) { free (io_cc_array[i]->data); }
38 free (io_cc_array[i]);
39 }
40 free (io_cc_array);
41 }
42 }
43
44 static krb5_error_code
copy_cc_array_to_addresses(krb5_context in_context,cc_data ** in_cc_array,krb5_address *** out_addresses)45 copy_cc_array_to_addresses (krb5_context in_context,
46 cc_data **in_cc_array,
47 krb5_address ***out_addresses)
48 {
49 krb5_error_code err = 0;
50
51 if (in_cc_array == NULL) {
52 *out_addresses = NULL;
53
54 } else {
55 unsigned int count, i;
56 krb5_address **addresses = NULL;
57
58 /* get length of array */
59 for (count = 0; in_cc_array[count]; count++);
60 addresses = (krb5_address **) malloc (sizeof (*addresses) * (count + 1));
61 if (!addresses) { err = KRB5_CC_NOMEM; }
62
63 for (i = 0; !err && i < count; i++) {
64 addresses[i] = (krb5_address *) malloc (sizeof (krb5_address));
65 if (!addresses[i]) { err = KRB5_CC_NOMEM; }
66
67 if (!err) {
68 addresses[i]->contents = (krb5_octet *) malloc (sizeof (krb5_octet) *
69 in_cc_array[i]->length);
70 if (!addresses[i]->contents) { err = KRB5_CC_NOMEM; }
71 }
72
73 if (!err) {
74 addresses[i]->magic = KV5M_ADDRESS;
75 addresses[i]->addrtype = in_cc_array[i]->type;
76 addresses[i]->length = in_cc_array[i]->length;
77 memcpy (addresses[i]->contents,
78 in_cc_array[i]->data, in_cc_array[i]->length);
79 }
80 }
81
82 if (!err) {
83 addresses[i] = NULL; /* terminator */
84 *out_addresses = addresses;
85 addresses = NULL;
86 }
87
88 if (addresses) { krb5_free_addresses (in_context, addresses); }
89 }
90
91 return err;
92 }
93
94 static krb5_error_code
copy_cc_array_to_authdata(krb5_context in_context,cc_data ** in_cc_array,krb5_authdata *** out_authdata)95 copy_cc_array_to_authdata (krb5_context in_context,
96 cc_data **in_cc_array,
97 krb5_authdata ***out_authdata)
98 {
99 krb5_error_code err = 0;
100
101 if (in_cc_array == NULL) {
102 *out_authdata = NULL;
103
104 } else {
105 unsigned int count, i;
106 krb5_authdata **authdata = NULL;
107
108 /* get length of array */
109 for (count = 0; in_cc_array[count]; count++);
110 authdata = (krb5_authdata **) malloc (sizeof (*authdata) * (count + 1));
111 if (!authdata) { err = KRB5_CC_NOMEM; }
112
113 for (i = 0; !err && i < count; i++) {
114 authdata[i] = (krb5_authdata *) malloc (sizeof (krb5_authdata));
115 if (!authdata[i]) { err = KRB5_CC_NOMEM; }
116
117 if (!err) {
118 authdata[i]->contents = (krb5_octet *) malloc (sizeof (krb5_octet) *
119 in_cc_array[i]->length);
120 if (!authdata[i]->contents) { err = KRB5_CC_NOMEM; }
121 }
122
123 if (!err) {
124 authdata[i]->magic = KV5M_AUTHDATA;
125 authdata[i]->ad_type = in_cc_array[i]->type;
126 authdata[i]->length = in_cc_array[i]->length;
127 memcpy (authdata[i]->contents,
128 in_cc_array[i]->data, in_cc_array[i]->length);
129 }
130 }
131
132 if (!err) {
133 authdata[i] = NULL; /* terminator */
134 *out_authdata = authdata;
135 authdata = NULL;
136 }
137
138 if (authdata) { krb5_free_authdata (in_context, authdata); }
139 }
140
141 return err;
142 }
143
144 static krb5_error_code
copy_addresses_to_cc_array(krb5_context in_context,krb5_address ** in_addresses,cc_data *** out_cc_array)145 copy_addresses_to_cc_array (krb5_context in_context,
146 krb5_address **in_addresses,
147 cc_data ***out_cc_array)
148 {
149 krb5_error_code err = 0;
150
151 if (in_addresses == NULL) {
152 *out_cc_array = NULL;
153
154 } else {
155 unsigned int count, i;
156 cc_data **cc_array = NULL;
157
158 /* get length of array */
159 for (count = 0; in_addresses[count]; count++);
160 cc_array = (cc_data **) malloc (sizeof (*cc_array) * (count + 1));
161 if (!cc_array) { err = KRB5_CC_NOMEM; }
162
163 for (i = 0; !err && i < count; i++) {
164 cc_array[i] = (cc_data *) malloc (sizeof (cc_data));
165 if (!cc_array[i]) { err = KRB5_CC_NOMEM; }
166
167 if (!err) {
168 cc_array[i]->data = malloc (in_addresses[i]->length);
169 if (!cc_array[i]->data) { err = KRB5_CC_NOMEM; }
170 }
171
172 if (!err) {
173 cc_array[i]->type = in_addresses[i]->addrtype;
174 cc_array[i]->length = in_addresses[i]->length;
175 memcpy (cc_array[i]->data, in_addresses[i]->contents, in_addresses[i]->length);
176 }
177 }
178
179 if (!err) {
180 cc_array[i] = NULL; /* terminator */
181 *out_cc_array = cc_array;
182 cc_array = NULL;
183 }
184
185 if (cc_array) { free_cc_array (cc_array); }
186 }
187
188
189 return err;
190 }
191
192 static krb5_error_code
copy_authdata_to_cc_array(krb5_context in_context,krb5_authdata ** in_authdata,cc_data *** out_cc_array)193 copy_authdata_to_cc_array (krb5_context in_context,
194 krb5_authdata **in_authdata,
195 cc_data ***out_cc_array)
196 {
197 krb5_error_code err = 0;
198
199 if (in_authdata == NULL) {
200 *out_cc_array = NULL;
201
202 } else {
203 unsigned int count, i;
204 cc_data **cc_array = NULL;
205
206 /* get length of array */
207 for (count = 0; in_authdata[count]; count++);
208 cc_array = (cc_data **) malloc (sizeof (*cc_array) * (count + 1));
209 if (!cc_array) { err = KRB5_CC_NOMEM; }
210
211 for (i = 0; !err && i < count; i++) {
212 cc_array[i] = (cc_data *) malloc (sizeof (cc_data));
213 if (!cc_array[i]) { err = KRB5_CC_NOMEM; }
214
215 if (!err) {
216 cc_array[i]->data = malloc (in_authdata[i]->length);
217 if (!cc_array[i]->data) { err = KRB5_CC_NOMEM; }
218 }
219
220 if (!err) {
221 cc_array[i]->type = in_authdata[i]->ad_type;
222 cc_array[i]->length = in_authdata[i]->length;
223 memcpy (cc_array[i]->data, in_authdata[i]->contents, in_authdata[i]->length);
224 }
225 }
226
227 if (!err) {
228 cc_array[i] = NULL; /* terminator */
229 *out_cc_array = cc_array;
230 cc_array = NULL;
231 }
232
233 if (cc_array) { free_cc_array (cc_array); }
234 }
235
236
237 return err;
238 }
239
240
241 /*
242 * copy_cc_credentials_to_krb5_creds
243 * - allocate an empty k5 style ticket and copy info from the cc_creds ticket
244 */
245
246 krb5_error_code
copy_cc_cred_union_to_krb5_creds(krb5_context in_context,const cc_credentials_union * in_cred_union,krb5_creds * out_creds)247 copy_cc_cred_union_to_krb5_creds (krb5_context in_context,
248 const cc_credentials_union *in_cred_union,
249 krb5_creds *out_creds)
250 {
251 krb5_error_code err = 0;
252 cc_credentials_v5_t *cv5 = NULL;
253 krb5_int32 offset_seconds = 0, offset_microseconds = 0;
254 krb5_principal client = NULL;
255 krb5_principal server = NULL;
256 char *ticket_data = NULL;
257 char *second_ticket_data = NULL;
258 unsigned char *keyblock_contents = NULL;
259 krb5_address **addresses = NULL;
260 krb5_authdata **authdata = NULL;
261
262 if (in_cred_union->version != cc_credentials_v5) {
263 err = KRB5_CC_NOT_KTYPE;
264 } else {
265 cv5 = in_cred_union->credentials.credentials_v5;
266 }
267
268 #if TARGET_OS_MAC
269 if (!err) {
270 err = krb5_get_time_offsets (in_context, &offset_seconds, &offset_microseconds);
271 }
272 #endif
273
274 if (!err) {
275 err = krb5_parse_name (in_context, cv5->client, &client);
276 }
277
278 if (!err) {
279 err = krb5_parse_name (in_context, cv5->server, &server);
280 }
281
282 if (!err && cv5->keyblock.data) {
283 keyblock_contents = (unsigned char *) malloc (cv5->keyblock.length);
284 if (!keyblock_contents) { err = KRB5_CC_NOMEM; }
285 }
286
287 if (!err && cv5->ticket.data) {
288 ticket_data = (char *) malloc (cv5->ticket.length);
289 if (!ticket_data) { err = KRB5_CC_NOMEM; }
290 }
291
292 if (!err && cv5->second_ticket.data) {
293 second_ticket_data = (char *) malloc (cv5->second_ticket.length);
294 if (!second_ticket_data) { err = KRB5_CC_NOMEM; }
295 }
296
297 if (!err) {
298 /* addresses */
299 err = copy_cc_array_to_addresses (in_context, cv5->addresses, &addresses);
300 }
301
302 if (!err) {
303 /* authdata */
304 err = copy_cc_array_to_authdata (in_context, cv5->authdata, &authdata);
305 }
306
307 if (!err) {
308 /* principals */
309 out_creds->client = client;
310 client = NULL;
311 out_creds->server = server;
312 server = NULL;
313
314 /* copy keyblock */
315 if (cv5->keyblock.data) {
316 memcpy (keyblock_contents, cv5->keyblock.data, cv5->keyblock.length);
317 }
318 out_creds->keyblock.enctype = cv5->keyblock.type;
319 out_creds->keyblock.length = cv5->keyblock.length;
320 out_creds->keyblock.contents = keyblock_contents;
321 keyblock_contents = NULL;
322
323 /* copy times */
324 out_creds->times.authtime = ts_incr(cv5->authtime, offset_seconds);
325 out_creds->times.starttime = ts_incr(cv5->starttime, offset_seconds);
326 out_creds->times.endtime = ts_incr(cv5->endtime, offset_seconds);
327 out_creds->times.renew_till = ts_incr(cv5->renew_till, offset_seconds);
328 out_creds->is_skey = cv5->is_skey;
329 out_creds->ticket_flags = cv5->ticket_flags;
330
331 /* first ticket */
332 if (cv5->ticket.data) {
333 memcpy(ticket_data, cv5->ticket.data, cv5->ticket.length);
334 }
335 out_creds->ticket.length = cv5->ticket.length;
336 out_creds->ticket.data = ticket_data;
337 ticket_data = NULL;
338
339 /* second ticket */
340 if (cv5->second_ticket.data) {
341 memcpy(second_ticket_data, cv5->second_ticket.data, cv5->second_ticket.length);
342 }
343 out_creds->second_ticket.length = cv5->second_ticket.length;
344 out_creds->second_ticket.data = second_ticket_data;
345 second_ticket_data = NULL;
346
347 out_creds->addresses = addresses;
348 addresses = NULL;
349
350 out_creds->authdata = authdata;
351 authdata = NULL;
352
353 /* zero out magic number */
354 out_creds->magic = 0;
355 }
356
357 if (addresses) { krb5_free_addresses (in_context, addresses); }
358 if (authdata) { krb5_free_authdata (in_context, authdata); }
359 if (keyblock_contents) { free (keyblock_contents); }
360 if (ticket_data) { free (ticket_data); }
361 if (second_ticket_data) { free (second_ticket_data); }
362 if (client) { krb5_free_principal (in_context, client); }
363 if (server) { krb5_free_principal (in_context, server); }
364
365 return err;
366 }
367
368 /*
369 * copy_krb5_creds_to_cc_credentials
370 * - analagous to above but in the reverse direction
371 */
372 krb5_error_code
copy_krb5_creds_to_cc_cred_union(krb5_context in_context,krb5_creds * in_creds,cc_credentials_union ** out_cred_union)373 copy_krb5_creds_to_cc_cred_union (krb5_context in_context,
374 krb5_creds *in_creds,
375 cc_credentials_union **out_cred_union)
376 {
377 krb5_error_code err = 0;
378 cc_credentials_union *cred_union = NULL;
379 cc_credentials_v5_t *cv5 = NULL;
380 char *client = NULL;
381 char *server = NULL;
382 unsigned char *ticket_data = NULL;
383 unsigned char *second_ticket_data = NULL;
384 unsigned char *keyblock_data = NULL;
385 krb5_int32 offset_seconds = 0, offset_microseconds = 0;
386 cc_data **cc_address_array = NULL;
387 cc_data **cc_authdata_array = NULL;
388
389 if (out_cred_union == NULL) { err = KRB5_CC_NOMEM; }
390
391 #if TARGET_OS_MAC
392 if (!err) {
393 err = krb5_get_time_offsets (in_context, &offset_seconds, &offset_microseconds);
394 }
395 #endif
396
397 if (!err) {
398 cred_union = (cc_credentials_union *) malloc (sizeof (*cred_union));
399 if (!cred_union) { err = KRB5_CC_NOMEM; }
400 }
401
402 if (!err) {
403 cv5 = (cc_credentials_v5_t *) malloc (sizeof (*cv5));
404 if (!cv5) { err = KRB5_CC_NOMEM; }
405 }
406
407 if (!err) {
408 err = krb5_unparse_name (in_context, in_creds->client, &client);
409 }
410
411 if (!err) {
412 err = krb5_unparse_name (in_context, in_creds->server, &server);
413 }
414
415 if (!err && in_creds->keyblock.contents) {
416 keyblock_data = (unsigned char *) malloc (in_creds->keyblock.length);
417 if (!keyblock_data) { err = KRB5_CC_NOMEM; }
418 }
419
420 if (!err && in_creds->ticket.data) {
421 ticket_data = (unsigned char *) malloc (in_creds->ticket.length);
422 if (!ticket_data) { err = KRB5_CC_NOMEM; }
423 }
424
425 if (!err && in_creds->second_ticket.data) {
426 second_ticket_data = (unsigned char *) malloc (in_creds->second_ticket.length);
427 if (!second_ticket_data) { err = KRB5_CC_NOMEM; }
428 }
429
430 if (!err) {
431 err = copy_addresses_to_cc_array (in_context, in_creds->addresses, &cc_address_array);
432 }
433
434 if (!err) {
435 err = copy_authdata_to_cc_array (in_context, in_creds->authdata, &cc_authdata_array);
436 }
437
438 if (!err) {
439 /* principals */
440 cv5->client = client;
441 client = NULL;
442 cv5->server = server;
443 server = NULL;
444
445 /* copy more fields */
446 if (in_creds->keyblock.contents) {
447 memcpy(keyblock_data, in_creds->keyblock.contents, in_creds->keyblock.length);
448 }
449 cv5->keyblock.type = in_creds->keyblock.enctype;
450 cv5->keyblock.length = in_creds->keyblock.length;
451 cv5->keyblock.data = keyblock_data;
452 keyblock_data = NULL;
453
454 cv5->authtime = ts_incr(in_creds->times.authtime, -offset_seconds);
455 cv5->starttime = ts_incr(in_creds->times.starttime, -offset_seconds);
456 cv5->endtime = ts_incr(in_creds->times.endtime, -offset_seconds);
457 cv5->renew_till = ts_incr(in_creds->times.renew_till, -offset_seconds);
458 cv5->is_skey = in_creds->is_skey;
459 cv5->ticket_flags = in_creds->ticket_flags;
460
461 if (in_creds->ticket.data) {
462 memcpy (ticket_data, in_creds->ticket.data, in_creds->ticket.length);
463 }
464 cv5->ticket.length = in_creds->ticket.length;
465 cv5->ticket.data = ticket_data;
466 ticket_data = NULL;
467
468 if (in_creds->second_ticket.data) {
469 memcpy (second_ticket_data, in_creds->second_ticket.data, in_creds->second_ticket.length);
470 }
471 cv5->second_ticket.length = in_creds->second_ticket.length;
472 cv5->second_ticket.data = second_ticket_data;
473 second_ticket_data = NULL;
474
475 cv5->addresses = cc_address_array;
476 cc_address_array = NULL;
477
478 cv5->authdata = cc_authdata_array;
479 cc_authdata_array = NULL;
480
481 /* Set up the structures to return to the caller */
482 cred_union->version = cc_credentials_v5;
483 cred_union->credentials.credentials_v5 = cv5;
484 cv5 = NULL;
485
486 *out_cred_union = cred_union;
487 cred_union = NULL;
488 }
489
490 if (cc_address_array) { free_cc_array (cc_address_array); }
491 if (cc_authdata_array) { free_cc_array (cc_authdata_array); }
492 if (keyblock_data) { free (keyblock_data); }
493 if (ticket_data) { free (ticket_data); }
494 if (second_ticket_data) { free (second_ticket_data); }
495 if (client) { krb5_free_unparsed_name (in_context, client); }
496 if (server) { krb5_free_unparsed_name (in_context, server); }
497 if (cv5) { free (cv5); }
498 if (cred_union) { free (cred_union); }
499
500 return err;
501 }
502
503 krb5_error_code
cred_union_release(cc_credentials_union * in_cred_union)504 cred_union_release (cc_credentials_union *in_cred_union)
505 {
506 if (in_cred_union) {
507 if (in_cred_union->version == cc_credentials_v5 &&
508 in_cred_union->credentials.credentials_v5) {
509 cc_credentials_v5_t *cv5 = in_cred_union->credentials.credentials_v5;
510
511 /* should use krb5_free_unparsed_name but we have no context */
512 if (cv5->client) { free (cv5->client); }
513 if (cv5->server) { free (cv5->server); }
514
515 if (cv5->keyblock.data) { free (cv5->keyblock.data); }
516 if (cv5->ticket.data) { free (cv5->ticket.data); }
517 if (cv5->second_ticket.data) { free (cv5->second_ticket.data); }
518
519 free_cc_array (cv5->addresses);
520 free_cc_array (cv5->authdata);
521
522 free (cv5);
523
524 }
525 free ((cc_credentials_union *) in_cred_union);
526 }
527
528 return 0;
529 }
530
531 #else /* !USE_CCAPI_V3 */
532 /*
533 * CopyCCDataArrayToK5
534 * - copy and translate the null terminated arrays of data records
535 * used in k5 tickets
536 */
copyCCDataArrayToK5(cc_creds * ccCreds,krb5_creds * v5Creds,char whichArray)537 int copyCCDataArrayToK5(cc_creds *ccCreds, krb5_creds *v5Creds, char whichArray) {
538
539 if (whichArray == kAddressArray) {
540 if (ccCreds->addresses == NULL) {
541 v5Creds->addresses = NULL;
542 } else {
543
544 krb5_address **addrPtr, *addr;
545 cc_data **dataPtr, *data;
546 unsigned int numRecords = 0;
547
548 /* Allocate the array of pointers: */
549 for (dataPtr = ccCreds->addresses; *dataPtr != NULL; numRecords++, dataPtr++) {}
550
551 v5Creds->addresses = (krb5_address **) malloc (sizeof(krb5_address *) * (numRecords + 1));
552 if (v5Creds->addresses == NULL)
553 return ENOMEM;
554
555 /* Fill in the array, allocating the address structures: */
556 for (dataPtr = ccCreds->addresses, addrPtr = v5Creds->addresses; *dataPtr != NULL; addrPtr++, dataPtr++) {
557
558 *addrPtr = (krb5_address *) malloc (sizeof(krb5_address));
559 if (*addrPtr == NULL)
560 return ENOMEM;
561 data = *dataPtr;
562 addr = *addrPtr;
563
564 addr->addrtype = data->type;
565 addr->magic = KV5M_ADDRESS;
566 addr->length = data->length;
567 addr->contents = (krb5_octet *) malloc (sizeof(krb5_octet) * addr->length);
568 if (addr->contents == NULL)
569 return ENOMEM;
570 memmove(addr->contents, data->data, addr->length); /* copy contents */
571 }
572
573 /* Write terminator: */
574 *addrPtr = NULL;
575 }
576 }
577
578 if (whichArray == kAuthDataArray) {
579 if (ccCreds->authdata == NULL) {
580 v5Creds->authdata = NULL;
581 } else {
582 krb5_authdata **authPtr, *auth;
583 cc_data **dataPtr, *data;
584 unsigned int numRecords = 0;
585
586 /* Allocate the array of pointers: */
587 for (dataPtr = ccCreds->authdata; *dataPtr != NULL; numRecords++, dataPtr++) {}
588
589 v5Creds->authdata = (krb5_authdata **) malloc (sizeof(krb5_authdata *) * (numRecords + 1));
590 if (v5Creds->authdata == NULL)
591 return ENOMEM;
592
593 /* Fill in the array, allocating the address structures: */
594 for (dataPtr = ccCreds->authdata, authPtr = v5Creds->authdata; *dataPtr != NULL; authPtr++, dataPtr++) {
595
596 *authPtr = (krb5_authdata *) malloc (sizeof(krb5_authdata));
597 if (*authPtr == NULL)
598 return ENOMEM;
599 data = *dataPtr;
600 auth = *authPtr;
601
602 auth->ad_type = data->type;
603 auth->magic = KV5M_AUTHDATA;
604 auth->length = data->length;
605 auth->contents = (krb5_octet *) malloc (sizeof(krb5_octet) * auth->length);
606 if (auth->contents == NULL)
607 return ENOMEM;
608 memmove(auth->contents, data->data, auth->length); /* copy contents */
609 }
610
611 /* Write terminator: */
612 *authPtr = NULL;
613 }
614 }
615
616 return 0;
617 }
618
619 /*
620 * copyK5DataArrayToCC
621 * - analagous to above, but in the other direction
622 */
copyK5DataArrayToCC(krb5_creds * v5Creds,cc_creds * ccCreds,char whichArray)623 int copyK5DataArrayToCC(krb5_creds *v5Creds, cc_creds *ccCreds, char whichArray)
624 {
625 if (whichArray == kAddressArray) {
626 if (v5Creds->addresses == NULL) {
627 ccCreds->addresses = NULL;
628 } else {
629
630 krb5_address **addrPtr, *addr;
631 cc_data **dataPtr, *data;
632 unsigned int numRecords = 0;
633
634 /* Allocate the array of pointers: */
635 for (addrPtr = v5Creds->addresses; *addrPtr != NULL; numRecords++, addrPtr++) {}
636
637 ccCreds->addresses = (cc_data **) malloc (sizeof(cc_data *) * (numRecords + 1));
638 if (ccCreds->addresses == NULL)
639 return ENOMEM;
640
641 /* Fill in the array, allocating the address structures: */
642 for (dataPtr = ccCreds->addresses, addrPtr = v5Creds->addresses; *addrPtr != NULL; addrPtr++, dataPtr++) {
643
644 *dataPtr = (cc_data *) malloc (sizeof(cc_data));
645 if (*dataPtr == NULL)
646 return ENOMEM;
647 data = *dataPtr;
648 addr = *addrPtr;
649
650 data->type = addr->addrtype;
651 data->length = addr->length;
652 data->data = malloc (sizeof(char) * data->length);
653 if (data->data == NULL)
654 return ENOMEM;
655 memmove(data->data, addr->contents, data->length); /* copy contents */
656 }
657
658 /* Write terminator: */
659 *dataPtr = NULL;
660 }
661 }
662
663 if (whichArray == kAuthDataArray) {
664 if (v5Creds->authdata == NULL) {
665 ccCreds->authdata = NULL;
666 } else {
667 krb5_authdata **authPtr, *auth;
668 cc_data **dataPtr, *data;
669 unsigned int numRecords = 0;
670
671 /* Allocate the array of pointers: */
672 for (authPtr = v5Creds->authdata; *authPtr != NULL; numRecords++, authPtr++) {}
673
674 ccCreds->authdata = (cc_data **) malloc (sizeof(cc_data *) * (numRecords + 1));
675 if (ccCreds->authdata == NULL)
676 return ENOMEM;
677
678 /* Fill in the array, allocating the address structures: */
679 for (dataPtr = ccCreds->authdata, authPtr = v5Creds->authdata; *authPtr != NULL; authPtr++, dataPtr++) {
680
681 *dataPtr = (cc_data *) malloc (sizeof(cc_data));
682 if (*dataPtr == NULL)
683 return ENOMEM;
684 data = *dataPtr;
685 auth = *authPtr;
686
687 data->type = auth->ad_type;
688 data->length = auth->length;
689 data->data = malloc (sizeof(char) * data->length);
690 if (data->data == NULL)
691 return ENOMEM;
692 memmove(data->data, auth->contents, data->length); /* copy contents */
693 }
694
695 /* Write terminator: */
696 *dataPtr = NULL;
697 }
698 }
699
700 return 0;
701 }
702
703 /*
704 * dupcctok5
705 * - allocate an empty k5 style ticket and copy info from the cc_creds ticket
706 */
707
dupCCtoK5(krb5_context context,cc_creds * src,krb5_creds * dest)708 void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest)
709 {
710 krb5_int32 offset_seconds = 0, offset_microseconds = 0;
711 int err;
712
713 /*
714 * allocate and copy
715 * copy all of those damn fields back
716 */
717 err = krb5_parse_name(context, src->client, &(dest->client));
718 err = krb5_parse_name(context, src->server, &(dest->server));
719 if (err) return; /* parsename fails w/o krb5.ini for example */
720
721 /* copy keyblock */
722 dest->keyblock.enctype = src->keyblock.type;
723 dest->keyblock.length = src->keyblock.length;
724 dest->keyblock.contents = (krb5_octet *)malloc(dest->keyblock.length);
725 memcpy(dest->keyblock.contents, src->keyblock.data, dest->keyblock.length);
726
727 /* copy times */
728 #if TARGET_OS_MAC
729 err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds);
730 if (err) return;
731 #endif
732 dest->times.authtime = ts_incr(src->authtime, offset_seconds);
733 dest->times.starttime = ts_incr(src->starttime, offset_seconds);
734 dest->times.endtime = ts_incr(src->endtime, offset_seconds);
735 dest->times.renew_till = ts_incr(src->renew_till, offset_seconds);
736 dest->is_skey = src->is_skey;
737 dest->ticket_flags = src->ticket_flags;
738
739 /* more branching fields */
740 err = copyCCDataArrayToK5(src, dest, kAddressArray);
741 if (err) return;
742
743 dest->ticket.length = src->ticket.length;
744 dest->ticket.data = (char *)malloc(src->ticket.length);
745 memcpy(dest->ticket.data, src->ticket.data, src->ticket.length);
746 dest->second_ticket.length = src->second_ticket.length;
747 (dest->second_ticket).data = ( char *)malloc(src->second_ticket.length);
748 memcpy(dest->second_ticket.data, src->second_ticket.data, src->second_ticket.length);
749
750 /* zero out magic number */
751 dest->magic = 0;
752
753 /* authdata */
754 err = copyCCDataArrayToK5(src, dest, kAuthDataArray);
755 if (err) return;
756
757 return;
758 }
759
760 /*
761 * dupK5toCC
762 * - analagous to above but in the reverse direction
763 */
dupK5toCC(krb5_context context,krb5_creds * creds,cred_union ** cu)764 void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu)
765 {
766 cc_creds *c;
767 int err;
768 krb5_int32 offset_seconds = 0, offset_microseconds = 0;
769
770 if (cu == NULL) return;
771
772 /* allocate the cred_union */
773 *cu = (cred_union *)malloc(sizeof(cred_union));
774 if ((*cu) == NULL)
775 return;
776
777 (*cu)->cred_type = CC_CRED_V5;
778
779 /* allocate creds structure (and install) */
780 c = (cc_creds *)malloc(sizeof(cc_creds));
781 if (c == NULL) return;
782 (*cu)->cred.pV5Cred = c;
783
784 /* convert krb5 principals to flat principals */
785 err = krb5_unparse_name(context, creds->client, &(c->client));
786 err = krb5_unparse_name(context, creds->server, &(c->server));
787 if (err) return;
788
789 /* copy more fields */
790 c->keyblock.type = creds->keyblock.enctype;
791 c->keyblock.length = creds->keyblock.length;
792
793 if (creds->keyblock.contents != NULL) {
794 c->keyblock.data = (unsigned char *)malloc(creds->keyblock.length);
795 memcpy(c->keyblock.data, creds->keyblock.contents, creds->keyblock.length);
796 } else {
797 c->keyblock.data = NULL;
798 }
799
800 #if TARGET_OS_MAC
801 err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds);
802 if (err) return;
803 #endif
804 c->authtime = ts_incr(creds->times.authtime, -offset_seconds);
805 c->starttime = ts_incr(creds->times.starttime, -offset_seconds);
806 c->endtime = ts_incr(creds->times.endtime, -offset_seconds);
807 c->renew_till = ts_incr(creds->times.renew_till, -offset_seconds);
808 c->is_skey = creds->is_skey;
809 c->ticket_flags = creds->ticket_flags;
810
811 err = copyK5DataArrayToCC(creds, c, kAddressArray);
812 if (err) return;
813
814 c->ticket.length = creds->ticket.length;
815 if (creds->ticket.data != NULL) {
816 c->ticket.data = (unsigned char *)malloc(creds->ticket.length);
817 memcpy(c->ticket.data, creds->ticket.data, creds->ticket.length);
818 } else {
819 c->ticket.data = NULL;
820 }
821
822 c->second_ticket.length = creds->second_ticket.length;
823 if (creds->second_ticket.data != NULL) {
824 c->second_ticket.data = (unsigned char *)malloc(creds->second_ticket.length);
825 memcpy(c->second_ticket.data, creds->second_ticket.data, creds->second_ticket.length);
826 } else {
827 c->second_ticket.data = NULL;
828 }
829
830 err = copyK5DataArrayToCC(creds, c, kAuthDataArray);
831 if (err) return;
832
833 return;
834 }
835
836 /* ----- free_cc_cred_union, etc -------------- */
837 /*
838 Since the Kerberos5 library allocates a credentials cache structure
839 (in dupK5toCC() above) with its own memory allocation routines - which
840 may be different than how the CCache allocates memory - the Kerb5 library
841 must have its own version of cc_free_creds() to deallocate it. These
842 functions do that. The top-level function to substitue for cc_free_creds()
843 is krb5_free_cc_cred_union().
844
845 If the CCache library wants to use a cred_union structure created by
846 the Kerb5 library, it should make a deep copy of it to "translate" to its
847 own memory allocation space.
848 */
deep_free_cc_data(cc_data data)849 static void deep_free_cc_data (cc_data data)
850 {
851 if (data.data != NULL)
852 free (data.data);
853 }
854
deep_free_cc_data_array(cc_data ** data)855 static void deep_free_cc_data_array (cc_data** data) {
856
857 unsigned int i;
858
859 if (data == NULL)
860 return;
861
862 for (i = 0; data [i] != NULL; i++) {
863 deep_free_cc_data (*(data [i]));
864 free (data [i]);
865 }
866
867 free (data);
868 }
869
deep_free_cc_v5_creds(cc_creds * creds)870 static void deep_free_cc_v5_creds (cc_creds* creds)
871 {
872 if (creds == NULL)
873 return;
874
875 if (creds -> client != NULL)
876 free (creds -> client);
877 if (creds -> server != NULL)
878 free (creds -> server);
879
880 deep_free_cc_data (creds -> keyblock);
881 deep_free_cc_data (creds -> ticket);
882 deep_free_cc_data (creds -> second_ticket);
883
884 deep_free_cc_data_array (creds -> addresses);
885 deep_free_cc_data_array (creds -> authdata);
886
887 free(creds);
888 }
889
deep_free_cc_creds(cred_union creds)890 static void deep_free_cc_creds (cred_union creds)
891 {
892 if (creds.cred_type == CC_CRED_V5) {
893 deep_free_cc_v5_creds (creds.cred.pV5Cred);
894 }
895 }
896
897 /* top-level exported function */
krb5int_free_cc_cred_union(cred_union ** creds)898 cc_int32 krb5int_free_cc_cred_union (cred_union** creds)
899 {
900 if (creds == NULL)
901 return CC_BAD_PARM;
902
903 if (*creds != NULL) {
904 deep_free_cc_creds (**creds);
905 free (*creds);
906 *creds = NULL;
907 }
908
909 return CC_NOERROR;
910 }
911 #endif
912
913 /*
914 * Utility functions...
915 */
916 static krb5_boolean
times_match(t1,t2)917 times_match(t1, t2)
918 const krb5_ticket_times *t1;
919 const krb5_ticket_times *t2;
920 {
921 if (t1->renew_till) {
922 if (ts_after(t1->renew_till, t2->renew_till))
923 return FALSE; /* this one expires too late */
924 }
925 if (t1->endtime) {
926 if (ts_after(t1->endtime, t2->endtime))
927 return FALSE; /* this one expires too late */
928 }
929 /* only care about expiration on a times_match */
930 return TRUE;
931 }
932
933 static krb5_boolean
times_match_exact(t1,t2)934 times_match_exact (t1, t2)
935 const krb5_ticket_times *t1, *t2;
936 {
937 return (t1->authtime == t2->authtime
938 && t1->starttime == t2->starttime
939 && t1->endtime == t2->endtime
940 && t1->renew_till == t2->renew_till);
941 }
942
943 static krb5_boolean
standard_fields_match(context,mcreds,creds)944 standard_fields_match(context, mcreds, creds)
945 krb5_context context;
946 const krb5_creds *mcreds, *creds;
947 {
948 return (krb5_principal_compare(context, mcreds->client,creds->client) &&
949 krb5_principal_compare(context, mcreds->server,creds->server));
950 }
951
952 /* only match the server name portion, not the server realm portion */
953
954 static krb5_boolean
srvname_match(context,mcreds,creds)955 srvname_match(context, mcreds, creds)
956 krb5_context context;
957 const krb5_creds *mcreds, *creds;
958 {
959 krb5_boolean retval;
960 krb5_principal_data p1, p2;
961
962 retval = krb5_principal_compare(context, mcreds->client,creds->client);
963 if (retval != TRUE)
964 return retval;
965 /*
966 * Hack to ignore the server realm for the purposes of the compare.
967 */
968 p1 = *mcreds->server;
969 p2 = *creds->server;
970 p1.realm = p2.realm;
971 return krb5_principal_compare(context, &p1, &p2);
972 }
973
974
975 static krb5_boolean
authdata_match(mdata,data)976 authdata_match(mdata, data)
977 krb5_authdata *const *mdata, *const *data;
978 {
979 const krb5_authdata *mdatap, *datap;
980
981 if (mdata == data)
982 return TRUE;
983
984 if (mdata == NULL)
985 return *data == NULL;
986
987 if (data == NULL)
988 return *mdata == NULL;
989
990 while ((mdatap = *mdata)
991 && (datap = *data)
992 && mdatap->ad_type == datap->ad_type
993 && mdatap->length == datap->length
994 && !memcmp ((char *) mdatap->contents, (char *) datap->contents,
995 datap->length)) {
996 mdata++;
997 data++;
998 }
999
1000 return !*mdata && !*data;
1001 }
1002
1003 static krb5_boolean
data_match(data1,data2)1004 data_match(data1, data2)
1005 const krb5_data *data1, *data2;
1006 {
1007 if (!data1) {
1008 if (!data2)
1009 return TRUE;
1010 else
1011 return FALSE;
1012 }
1013 if (!data2) return FALSE;
1014
1015 if (data1->length != data2->length)
1016 return FALSE;
1017 else
1018 return memcmp(data1->data, data2->data, data1->length) ? FALSE : TRUE;
1019 }
1020
1021 #define MATCH_SET(bits) (whichfields & bits)
1022 #define flags_match(a,b) (((a) & (b)) == (a))
1023
1024 /* stdccCredsMatch
1025 * - check to see if the creds match based on the whichFields variable
1026 * NOTE: if whichfields is zero we are now comparing 'standard fields.'
1027 * This is the bug that was killing fetch for a
1028 * week. The behaviour is what krb5 expects, however.
1029 */
stdccCredsMatch(krb5_context context,krb5_creds * base,krb5_creds * match,int whichfields)1030 int stdccCredsMatch(krb5_context context, krb5_creds *base,
1031 krb5_creds *match, int whichfields)
1032 {
1033 if (((MATCH_SET(KRB5_TC_MATCH_SRV_NAMEONLY) &&
1034 srvname_match(context, match, base)) ||
1035 standard_fields_match(context, match, base))
1036 &&
1037 (! MATCH_SET(KRB5_TC_MATCH_IS_SKEY) ||
1038 match->is_skey == base->is_skey)
1039 &&
1040 (! MATCH_SET(KRB5_TC_MATCH_FLAGS_EXACT) ||
1041 match->ticket_flags == base->ticket_flags)
1042 &&
1043 (! MATCH_SET(KRB5_TC_MATCH_FLAGS) ||
1044 flags_match(match->ticket_flags, base->ticket_flags))
1045 &&
1046 (! MATCH_SET(KRB5_TC_MATCH_TIMES_EXACT) ||
1047 times_match_exact(&match->times, &base->times))
1048 &&
1049 (! MATCH_SET(KRB5_TC_MATCH_TIMES) ||
1050 times_match(&match->times, &base->times))
1051 &&
1052 (! MATCH_SET(KRB5_TC_MATCH_AUTHDATA) ||
1053 authdata_match (match->authdata, base->authdata))
1054 &&
1055 (! MATCH_SET(KRB5_TC_MATCH_2ND_TKT) ||
1056 data_match (&match->second_ticket, &base->second_ticket))
1057 &&
1058 ((! MATCH_SET(KRB5_TC_MATCH_KTYPE))||
1059 (match->keyblock.enctype == base->keyblock.enctype))
1060 )
1061 return TRUE;
1062 return FALSE;
1063 }
1064
1065 #endif /* defined(_WIN32) || defined(USE_CCAPI) */
1066