3 * utility functions used in implementing the ccache api for krb5
4 * not publicly exported
5 * Frank Dabek, July 1998
11 #if defined(_MSDOS) || defined(_WIN32)
15 #include "stdcc_util.h"
23 * - copy and translate the null terminated arrays of data records
26 int copyCCDataArrayToK5(cc_creds *ccCreds, krb5_creds *v5Creds, char whichArray) {
28 if (whichArray == kAddressArray) {
29 if (ccCreds->addresses == NULL) {
30 v5Creds->addresses = NULL;
33 krb5_address **addrPtr, *addr;
34 cc_data **dataPtr, *data;
35 unsigned int numRecords = 0;
37 /* Allocate the array of pointers: */
38 for (dataPtr = ccCreds->addresses; *dataPtr != NULL; numRecords++, dataPtr++) {}
40 v5Creds->addresses = (krb5_address **) malloc (sizeof(krb5_address *) * (numRecords + 1));
41 if (v5Creds->addresses == NULL)
44 /* Fill in the array, allocating the address structures: */
45 for (dataPtr = ccCreds->addresses, addrPtr = v5Creds->addresses; *dataPtr != NULL; addrPtr++, dataPtr++) {
47 *addrPtr = (krb5_address *) malloc (sizeof(krb5_address));
53 addr->addrtype = data->type;
54 addr->magic = KV5M_ADDRESS;
55 addr->length = data->length;
56 addr->contents = (krb5_octet *) malloc (sizeof(krb5_octet) * addr->length);
57 if (addr->contents == NULL)
59 memmove(addr->contents, data->data, addr->length); /* copy contents */
62 /* Write terminator: */
67 if (whichArray == kAuthDataArray) {
68 if (ccCreds->authdata == NULL) {
69 v5Creds->authdata = NULL;
71 krb5_authdata **authPtr, *auth;
72 cc_data **dataPtr, *data;
73 unsigned int numRecords = 0;
75 /* Allocate the array of pointers: */
76 for (dataPtr = ccCreds->authdata; *dataPtr != NULL; numRecords++, dataPtr++) {}
78 v5Creds->authdata = (krb5_authdata **) malloc (sizeof(krb5_authdata *) * (numRecords + 1));
79 if (v5Creds->authdata == NULL)
82 /* Fill in the array, allocating the address structures: */
83 for (dataPtr = ccCreds->authdata, authPtr = v5Creds->authdata; *dataPtr != NULL; authPtr++, dataPtr++) {
85 *authPtr = (krb5_authdata *) malloc (sizeof(krb5_authdata));
91 auth->ad_type = data->type;
92 auth->magic = KV5M_AUTHDATA;
93 auth->length = data->length;
94 auth->contents = (krb5_octet *) malloc (sizeof(krb5_octet) * auth->length);
95 if (auth->contents == NULL)
97 memmove(auth->contents, data->data, auth->length); /* copy contents */
100 /* Write terminator: */
109 * copyK5DataArrayToCC
110 * - analagous to above, but in the other direction
112 int copyK5DataArrayToCC(krb5_creds *v5Creds, cc_creds *ccCreds, char whichArray)
114 if (whichArray == kAddressArray) {
115 if (v5Creds->addresses == NULL) {
116 ccCreds->addresses = NULL;
119 krb5_address **addrPtr, *addr;
120 cc_data **dataPtr, *data;
121 unsigned int numRecords = 0;
123 /* Allocate the array of pointers: */
124 for (addrPtr = v5Creds->addresses; *addrPtr != NULL; numRecords++, addrPtr++) {}
126 ccCreds->addresses = (cc_data **) malloc (sizeof(cc_data *) * (numRecords + 1));
127 if (ccCreds->addresses == NULL)
130 /* Fill in the array, allocating the address structures: */
131 for (dataPtr = ccCreds->addresses, addrPtr = v5Creds->addresses; *addrPtr != NULL; addrPtr++, dataPtr++) {
133 *dataPtr = (cc_data *) malloc (sizeof(cc_data));
134 if (*dataPtr == NULL)
139 data->type = addr->addrtype;
140 data->length = addr->length;
141 data->data = malloc (sizeof(char) * data->length);
142 if (data->data == NULL)
144 memmove(data->data, addr->contents, data->length); /* copy contents */
147 /* Write terminator: */
152 if (whichArray == kAuthDataArray) {
153 if (v5Creds->authdata == NULL) {
154 ccCreds->authdata = NULL;
156 krb5_authdata **authPtr, *auth;
157 cc_data **dataPtr, *data;
158 unsigned int numRecords = 0;
160 /* Allocate the array of pointers: */
161 for (authPtr = v5Creds->authdata; *authPtr != NULL; numRecords++, authPtr++) {}
163 ccCreds->authdata = (cc_data **) malloc (sizeof(cc_data *) * (numRecords + 1));
164 if (ccCreds->authdata == NULL)
167 /* Fill in the array, allocating the address structures: */
168 for (dataPtr = ccCreds->authdata, authPtr = v5Creds->authdata; *authPtr != NULL; authPtr++, dataPtr++) {
170 *dataPtr = (cc_data *) malloc (sizeof(cc_data));
171 if (*dataPtr == NULL)
176 data->type = auth->ad_type;
177 data->length = auth->length;
178 data->data = malloc (sizeof(char) * data->length);
179 if (data->data == NULL)
181 memmove(data->data, auth->contents, data->length); /* copy contents */
184 /* Write terminator: */
194 * - allocate an empty k5 style ticket and copy info from the cc_creds ticket
197 void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest)
199 krb5_int32 offset_seconds = 0, offset_microseconds = 0;
204 * copy all of those damn fields back
206 err = krb5_parse_name(context, src->client, &(dest->client));
207 err = krb5_parse_name(context, src->server, &(dest->server));
208 if (err) return; /* parsename fails w/o krb5.ini for example */
211 dest->keyblock.enctype = src->keyblock.type;
212 dest->keyblock.length = src->keyblock.length;
213 dest->keyblock.contents = (krb5_octet *)malloc(dest->keyblock.length);
214 memcpy(dest->keyblock.contents, src->keyblock.data, dest->keyblock.length);
218 err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds);
221 dest->times.authtime = src->authtime + offset_seconds;
222 dest->times.starttime = src->starttime + offset_seconds;
223 dest->times.endtime = src->endtime + offset_seconds;
224 dest->times.renew_till = src->renew_till + offset_seconds;
225 dest->is_skey = src->is_skey;
226 dest->ticket_flags = src->ticket_flags;
228 /* more branching fields */
229 err = copyCCDataArrayToK5(src, dest, kAddressArray);
232 dest->ticket.length = src->ticket.length;
233 dest->ticket.data = (char *)malloc(src->ticket.length);
234 memcpy(dest->ticket.data, src->ticket.data, src->ticket.length);
235 dest->second_ticket.length = src->second_ticket.length;
236 (dest->second_ticket).data = ( char *)malloc(src->second_ticket.length);
237 memcpy(dest->second_ticket.data, src->second_ticket.data, src->second_ticket.length);
239 /* zero out magic number */
243 err = copyCCDataArrayToK5(src, dest, kAuthDataArray);
251 * - analagous to above but in the reverse direction
253 void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu)
257 krb5_int32 offset_seconds = 0, offset_microseconds = 0;
259 char *tempname = NULL;
262 if (cu == NULL) return;
264 /* allocate the cred_union */
265 *cu = (cred_union *)malloc(sizeof(cred_union));
269 (*cu)->cred_type = CC_CRED_V5;
271 /* allocate creds structure (and install) */
272 c = (cc_creds *)malloc(sizeof(cc_creds));
273 if (c == NULL) return;
274 (*cu)->cred.pV5Cred = c;
276 /* convert krb5 principals to flat principals */
279 * and make sure the memory for c->client and c->server is on
280 * the system heap with NewPtr for the Mac (krb5_unparse_name
281 * puts it in appl heap with malloc)
283 err = krb5_unparse_name(context, creds->client, &tempname);
284 c->client = malloc(strlen(tempname)+1);
285 if (c->client != NULL)
286 strcpy(c->client,tempname);
290 err = krb5_unparse_name(context, creds->server, &tempname);
291 c->server = malloc(strlen(tempname)+1);
292 if (c->server != NULL)
293 strcpy(c->server,tempname);
296 err = krb5_unparse_name(context, creds->client, &(c->client));
297 err = krb5_unparse_name(context, creds->server, &(c->server));
301 /* copy more fields */
302 c->keyblock.type = creds->keyblock.enctype;
303 c->keyblock.length = creds->keyblock.length;
305 if (creds->keyblock.contents != NULL) {
306 c->keyblock.data = (unsigned char *)malloc(creds->keyblock.length);
307 memcpy(c->keyblock.data, creds->keyblock.contents, creds->keyblock.length);
309 c->keyblock.data = NULL;
313 err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds);
316 c->authtime = creds->times.authtime - offset_seconds;
317 c->starttime = creds->times.starttime - offset_seconds;
318 c->endtime = creds->times.endtime - offset_seconds;
319 c->renew_till = creds->times.renew_till - offset_seconds;
320 c->is_skey = creds->is_skey;
321 c->ticket_flags = creds->ticket_flags;
323 err = copyK5DataArrayToCC(creds, c, kAddressArray);
326 c->ticket.length = creds->ticket.length;
327 if (creds->ticket.data != NULL) {
328 c->ticket.data = (unsigned char *)malloc(creds->ticket.length);
329 memcpy(c->ticket.data, creds->ticket.data, creds->ticket.length);
331 c->ticket.data = NULL;
334 c->second_ticket.length = creds->second_ticket.length;
335 if (creds->second_ticket.data != NULL) {
336 c->second_ticket.data = (unsigned char *)malloc(creds->second_ticket.length);
337 memcpy(c->second_ticket.data, creds->second_ticket.data, creds->second_ticket.length);
339 c->second_ticket.data = NULL;
342 err = copyK5DataArrayToCC(creds, c, kAuthDataArray);
349 * Utility functions...
353 register const krb5_ticket_times *t1;
354 register const krb5_ticket_times *t2;
356 if (t1->renew_till) {
357 if (t1->renew_till > t2->renew_till)
358 return FALSE; /* this one expires too late */
361 if (t1->endtime > t2->endtime)
362 return FALSE; /* this one expires too late */
364 /* only care about expiration on a times_match */
369 times_match_exact (t1, t2)
370 register const krb5_ticket_times *t1, *t2;
372 return (t1->authtime == t2->authtime
373 && t1->starttime == t2->starttime
374 && t1->endtime == t2->endtime
375 && t1->renew_till == t2->renew_till);
379 standard_fields_match(context, mcreds, creds)
380 krb5_context context;
381 register const krb5_creds *mcreds, *creds;
383 return (krb5_principal_compare(context, mcreds->client,creds->client) &&
384 krb5_principal_compare(context, mcreds->server,creds->server));
387 /* only match the server name portion, not the server realm portion */
390 srvname_match(context, mcreds, creds)
391 krb5_context context;
392 register const krb5_creds *mcreds, *creds;
395 krb5_principal_data p1, p2;
397 retval = krb5_principal_compare(context, mcreds->client,creds->client);
401 * Hack to ignore the server realm for the purposes of the compare.
403 p1 = *mcreds->server;
406 return krb5_principal_compare(context, &p1, &p2);
411 authdata_match(mdata, data)
412 krb5_authdata *const *mdata, *const *data;
414 const krb5_authdata *mdatap, *datap;
420 return *data == NULL;
423 return *mdata == NULL;
425 while ((mdatap = *mdata)
427 && mdatap->ad_type == datap->ad_type
428 && mdatap->length == datap->length
429 && !memcmp ((char *) mdatap->contents, (char *) datap->contents,
435 return !*mdata && !*data;
439 data_match(data1, data2)
440 register const krb5_data *data1, *data2;
448 if (!data2) return FALSE;
450 if (data1->length != data2->length)
453 return memcmp(data1->data, data2->data, data1->length) ? FALSE : TRUE;
456 #define MATCH_SET(bits) (whichfields & bits)
457 #define flags_match(a,b) (((a) & (b)) == (a))
460 * - check to see if the creds match based on the whichFields variable
461 * NOTE: if whichfields is zero we are now comparing 'standard fields.'
462 * This is the bug that was killing fetch for a
463 * week. The behaviour is what krb5 expects, however.
465 int stdccCredsMatch(krb5_context context, krb5_creds *base,
466 krb5_creds *match, int whichfields)
468 if (((MATCH_SET(KRB5_TC_MATCH_SRV_NAMEONLY) &&
469 srvname_match(context, match, base)) ||
470 standard_fields_match(context, match, base))
472 (! MATCH_SET(KRB5_TC_MATCH_IS_SKEY) ||
473 match->is_skey == base->is_skey)
475 (! MATCH_SET(KRB5_TC_MATCH_FLAGS_EXACT) ||
476 match->ticket_flags == base->ticket_flags)
478 (! MATCH_SET(KRB5_TC_MATCH_FLAGS) ||
479 flags_match(match->ticket_flags, base->ticket_flags))
481 (! MATCH_SET(KRB5_TC_MATCH_TIMES_EXACT) ||
482 times_match_exact(&match->times, &base->times))
484 (! MATCH_SET(KRB5_TC_MATCH_TIMES) ||
485 times_match(&match->times, &base->times))
487 (! MATCH_SET(KRB5_TC_MATCH_AUTHDATA) ||
488 authdata_match (match->authdata, base->authdata))
490 (! MATCH_SET(KRB5_TC_MATCH_2ND_TKT) ||
491 data_match (&match->second_ticket, &base->second_ticket))
493 ((! MATCH_SET(KRB5_TC_MATCH_KTYPE))||
494 (match->keyblock.enctype == base->keyblock.enctype))
500 /* ----- free_cc_cred_union, etc -------------- */
502 Since the Kerberos5 library allocates a credentials cache structure
503 (in dupK5toCC() above) with its own memory allocation routines - which
504 may be different than how the CCache allocates memory - the Kerb5 library
505 must have its own version of cc_free_creds() to deallocate it. These
506 functions do that. The top-level function to substitue for cc_free_creds()
507 is krb5_free_cc_cred_union().
509 If the CCache library wants to use a cred_union structure created by
510 the Kerb5 library, it should make a deep copy of it to "translate" to its
511 own memory allocation space.
513 static void deep_free_cc_data (cc_data data)
515 if (data.data != NULL)
519 static void deep_free_cc_data_array (cc_data** data) {
526 for (index = 0; data [index] != NULL; index++) {
527 deep_free_cc_data (*(data [index]));
534 static void deep_free_cc_v5_creds (cc_creds* creds)
539 if (creds -> client != NULL)
540 free (creds -> client);
541 if (creds -> server != NULL)
542 free (creds -> server);
544 deep_free_cc_data (creds -> keyblock);
545 deep_free_cc_data (creds -> ticket);
546 deep_free_cc_data (creds -> second_ticket);
548 deep_free_cc_data_array (creds -> addresses);
549 deep_free_cc_data_array (creds -> authdata);
554 static void deep_free_cc_creds (cred_union creds)
556 if (creds.cred_type == CC_CRED_V4) {
557 /* we shouldn't get this, of course */
558 free (creds.cred.pV4Cred);
559 } else if (creds.cred_type == CC_CRED_V5) {
560 deep_free_cc_v5_creds (creds.cred.pV5Cred);
564 /* top-level exported function */
565 cc_int32 krb5_free_cc_cred_union (cred_union** creds)
570 if (*creds != NULL) {
571 deep_free_cc_creds (**creds);