diff options
Diffstat (limited to 'src/lib/krb5/ccache/ccapi/stdcc_util.c')
| -rw-r--r-- | src/lib/krb5/ccache/ccapi/stdcc_util.c | 1071 |
1 files changed, 1071 insertions, 0 deletions
diff --git a/src/lib/krb5/ccache/ccapi/stdcc_util.c b/src/lib/krb5/ccache/ccapi/stdcc_util.c new file mode 100644 index 000000000000..9f44af3d087c --- /dev/null +++ b/src/lib/krb5/ccache/ccapi/stdcc_util.c @@ -0,0 +1,1071 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + * stdcc_util.c + * utility functions used in implementing the ccache api for krb5 + * not publicly exported + * Frank Dabek, July 1998 + */ + +#if defined(_WIN32) || defined(USE_CCAPI) + +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#if defined(_WIN32) +#include <malloc.h> +#endif + +#include "stdcc_util.h" +#include "krb5.h" +#ifdef _WIN32 /* it's part of krb5.h everywhere else */ +#include "kv5m_err.h" +#endif + +#define fieldSize 255 + +#ifdef USE_CCAPI_V3 + + +static void +free_cc_array (cc_data **io_cc_array) +{ + if (io_cc_array) { + unsigned int i; + + for (i = 0; io_cc_array[i]; i++) { + if (io_cc_array[i]->data) { free (io_cc_array[i]->data); } + free (io_cc_array[i]); + } + free (io_cc_array); + } +} + +static krb5_error_code +copy_cc_array_to_addresses (krb5_context in_context, + cc_data **in_cc_array, + krb5_address ***out_addresses) +{ + krb5_error_code err = 0; + + if (in_cc_array == NULL) { + *out_addresses = NULL; + + } else { + unsigned int count, i; + krb5_address **addresses = NULL; + + /* get length of array */ + for (count = 0; in_cc_array[count]; count++); + addresses = (krb5_address **) malloc (sizeof (*addresses) * (count + 1)); + if (!addresses) { err = KRB5_CC_NOMEM; } + + for (i = 0; !err && i < count; i++) { + addresses[i] = (krb5_address *) malloc (sizeof (krb5_address)); + if (!addresses[i]) { err = KRB5_CC_NOMEM; } + + if (!err) { + addresses[i]->contents = (krb5_octet *) malloc (sizeof (krb5_octet) * + in_cc_array[i]->length); + if (!addresses[i]->contents) { err = KRB5_CC_NOMEM; } + } + + if (!err) { + addresses[i]->magic = KV5M_ADDRESS; + addresses[i]->addrtype = in_cc_array[i]->type; + addresses[i]->length = in_cc_array[i]->length; + memcpy (addresses[i]->contents, + in_cc_array[i]->data, in_cc_array[i]->length); + } + } + + if (!err) { + addresses[i] = NULL; /* terminator */ + *out_addresses = addresses; + addresses = NULL; + } + + if (addresses) { krb5_free_addresses (in_context, addresses); } + } + + return err; +} + +static krb5_error_code +copy_cc_array_to_authdata (krb5_context in_context, + cc_data **in_cc_array, + krb5_authdata ***out_authdata) +{ + krb5_error_code err = 0; + + if (in_cc_array == NULL) { + *out_authdata = NULL; + + } else { + unsigned int count, i; + krb5_authdata **authdata = NULL; + + /* get length of array */ + for (count = 0; in_cc_array[count]; count++); + authdata = (krb5_authdata **) malloc (sizeof (*authdata) * (count + 1)); + if (!authdata) { err = KRB5_CC_NOMEM; } + + for (i = 0; !err && i < count; i++) { + authdata[i] = (krb5_authdata *) malloc (sizeof (krb5_authdata)); + if (!authdata[i]) { err = KRB5_CC_NOMEM; } + + if (!err) { + authdata[i]->contents = (krb5_octet *) malloc (sizeof (krb5_octet) * + in_cc_array[i]->length); + if (!authdata[i]->contents) { err = KRB5_CC_NOMEM; } + } + + if (!err) { + authdata[i]->magic = KV5M_AUTHDATA; + authdata[i]->ad_type = in_cc_array[i]->type; + authdata[i]->length = in_cc_array[i]->length; + memcpy (authdata[i]->contents, + in_cc_array[i]->data, in_cc_array[i]->length); + } + } + + if (!err) { + authdata[i] = NULL; /* terminator */ + *out_authdata = authdata; + authdata = NULL; + } + + if (authdata) { krb5_free_authdata (in_context, authdata); } + } + + return err; +} + +static krb5_error_code +copy_addresses_to_cc_array (krb5_context in_context, + krb5_address **in_addresses, + cc_data ***out_cc_array) +{ + krb5_error_code err = 0; + + if (in_addresses == NULL) { + *out_cc_array = NULL; + + } else { + unsigned int count, i; + cc_data **cc_array = NULL; + + /* get length of array */ + for (count = 0; in_addresses[count]; count++); + cc_array = (cc_data **) malloc (sizeof (*cc_array) * (count + 1)); + if (!cc_array) { err = KRB5_CC_NOMEM; } + + for (i = 0; !err && i < count; i++) { + cc_array[i] = (cc_data *) malloc (sizeof (cc_data)); + if (!cc_array[i]) { err = KRB5_CC_NOMEM; } + + if (!err) { + cc_array[i]->data = malloc (in_addresses[i]->length); + if (!cc_array[i]->data) { err = KRB5_CC_NOMEM; } + } + + if (!err) { + cc_array[i]->type = in_addresses[i]->addrtype; + cc_array[i]->length = in_addresses[i]->length; + memcpy (cc_array[i]->data, in_addresses[i]->contents, in_addresses[i]->length); + } + } + + if (!err) { + cc_array[i] = NULL; /* terminator */ + *out_cc_array = cc_array; + cc_array = NULL; + } + + if (cc_array) { free_cc_array (cc_array); } + } + + + return err; +} + +static krb5_error_code +copy_authdata_to_cc_array (krb5_context in_context, + krb5_authdata **in_authdata, + cc_data ***out_cc_array) +{ + krb5_error_code err = 0; + + if (in_authdata == NULL) { + *out_cc_array = NULL; + + } else { + unsigned int count, i; + cc_data **cc_array = NULL; + + /* get length of array */ + for (count = 0; in_authdata[count]; count++); + cc_array = (cc_data **) malloc (sizeof (*cc_array) * (count + 1)); + if (!cc_array) { err = KRB5_CC_NOMEM; } + + for (i = 0; !err && i < count; i++) { + cc_array[i] = (cc_data *) malloc (sizeof (cc_data)); + if (!cc_array[i]) { err = KRB5_CC_NOMEM; } + + if (!err) { + cc_array[i]->data = malloc (in_authdata[i]->length); + if (!cc_array[i]->data) { err = KRB5_CC_NOMEM; } + } + + if (!err) { + cc_array[i]->type = in_authdata[i]->ad_type; + cc_array[i]->length = in_authdata[i]->length; + memcpy (cc_array[i]->data, in_authdata[i]->contents, in_authdata[i]->length); + } + } + + if (!err) { + cc_array[i] = NULL; /* terminator */ + *out_cc_array = cc_array; + cc_array = NULL; + } + + if (cc_array) { free_cc_array (cc_array); } + } + + + return err; +} + + +/* + * copy_cc_credentials_to_krb5_creds + * - allocate an empty k5 style ticket and copy info from the cc_creds ticket + */ + +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) +{ + krb5_error_code err = 0; + cc_credentials_v5_t *cv5 = NULL; + krb5_int32 offset_seconds = 0, offset_microseconds = 0; + krb5_principal client = NULL; + krb5_principal server = NULL; + char *ticket_data = NULL; + char *second_ticket_data = NULL; + unsigned char *keyblock_contents = NULL; + krb5_address **addresses = NULL; + krb5_authdata **authdata = NULL; + + if (in_cred_union->version != cc_credentials_v5) { + err = KRB5_CC_NOT_KTYPE; + } else { + cv5 = in_cred_union->credentials.credentials_v5; + } + +#if TARGET_OS_MAC + if (!err) { + err = krb5_get_time_offsets (in_context, &offset_seconds, &offset_microseconds); + } +#endif + + if (!err) { + err = krb5_parse_name (in_context, cv5->client, &client); + } + + if (!err) { + err = krb5_parse_name (in_context, cv5->server, &server); + } + + if (!err && cv5->keyblock.data) { + keyblock_contents = (unsigned char *) malloc (cv5->keyblock.length); + if (!keyblock_contents) { err = KRB5_CC_NOMEM; } + } + + if (!err && cv5->ticket.data) { + ticket_data = (char *) malloc (cv5->ticket.length); + if (!ticket_data) { err = KRB5_CC_NOMEM; } + } + + if (!err && cv5->second_ticket.data) { + second_ticket_data = (char *) malloc (cv5->second_ticket.length); + if (!second_ticket_data) { err = KRB5_CC_NOMEM; } + } + + if (!err) { + /* addresses */ + err = copy_cc_array_to_addresses (in_context, cv5->addresses, &addresses); + } + + if (!err) { + /* authdata */ + err = copy_cc_array_to_authdata (in_context, cv5->authdata, &authdata); + } + + if (!err) { + /* principals */ + out_creds->client = client; + client = NULL; + out_creds->server = server; + server = NULL; + + /* copy keyblock */ + if (cv5->keyblock.data) { + memcpy (keyblock_contents, cv5->keyblock.data, cv5->keyblock.length); + } + out_creds->keyblock.enctype = cv5->keyblock.type; + out_creds->keyblock.length = cv5->keyblock.length; + out_creds->keyblock.contents = keyblock_contents; + keyblock_contents = NULL; + + /* copy times */ + out_creds->times.authtime = cv5->authtime + offset_seconds; + out_creds->times.starttime = cv5->starttime + offset_seconds; + out_creds->times.endtime = cv5->endtime + offset_seconds; + out_creds->times.renew_till = cv5->renew_till + offset_seconds; + out_creds->is_skey = cv5->is_skey; + out_creds->ticket_flags = cv5->ticket_flags; + + /* first ticket */ + if (cv5->ticket.data) { + memcpy(ticket_data, cv5->ticket.data, cv5->ticket.length); + } + out_creds->ticket.length = cv5->ticket.length; + out_creds->ticket.data = ticket_data; + ticket_data = NULL; + + /* second ticket */ + if (cv5->second_ticket.data) { + memcpy(second_ticket_data, cv5->second_ticket.data, cv5->second_ticket.length); + } + out_creds->second_ticket.length = cv5->second_ticket.length; + out_creds->second_ticket.data = second_ticket_data; + second_ticket_data = NULL; + + out_creds->addresses = addresses; + addresses = NULL; + + out_creds->authdata = authdata; + authdata = NULL; + + /* zero out magic number */ + out_creds->magic = 0; + } + + if (addresses) { krb5_free_addresses (in_context, addresses); } + if (authdata) { krb5_free_authdata (in_context, authdata); } + if (keyblock_contents) { free (keyblock_contents); } + if (ticket_data) { free (ticket_data); } + if (second_ticket_data) { free (second_ticket_data); } + if (client) { krb5_free_principal (in_context, client); } + if (server) { krb5_free_principal (in_context, server); } + + return err; +} + +/* + * copy_krb5_creds_to_cc_credentials + * - analagous to above but in the reverse direction + */ +krb5_error_code +copy_krb5_creds_to_cc_cred_union (krb5_context in_context, + krb5_creds *in_creds, + cc_credentials_union **out_cred_union) +{ + krb5_error_code err = 0; + cc_credentials_union *cred_union = NULL; + cc_credentials_v5_t *cv5 = NULL; + char *client = NULL; + char *server = NULL; + unsigned char *ticket_data = NULL; + unsigned char *second_ticket_data = NULL; + unsigned char *keyblock_data = NULL; + krb5_int32 offset_seconds = 0, offset_microseconds = 0; + cc_data **cc_address_array = NULL; + cc_data **cc_authdata_array = NULL; + + if (out_cred_union == NULL) { err = KRB5_CC_NOMEM; } + +#if TARGET_OS_MAC + if (!err) { + err = krb5_get_time_offsets (in_context, &offset_seconds, &offset_microseconds); + } +#endif + + if (!err) { + cred_union = (cc_credentials_union *) malloc (sizeof (*cred_union)); + if (!cred_union) { err = KRB5_CC_NOMEM; } + } + + if (!err) { + cv5 = (cc_credentials_v5_t *) malloc (sizeof (*cv5)); + if (!cv5) { err = KRB5_CC_NOMEM; } + } + + if (!err) { + err = krb5_unparse_name (in_context, in_creds->client, &client); + } + + if (!err) { + err = krb5_unparse_name (in_context, in_creds->server, &server); + } + + if (!err && in_creds->keyblock.contents) { + keyblock_data = (unsigned char *) malloc (in_creds->keyblock.length); + if (!keyblock_data) { err = KRB5_CC_NOMEM; } + } + + if (!err && in_creds->ticket.data) { + ticket_data = (unsigned char *) malloc (in_creds->ticket.length); + if (!ticket_data) { err = KRB5_CC_NOMEM; } + } + + if (!err && in_creds->second_ticket.data) { + second_ticket_data = (unsigned char *) malloc (in_creds->second_ticket.length); + if (!second_ticket_data) { err = KRB5_CC_NOMEM; } + } + + if (!err) { + err = copy_addresses_to_cc_array (in_context, in_creds->addresses, &cc_address_array); + } + + if (!err) { + err = copy_authdata_to_cc_array (in_context, in_creds->authdata, &cc_authdata_array); + } + + if (!err) { + /* principals */ + cv5->client = client; + client = NULL; + cv5->server = server; + server = NULL; + + /* copy more fields */ + if (in_creds->keyblock.contents) { + memcpy(keyblock_data, in_creds->keyblock.contents, in_creds->keyblock.length); + } + cv5->keyblock.type = in_creds->keyblock.enctype; + cv5->keyblock.length = in_creds->keyblock.length; + cv5->keyblock.data = keyblock_data; + keyblock_data = NULL; + + cv5->authtime = in_creds->times.authtime - offset_seconds; + cv5->starttime = in_creds->times.starttime - offset_seconds; + cv5->endtime = in_creds->times.endtime - offset_seconds; + cv5->renew_till = in_creds->times.renew_till - offset_seconds; + cv5->is_skey = in_creds->is_skey; + cv5->ticket_flags = in_creds->ticket_flags; + + if (in_creds->ticket.data) { + memcpy (ticket_data, in_creds->ticket.data, in_creds->ticket.length); + } + cv5->ticket.length = in_creds->ticket.length; + cv5->ticket.data = ticket_data; + ticket_data = NULL; + + if (in_creds->second_ticket.data) { + memcpy (second_ticket_data, in_creds->second_ticket.data, in_creds->second_ticket.length); + } + cv5->second_ticket.length = in_creds->second_ticket.length; + cv5->second_ticket.data = second_ticket_data; + second_ticket_data = NULL; + + cv5->addresses = cc_address_array; + cc_address_array = NULL; + + cv5->authdata = cc_authdata_array; + cc_authdata_array = NULL; + + /* Set up the structures to return to the caller */ + cred_union->version = cc_credentials_v5; + cred_union->credentials.credentials_v5 = cv5; + cv5 = NULL; + + *out_cred_union = cred_union; + cred_union = NULL; + } + + if (cc_address_array) { free_cc_array (cc_address_array); } + if (cc_authdata_array) { free_cc_array (cc_authdata_array); } + if (keyblock_data) { free (keyblock_data); } + if (ticket_data) { free (ticket_data); } + if (second_ticket_data) { free (second_ticket_data); } + if (client) { krb5_free_unparsed_name (in_context, client); } + if (server) { krb5_free_unparsed_name (in_context, server); } + if (cv5) { free (cv5); } + if (cred_union) { free (cred_union); } + + return err; +} + +krb5_error_code +cred_union_release (cc_credentials_union *in_cred_union) +{ + if (in_cred_union) { + if (in_cred_union->version == cc_credentials_v5 && + in_cred_union->credentials.credentials_v5) { + cc_credentials_v5_t *cv5 = in_cred_union->credentials.credentials_v5; + + /* should use krb5_free_unparsed_name but we have no context */ + if (cv5->client) { free (cv5->client); } + if (cv5->server) { free (cv5->server); } + + if (cv5->keyblock.data) { free (cv5->keyblock.data); } + if (cv5->ticket.data) { free (cv5->ticket.data); } + if (cv5->second_ticket.data) { free (cv5->second_ticket.data); } + + free_cc_array (cv5->addresses); + free_cc_array (cv5->authdata); + + free (cv5); + + } else if (in_cred_union->version == cc_credentials_v4 && + in_cred_union->credentials.credentials_v4) { + free (in_cred_union->credentials.credentials_v4); + } + free ((cc_credentials_union *) in_cred_union); + } + + return 0; +} + +#else /* !USE_CCAPI_V3 */ +/* + * CopyCCDataArrayToK5 + * - copy and translate the null terminated arrays of data records + * used in k5 tickets + */ +int copyCCDataArrayToK5(cc_creds *ccCreds, krb5_creds *v5Creds, char whichArray) { + + if (whichArray == kAddressArray) { + if (ccCreds->addresses == NULL) { + v5Creds->addresses = NULL; + } else { + + krb5_address **addrPtr, *addr; + cc_data **dataPtr, *data; + unsigned int numRecords = 0; + + /* Allocate the array of pointers: */ + for (dataPtr = ccCreds->addresses; *dataPtr != NULL; numRecords++, dataPtr++) {} + + v5Creds->addresses = (krb5_address **) malloc (sizeof(krb5_address *) * (numRecords + 1)); + if (v5Creds->addresses == NULL) + return ENOMEM; + + /* Fill in the array, allocating the address structures: */ + for (dataPtr = ccCreds->addresses, addrPtr = v5Creds->addresses; *dataPtr != NULL; addrPtr++, dataPtr++) { + + *addrPtr = (krb5_address *) malloc (sizeof(krb5_address)); + if (*addrPtr == NULL) + return ENOMEM; + data = *dataPtr; + addr = *addrPtr; + + addr->addrtype = data->type; + addr->magic = KV5M_ADDRESS; + addr->length = data->length; + addr->contents = (krb5_octet *) malloc (sizeof(krb5_octet) * addr->length); + if (addr->contents == NULL) + return ENOMEM; + memmove(addr->contents, data->data, addr->length); /* copy contents */ + } + + /* Write terminator: */ + *addrPtr = NULL; + } + } + + if (whichArray == kAuthDataArray) { + if (ccCreds->authdata == NULL) { + v5Creds->authdata = NULL; + } else { + krb5_authdata **authPtr, *auth; + cc_data **dataPtr, *data; + unsigned int numRecords = 0; + + /* Allocate the array of pointers: */ + for (dataPtr = ccCreds->authdata; *dataPtr != NULL; numRecords++, dataPtr++) {} + + v5Creds->authdata = (krb5_authdata **) malloc (sizeof(krb5_authdata *) * (numRecords + 1)); + if (v5Creds->authdata == NULL) + return ENOMEM; + + /* Fill in the array, allocating the address structures: */ + for (dataPtr = ccCreds->authdata, authPtr = v5Creds->authdata; *dataPtr != NULL; authPtr++, dataPtr++) { + + *authPtr = (krb5_authdata *) malloc (sizeof(krb5_authdata)); + if (*authPtr == NULL) + return ENOMEM; + data = *dataPtr; + auth = *authPtr; + + auth->ad_type = data->type; + auth->magic = KV5M_AUTHDATA; + auth->length = data->length; + auth->contents = (krb5_octet *) malloc (sizeof(krb5_octet) * auth->length); + if (auth->contents == NULL) + return ENOMEM; + memmove(auth->contents, data->data, auth->length); /* copy contents */ + } + + /* Write terminator: */ + *authPtr = NULL; + } + } + + return 0; +} + +/* + * copyK5DataArrayToCC + * - analagous to above, but in the other direction + */ +int copyK5DataArrayToCC(krb5_creds *v5Creds, cc_creds *ccCreds, char whichArray) +{ + if (whichArray == kAddressArray) { + if (v5Creds->addresses == NULL) { + ccCreds->addresses = NULL; + } else { + + krb5_address **addrPtr, *addr; + cc_data **dataPtr, *data; + unsigned int numRecords = 0; + + /* Allocate the array of pointers: */ + for (addrPtr = v5Creds->addresses; *addrPtr != NULL; numRecords++, addrPtr++) {} + + ccCreds->addresses = (cc_data **) malloc (sizeof(cc_data *) * (numRecords + 1)); + if (ccCreds->addresses == NULL) + return ENOMEM; + + /* Fill in the array, allocating the address structures: */ + for (dataPtr = ccCreds->addresses, addrPtr = v5Creds->addresses; *addrPtr != NULL; addrPtr++, dataPtr++) { + + *dataPtr = (cc_data *) malloc (sizeof(cc_data)); + if (*dataPtr == NULL) + return ENOMEM; + data = *dataPtr; + addr = *addrPtr; + + data->type = addr->addrtype; + data->length = addr->length; + data->data = malloc (sizeof(char) * data->length); + if (data->data == NULL) + return ENOMEM; + memmove(data->data, addr->contents, data->length); /* copy contents */ + } + + /* Write terminator: */ + *dataPtr = NULL; + } + } + + if (whichArray == kAuthDataArray) { + if (v5Creds->authdata == NULL) { + ccCreds->authdata = NULL; + } else { + krb5_authdata **authPtr, *auth; + cc_data **dataPtr, *data; + unsigned int numRecords = 0; + + /* Allocate the array of pointers: */ + for (authPtr = v5Creds->authdata; *authPtr != NULL; numRecords++, authPtr++) {} + + ccCreds->authdata = (cc_data **) malloc (sizeof(cc_data *) * (numRecords + 1)); + if (ccCreds->authdata == NULL) + return ENOMEM; + + /* Fill in the array, allocating the address structures: */ + for (dataPtr = ccCreds->authdata, authPtr = v5Creds->authdata; *authPtr != NULL; authPtr++, dataPtr++) { + + *dataPtr = (cc_data *) malloc (sizeof(cc_data)); + if (*dataPtr == NULL) + return ENOMEM; + data = *dataPtr; + auth = *authPtr; + + data->type = auth->ad_type; + data->length = auth->length; + data->data = malloc (sizeof(char) * data->length); + if (data->data == NULL) + return ENOMEM; + memmove(data->data, auth->contents, data->length); /* copy contents */ + } + + /* Write terminator: */ + *dataPtr = NULL; + } + } + + return 0; +} + +/* + * dupcctok5 + * - allocate an empty k5 style ticket and copy info from the cc_creds ticket + */ + +void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest) +{ + krb5_int32 offset_seconds = 0, offset_microseconds = 0; + int err; + + /* + * allocate and copy + * copy all of those damn fields back + */ + err = krb5_parse_name(context, src->client, &(dest->client)); + err = krb5_parse_name(context, src->server, &(dest->server)); + if (err) return; /* parsename fails w/o krb5.ini for example */ + + /* copy keyblock */ + dest->keyblock.enctype = src->keyblock.type; + dest->keyblock.length = src->keyblock.length; + dest->keyblock.contents = (krb5_octet *)malloc(dest->keyblock.length); + memcpy(dest->keyblock.contents, src->keyblock.data, dest->keyblock.length); + + /* copy times */ +#if TARGET_OS_MAC + err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds); + if (err) return; +#endif + dest->times.authtime = src->authtime + offset_seconds; + dest->times.starttime = src->starttime + offset_seconds; + dest->times.endtime = src->endtime + offset_seconds; + dest->times.renew_till = src->renew_till + offset_seconds; + dest->is_skey = src->is_skey; + dest->ticket_flags = src->ticket_flags; + + /* more branching fields */ + err = copyCCDataArrayToK5(src, dest, kAddressArray); + if (err) return; + + dest->ticket.length = src->ticket.length; + dest->ticket.data = (char *)malloc(src->ticket.length); + memcpy(dest->ticket.data, src->ticket.data, src->ticket.length); + dest->second_ticket.length = src->second_ticket.length; + (dest->second_ticket).data = ( char *)malloc(src->second_ticket.length); + memcpy(dest->second_ticket.data, src->second_ticket.data, src->second_ticket.length); + + /* zero out magic number */ + dest->magic = 0; + + /* authdata */ + err = copyCCDataArrayToK5(src, dest, kAuthDataArray); + if (err) return; + + return; +} + +/* + * dupK5toCC + * - analagous to above but in the reverse direction + */ +void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu) +{ + cc_creds *c; + int err; + krb5_int32 offset_seconds = 0, offset_microseconds = 0; + + if (cu == NULL) return; + + /* allocate the cred_union */ + *cu = (cred_union *)malloc(sizeof(cred_union)); + if ((*cu) == NULL) + return; + + (*cu)->cred_type = CC_CRED_V5; + + /* allocate creds structure (and install) */ + c = (cc_creds *)malloc(sizeof(cc_creds)); + if (c == NULL) return; + (*cu)->cred.pV5Cred = c; + + /* convert krb5 principals to flat principals */ + err = krb5_unparse_name(context, creds->client, &(c->client)); + err = krb5_unparse_name(context, creds->server, &(c->server)); + if (err) return; + + /* copy more fields */ + c->keyblock.type = creds->keyblock.enctype; + c->keyblock.length = creds->keyblock.length; + + if (creds->keyblock.contents != NULL) { + c->keyblock.data = (unsigned char *)malloc(creds->keyblock.length); + memcpy(c->keyblock.data, creds->keyblock.contents, creds->keyblock.length); + } else { + c->keyblock.data = NULL; + } + +#if TARGET_OS_MAC + err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds); + if (err) return; +#endif + c->authtime = creds->times.authtime - offset_seconds; + c->starttime = creds->times.starttime - offset_seconds; + c->endtime = creds->times.endtime - offset_seconds; + c->renew_till = creds->times.renew_till - offset_seconds; + c->is_skey = creds->is_skey; + c->ticket_flags = creds->ticket_flags; + + err = copyK5DataArrayToCC(creds, c, kAddressArray); + if (err) return; + + c->ticket.length = creds->ticket.length; + if (creds->ticket.data != NULL) { + c->ticket.data = (unsigned char *)malloc(creds->ticket.length); + memcpy(c->ticket.data, creds->ticket.data, creds->ticket.length); + } else { + c->ticket.data = NULL; + } + + c->second_ticket.length = creds->second_ticket.length; + if (creds->second_ticket.data != NULL) { + c->second_ticket.data = (unsigned char *)malloc(creds->second_ticket.length); + memcpy(c->second_ticket.data, creds->second_ticket.data, creds->second_ticket.length); + } else { + c->second_ticket.data = NULL; + } + + err = copyK5DataArrayToCC(creds, c, kAuthDataArray); + if (err) return; + + return; +} + +/* ----- free_cc_cred_union, etc -------------- */ +/* + Since the Kerberos5 library allocates a credentials cache structure + (in dupK5toCC() above) with its own memory allocation routines - which + may be different than how the CCache allocates memory - the Kerb5 library + must have its own version of cc_free_creds() to deallocate it. These + functions do that. The top-level function to substitue for cc_free_creds() + is krb5_free_cc_cred_union(). + + If the CCache library wants to use a cred_union structure created by + the Kerb5 library, it should make a deep copy of it to "translate" to its + own memory allocation space. +*/ +static void deep_free_cc_data (cc_data data) +{ + if (data.data != NULL) + free (data.data); +} + +static void deep_free_cc_data_array (cc_data** data) { + + unsigned int i; + + if (data == NULL) + return; + + for (i = 0; data [i] != NULL; i++) { + deep_free_cc_data (*(data [i])); + free (data [i]); + } + + free (data); +} + +static void deep_free_cc_v5_creds (cc_creds* creds) +{ + if (creds == NULL) + return; + + if (creds -> client != NULL) + free (creds -> client); + if (creds -> server != NULL) + free (creds -> server); + + deep_free_cc_data (creds -> keyblock); + deep_free_cc_data (creds -> ticket); + deep_free_cc_data (creds -> second_ticket); + + deep_free_cc_data_array (creds -> addresses); + deep_free_cc_data_array (creds -> authdata); + + free(creds); +} + +static void deep_free_cc_creds (cred_union creds) +{ + if (creds.cred_type == CC_CRED_V4) { + /* we shouldn't get this, of course */ + free (creds.cred.pV4Cred); + } else if (creds.cred_type == CC_CRED_V5) { + deep_free_cc_v5_creds (creds.cred.pV5Cred); + } +} + +/* top-level exported function */ +cc_int32 krb5int_free_cc_cred_union (cred_union** creds) +{ + if (creds == NULL) + return CC_BAD_PARM; + + if (*creds != NULL) { + deep_free_cc_creds (**creds); + free (*creds); + *creds = NULL; + } + + return CC_NOERROR; +} +#endif + +/* + * Utility functions... + */ +static krb5_boolean +times_match(t1, t2) + register const krb5_ticket_times *t1; + register const krb5_ticket_times *t2; +{ + if (t1->renew_till) { + if (t1->renew_till > t2->renew_till) + return FALSE; /* this one expires too late */ + } + if (t1->endtime) { + if (t1->endtime > t2->endtime) + return FALSE; /* this one expires too late */ + } + /* only care about expiration on a times_match */ + return TRUE; +} + +static krb5_boolean +times_match_exact (t1, t2) + register const krb5_ticket_times *t1, *t2; +{ + return (t1->authtime == t2->authtime + && t1->starttime == t2->starttime + && t1->endtime == t2->endtime + && t1->renew_till == t2->renew_till); +} + +static krb5_boolean +standard_fields_match(context, mcreds, creds) + krb5_context context; + register const krb5_creds *mcreds, *creds; +{ + return (krb5_principal_compare(context, mcreds->client,creds->client) && + krb5_principal_compare(context, mcreds->server,creds->server)); +} + +/* only match the server name portion, not the server realm portion */ + +static krb5_boolean +srvname_match(context, mcreds, creds) + krb5_context context; + register const krb5_creds *mcreds, *creds; +{ + krb5_boolean retval; + krb5_principal_data p1, p2; + + retval = krb5_principal_compare(context, mcreds->client,creds->client); + if (retval != TRUE) + return retval; + /* + * Hack to ignore the server realm for the purposes of the compare. + */ + p1 = *mcreds->server; + p2 = *creds->server; + p1.realm = p2.realm; + return krb5_principal_compare(context, &p1, &p2); +} + + +static krb5_boolean +authdata_match(mdata, data) + krb5_authdata *const *mdata, *const *data; +{ + const krb5_authdata *mdatap, *datap; + + if (mdata == data) + return TRUE; + + if (mdata == NULL) + return *data == NULL; + + if (data == NULL) + return *mdata == NULL; + + while ((mdatap = *mdata) + && (datap = *data) + && mdatap->ad_type == datap->ad_type + && mdatap->length == datap->length + && !memcmp ((char *) mdatap->contents, (char *) datap->contents, + datap->length)) { + mdata++; + data++; + } + + return !*mdata && !*data; +} + +static krb5_boolean +data_match(data1, data2) + register const krb5_data *data1, *data2; +{ + if (!data1) { + if (!data2) + return TRUE; + else + return FALSE; + } + if (!data2) return FALSE; + + if (data1->length != data2->length) + return FALSE; + else + return memcmp(data1->data, data2->data, data1->length) ? FALSE : TRUE; +} + +#define MATCH_SET(bits) (whichfields & bits) +#define flags_match(a,b) (((a) & (b)) == (a)) + +/* stdccCredsMatch + * - check to see if the creds match based on the whichFields variable + * NOTE: if whichfields is zero we are now comparing 'standard fields.' + * This is the bug that was killing fetch for a + * week. The behaviour is what krb5 expects, however. + */ +int stdccCredsMatch(krb5_context context, krb5_creds *base, + krb5_creds *match, int whichfields) +{ + if (((MATCH_SET(KRB5_TC_MATCH_SRV_NAMEONLY) && + srvname_match(context, match, base)) || + standard_fields_match(context, match, base)) + && + (! MATCH_SET(KRB5_TC_MATCH_IS_SKEY) || + match->is_skey == base->is_skey) + && + (! MATCH_SET(KRB5_TC_MATCH_FLAGS_EXACT) || + match->ticket_flags == base->ticket_flags) + && + (! MATCH_SET(KRB5_TC_MATCH_FLAGS) || + flags_match(match->ticket_flags, base->ticket_flags)) + && + (! MATCH_SET(KRB5_TC_MATCH_TIMES_EXACT) || + times_match_exact(&match->times, &base->times)) + && + (! MATCH_SET(KRB5_TC_MATCH_TIMES) || + times_match(&match->times, &base->times)) + && + (! MATCH_SET(KRB5_TC_MATCH_AUTHDATA) || + authdata_match (match->authdata, base->authdata)) + && + (! MATCH_SET(KRB5_TC_MATCH_2ND_TKT) || + data_match (&match->second_ticket, &base->second_ticket)) + && + ((! MATCH_SET(KRB5_TC_MATCH_KTYPE))|| + (match->keyblock.enctype == base->keyblock.enctype)) + ) + return TRUE; + return FALSE; +} + +#endif /* defined(_WIN32) || defined(USE_CCAPI) */ |
