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