#include <Kerberos/UCCache.h> #include <Kerberos/UKerberos5Context.h> #include <Kerberos/KerberosDebug.h> #include <string.h> #include "ThrowUtils.h" #pragma mark - // Wrappers for ccache functions. Most of them are pretty straigtforward wrappers which // call the function and throw errors UCCacheContext::UCCacheContext (): UCCacheContextAutoPtr () { cc_context_t context; cc_int32 ccErr = cc_initialize (&context, ccapi_version_4, NULL, NULL); ThrowIfCCacheError (ccErr); Reset (context); } cc_time_t UCCacheContext::GetChangeTime () { ThrowIfInvalid (*this); cc_time_t changeTime; cc_int32 ccErr = cc_context_get_change_time (Get (), &changeTime); ThrowIfCCacheError (ccErr); return changeTime; } UCCacheString UCCacheContext::GetDefaultCCacheName () { ThrowIfInvalid (*this); cc_string_t name; cc_int32 ccErr = cc_context_get_default_ccache_name (Get (), &name); ThrowIfCCacheError (ccErr); return UCCacheString (name); } UCCache UCCacheContext::OpenCCache ( const char* inName) { ThrowIfInvalid (*this); cc_ccache_t ccache; cc_int32 ccErr = cc_context_open_ccache (Get (), inName, &ccache); ThrowIfCCacheError (ccErr); return UCCache (ccache); } UCCache UCCacheContext::OpenDefaultCCache () { ThrowIfInvalid (*this); cc_ccache_t ccache; cc_int32 ccErr = cc_context_open_default_ccache (Get (), &ccache); ThrowIfCCacheError (ccErr); return UCCache (ccache); } UCCache UCCacheContext::CreateCCache ( const char* inName, UPrincipal::EVersion inVersion, const char* inPrincipal) { ThrowIfInvalid (*this); cc_ccache_t ccache; cc_int32 ccErr = cc_context_create_ccache (Get(), inName, inVersion, inPrincipal, &ccache); ThrowIfCCacheError (ccErr); return UCCache (ccache); } UCCache UCCacheContext::CreateDefaultCCache ( UPrincipal::EVersion inVersion, const char* inPrincipal) { ThrowIfInvalid (*this); cc_ccache_t ccache; cc_int32 ccErr = cc_context_create_default_ccache (Get(), inVersion, inPrincipal, &ccache); ThrowIfCCacheError (ccErr); return UCCache (ccache); } UCCache UCCacheContext::CreateNewCCache ( UPrincipal::EVersion inVersion, const char* inPrincipal) { ThrowIfInvalid (*this); cc_ccache_t ccache; cc_int32 ccErr = cc_context_create_new_ccache (Get(), inVersion, inPrincipal, &ccache); ThrowIfCCacheError (ccErr); return UCCache (ccache); } UCCacheIterator UCCacheContext::NewCCacheIterator () { ThrowIfInvalid (*this); cc_ccache_iterator_t iterator = NULL; cc_int32 ccErr = cc_context_new_ccache_iterator (Get (), &iterator); ThrowIfCCacheError (ccErr); return UCCacheIterator (iterator); } // Search all ccaches for a principal UCCache UCCacheContext::OpenCCacheForPrincipal ( const UPrincipal& inPrincipal) { UCCacheIterator iterator = NewCCacheIterator (); UCCache ccache; while (iterator.Next (ccache)) { if (ccache.GetCredentialsVersion () == UPrincipal::kerberosV4) { if (ccache.GetPrincipal (UPrincipal::kerberosV4) == inPrincipal) return ccache; } else { if (ccache.GetPrincipal (UPrincipal::kerberosV5) == inPrincipal) return ccache; } } DebugThrow_ (UCCacheLogicError (ccErrCCacheNotFound)); return UCCache (); // silence the warning } bool UCCacheContext::operator == ( const UCCacheContext& inCompareTo) { cc_uint32 equal; cc_int32 err = cc_context_compare (Get (), inCompareTo.Get (), &equal); ThrowIfCCacheError (err); return (equal != 0); } #pragma mark - void UCCache::Destroy () { ThrowIfInvalid (*this); // ccache releases the cc_ccache_t on destroy cc_ccache_destroy (Get ()); Release (); } void UCCache::MoveTo (UCCache& destination) { ThrowIfInvalid (*this); ThrowIfInvalid (destination); // ccache releases the cc_ccache_t on move cc_ccache_move (Get (), destination.Get ()); Release (); } void UCCache::SetDefault () { ThrowIfInvalid (*this); cc_int32 ccErr = cc_ccache_set_default (Get ()); ThrowIfCCacheError (ccErr); } UPrincipal::EVersion UCCache::GetCredentialsVersion () const { ThrowIfInvalid (*this); cc_uint32 version; cc_int32 ccErr = cc_ccache_get_credentials_version (Get (), &version); ThrowIfCCacheError (ccErr); return static_cast <UPrincipal::EVersion> (version); } UCCacheString UCCache::GetName () const { ThrowIfInvalid (*this); cc_string_t name; cc_int32 ccErr = cc_ccache_get_name (Get (), &name); ThrowIfCCacheError (ccErr); return UCCacheString (name); } UPrincipal UCCache::GetPrincipal ( UPrincipal::EVersion inVersion) const { ThrowIfInvalid (*this); cc_string_t principal; cc_int32 ccErr = cc_ccache_get_principal (Get (), inVersion, &principal); ThrowIfCCacheError (ccErr); UCCacheString string (principal); return UPrincipal (static_cast <UPrincipal::EVersion> (inVersion), principal -> data); } void UCCache::SetPrincipal ( UPrincipal::EVersion inVersion, const char* inPrincipal) { ThrowIfInvalid (*this); cc_uint32 ccErr = cc_ccache_set_principal (Get (), inVersion, inPrincipal); ThrowIfCCacheError (ccErr); } // Set the principal for specified versions -- can be both v4 and v5 void UCCache::SetPrincipal ( UPrincipal::EVersion inVersion, UPrincipal& inPrincipal) { cc_uint32 ccErr; ThrowIfInvalid (*this); if (inVersion == UPrincipal::kerberosV4And5) { ccErr = cc_ccache_set_principal (Get (), UPrincipal::kerberosV4, inPrincipal.GetString (UPrincipal::kerberosV4).c_str ()); ThrowIfCCacheError (ccErr); ccErr = cc_ccache_set_principal (Get (), UPrincipal::kerberosV5, inPrincipal.GetString (UPrincipal::kerberosV5).c_str ()); ThrowIfCCacheError (ccErr); } else { ccErr = cc_ccache_set_principal (Get (), inVersion, inPrincipal.GetString (inVersion).c_str ()); ThrowIfCCacheError (ccErr); } } void UCCache::StoreCredentials ( const cc_credentials_union* inCredentials) { ThrowIfInvalid (*this); cc_uint32 ccErr = cc_ccache_store_credentials (Get (), inCredentials); ThrowIfCCacheError (ccErr); } void UCCache::StoreCredentials ( const CREDENTIALS* inCredentials) { ThrowIfInvalid (*this); StCredentialsUnion credentials(*inCredentials); cc_int32 ccErr = cc_ccache_store_credentials (Get (), credentials.Get ()); ThrowIfCCacheError (ccErr); } void UCCache::StoreCredentials ( const krb5_creds* inCredentials) { ThrowIfInvalid (*this); StCredentialsUnion credentials(*inCredentials); cc_int32 ccErr = cc_ccache_store_credentials (Get (), credentials.Get ()); ThrowIfCCacheError (ccErr); } void UCCache::RemoveCredentials ( UCredentials& inCredentials) { ThrowIfInvalid (*this); cc_uint32 ccErr = cc_ccache_remove_credentials (Get (), inCredentials.Get ()); ThrowIfCCacheError (ccErr); } UCredentialsIterator UCCache::NewCredentialsIterator ( UPrincipal::EVersion inVersion) const { ThrowIfInvalid (*this); cc_credentials_iterator_t iterator = NULL; cc_int32 ccErr = cc_ccache_new_credentials_iterator (Get (), &iterator); ThrowIfCCacheError (ccErr); return UCredentialsIterator (iterator, inVersion); } // Search a ccache for credentials for a given service UCredentials UCCache::GetCredentialsForService ( const UPrincipal& inPrincipal, UPrincipal::EVersion inVersion) const { ThrowIfInvalid (*this); UCredentialsIterator iterator = NewCredentialsIterator (inVersion); UCredentials credentials; while (iterator.Next (credentials)) { if (credentials.GetServicePrincipal () == inPrincipal) return credentials; } DebugThrow_ (UCCacheRuntimeError (ccErrCredentialsNotFound)); return UCredentials (); // silence the warning } // Delete credentials for a given service from the ccache void UCCache::DeleteCredentialsForService ( const UPrincipal& inPrincipal, UPrincipal::EVersion inVersion) { ThrowIfInvalid (*this); UCredentialsIterator iterator = NewCredentialsIterator (inVersion); UCredentials theCredentials; while (iterator.Next (theCredentials)) { if (theCredentials.GetServicePrincipal () == inPrincipal) { cc_int32 ccErr = cc_ccache_remove_credentials (Get (), theCredentials.Get ()); ThrowIfCCacheError (ccErr); } } DebugThrow_ (UCCacheLogicError (ccErrCredentialsNotFound)); } bool UCCache::operator == ( const UCCache& inCompareTo) { cc_uint32 equal; cc_int32 err = cc_ccache_compare (Get (), inCompareTo.Get (), &equal); ThrowIfCCacheError (err); return (equal != 0); } #pragma mark - bool UCCacheIterator::Next ( UCCache& ioCCache) { ThrowIfInvalid (*this); cc_ccache_t ccache; cc_int32 ccErr = cc_ccache_iterator_next (Get (), &ccache); if (ccErr == ccIteratorEnd) return false; ThrowIfCCacheError (ccErr); ioCCache = ccache; return true; } #pragma mark - // Copy ccache credentials to v4 CREDENTIALS struct void UCredentials::CopyToV4Credentials ( CREDENTIALS& outCredentials) const { cc_credentials_v4_t* v4creds = GetV4Credentials (); strcpy (outCredentials.service, v4creds -> service); strcpy (outCredentials.instance, v4creds -> service_instance); strcpy (outCredentials.realm, v4creds -> realm); memmove (&outCredentials.session, &v4creds -> session_key, sizeof (des_cblock)); outCredentials.kvno = v4creds -> kvno; outCredentials.ticket_st.length = v4creds -> ticket_size; memmove (outCredentials.ticket_st.dat, v4creds -> ticket, (u_int32_t) v4creds -> ticket_size); outCredentials.issue_date = (int32_t) v4creds -> issue_date; // Fix the lifetime from CCAPI v4 to Kerberos 4 long lifetimes: outCredentials.lifetime = krb_time_to_life (v4creds->issue_date, v4creds->lifetime + v4creds->issue_date); strcpy (outCredentials.pname, v4creds -> principal); strcpy (outCredentials.pinst, v4creds -> principal_instance); outCredentials.address = v4creds -> address; outCredentials.stk_type = (u_int32_t) v4creds -> string_to_key_type; } // Copy ccache credentials to v4 CREDENTIALS struct void UCredentials::CopyToV5Credentials ( krb5_creds& outCredentials) const { UKerberos5Context context; cc_credentials_v5_t* v5creds = GetV5Credentials (); krb5_int32 offset_seconds = 0, offset_microseconds = 0; krb5_error_code v5err; /* * allocate and copy * copy all of those damn fields back */ v5err = krb5_parse_name(context.Get (), v5creds->client, &(outCredentials.client)); if (v5err) { if (v5err == ENOMEM) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } else { DebugThrow_ (std::logic_error ("UCredentials: Principal is not valid")); } } v5err = krb5_parse_name(context.Get (), v5creds->server, &(outCredentials.server)); if (v5err) { if (v5err == ENOMEM) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } else { DebugThrow_ (std::logic_error ("UCredentials: Principal is not valid")); } } /* copy keyblock */ outCredentials.keyblock.enctype = v5creds->keyblock.type; outCredentials.keyblock.length = v5creds->keyblock.length; outCredentials.keyblock.contents = (krb5_octet *) malloc (outCredentials.keyblock.length); if (outCredentials.keyblock.contents == NULL) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } memcpy (outCredentials.keyblock.contents, v5creds->keyblock.data, outCredentials.keyblock.length); /* copy times */ v5err = krb5_get_time_offsets (context.Get (), &offset_seconds, &offset_microseconds); if (v5err) { if (v5err == ENOMEM) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } else { DebugThrow_ (std::logic_error ("UCredentials: Can't get time offsets")); } } outCredentials.times.authtime = v5creds->authtime + offset_seconds; outCredentials.times.starttime = v5creds->starttime + offset_seconds; outCredentials.times.endtime = v5creds->endtime + offset_seconds; outCredentials.times.renew_till = v5creds->renew_till + offset_seconds; outCredentials.is_skey = v5creds->is_skey; outCredentials.ticket_flags = v5creds->ticket_flags; /* more branching fields */ if (v5creds->addresses == NULL) { outCredentials.addresses = NULL; } else { krb5_address **addrPtr, *addr; cc_data **dataPtr, *data; unsigned int numRecords = 0; /* Allocate the array of pointers: */ for (dataPtr = v5creds->addresses; *dataPtr != NULL; numRecords++, dataPtr++) {} outCredentials.addresses = (krb5_address **) malloc (sizeof(krb5_address *) * (numRecords + 1)); if (outCredentials.addresses == NULL) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } /* Fill in the array, allocating the address structures: */ for (dataPtr = v5creds->addresses, addrPtr = outCredentials.addresses; *dataPtr != NULL; addrPtr++, dataPtr++) { *addrPtr = (krb5_address *) malloc (sizeof(krb5_address)); if (*addrPtr == NULL) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } 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) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } memmove(addr->contents, data->data, addr->length); /* copy contents */ } /* Write terminator: */ *addrPtr = NULL; } outCredentials.ticket.length = v5creds->ticket.length; outCredentials.ticket.data = (char *) malloc (v5creds->ticket.length); if (outCredentials.ticket.data == NULL) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } memcpy(outCredentials.ticket.data, v5creds->ticket.data, v5creds->ticket.length); outCredentials.second_ticket.length = v5creds->second_ticket.length; outCredentials.second_ticket.data = (char *) malloc (v5creds->second_ticket.length); if (outCredentials.second_ticket.data == NULL) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } memcpy (outCredentials.second_ticket.data, v5creds->second_ticket.data, v5creds->second_ticket.length); /* zero out magic number */ outCredentials.magic = 0; /* authdata */ if (v5creds->authdata == NULL) { outCredentials.authdata = NULL; } else { krb5_authdata **authPtr, *auth; cc_data **dataPtr, *data; unsigned int numRecords = 0; /* Allocate the array of pointers: */ for (dataPtr = v5creds->authdata; *dataPtr != NULL; numRecords++, dataPtr++) {} outCredentials.authdata = (krb5_authdata **) malloc (sizeof(krb5_authdata *) * (numRecords + 1)); if (outCredentials.authdata == NULL) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } /* Fill in the array, allocating the address structures: */ for (dataPtr = v5creds->authdata, authPtr = outCredentials.authdata; *dataPtr != NULL; authPtr++, dataPtr++) { *authPtr = (krb5_authdata *) malloc (sizeof(krb5_authdata)); if (*authPtr == NULL) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } 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) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } memmove(auth->contents, data->data, auth->length); /* copy contents */ } /* Write terminator: */ *authPtr = NULL; } return; } // Get the appropriate service principal based on the ticket version UPrincipal UCredentials::GetServicePrincipal () const { if (GetVersion () == UPrincipal::kerberosV4) { return UPrincipal ( UPrincipal::kerberosV4, GetV4Credentials () -> service, GetV4Credentials () -> service_instance, GetV4Credentials () -> realm); } else { return UPrincipal ( UPrincipal::kerberosV5, GetV5Credentials () -> server); } } // Get the appropriate client principal based on the ticket version UPrincipal UCredentials::GetClientPrincipal () const { if (GetVersion () == UPrincipal::kerberosV4) { return UPrincipal ( UPrincipal::kerberosV4, GetV4Credentials () -> principal, GetV4Credentials () -> principal_instance, GetV4Credentials () -> realm); } else { return UPrincipal ( UPrincipal::kerberosV5, GetV5Credentials () -> client); } } // Copy out the v4 session key des_cblock& UCredentials::GetV4SessionKey ( des_cblock& outSessionKey) const { memmove (&outSessionKey, &GetV4Credentials () -> session_key, sizeof (des_cblock)); return outSessionKey; } // Get the v4 credentials if appropriate cc_credentials_v4_t* UCredentials::GetV4Credentials () const { ThrowIfInvalid (*this); if (GetVersion () != UPrincipal::kerberosV4) ThrowIfCCacheError (ccErrBadCredentialsVersion); return Get () -> data -> credentials.credentials_v4; } // Get the v5 credentials if appropriate cc_credentials_v5_t* UCredentials::GetV5Credentials () const { ThrowIfInvalid (*this); if (GetVersion () != UPrincipal::kerberosV5) ThrowIfCCacheError (ccErrBadCredentialsVersion); return Get () -> data -> credentials.credentials_v5; } UPrincipal::EVersion UCredentials::GetVersion () const { ThrowIfInvalid (*this); return static_cast <UPrincipal::EVersion> (Get () -> data -> version); } bool UCredentials::operator == ( const UCredentials& inCompareTo) { cc_uint32 equal; cc_int32 err = cc_credentials_compare (Get (), inCompareTo.Get (), &equal); ThrowIfCCacheError (err); return (equal != 0); } #pragma mark - // Initialize from v4 CREDENTIALS struct StCredentialsUnion::StCredentialsUnion ( const CREDENTIALS& inCreds) { mCredentialsUnion.version = cc_credentials_v4; mCredentialsUnion.credentials.credentials_v4 = &mV4Creds; ::strcpy (mV4Creds.principal, inCreds.pname); ::strcpy (mV4Creds.principal_instance, inCreds.pinst); ::strcpy (mV4Creds.service, inCreds.service); ::strcpy (mV4Creds.service_instance, inCreds.instance); ::strcpy (mV4Creds.realm, inCreds.realm); ::memmove (mV4Creds.session_key, inCreds.session, sizeof (des_cblock)); mV4Creds.kvno = inCreds.kvno; mV4Creds.string_to_key_type = inCreds.stk_type; mV4Creds.issue_date = inCreds.issue_date; mV4Creds.address = inCreds.address; // Fix the lifetime to something CCAPI v4 likes: mV4Creds.lifetime = (int) (krb_life_to_time ((unsigned long) inCreds.issue_date, inCreds.lifetime) - inCreds.issue_date); mV4Creds.ticket_size = inCreds.ticket_st.length; ::memmove (mV4Creds.ticket, inCreds.ticket_st.dat, mV4Creds.ticket_size); } // Initialize from v5 creds StCredentialsUnion::StCredentialsUnion ( const krb5_creds& inCreds) { mCredentialsUnion.version = cc_credentials_v5; mCredentialsUnion.credentials.credentials_v5 = &mV5Creds; UKerberos5Context context; char* tempString; krb5_error_code v5err; krb5_int32 offset_seconds, offset_microseconds; // Client: v5err = ::krb5_unparse_name (context.Get (), inCreds.client, &tempString); Assert_ ((v5err == KRB5_PARSE_MALFORMED) || (v5err == ENOMEM) || (v5err == 0)); if (v5err == ENOMEM) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } else if (v5err == KRB5_PARSE_MALFORMED) DebugThrow_ (std::logic_error ("StCredentialsUnion: Principal is not valid")); mV5Creds.client = new char [::strlen(tempString) + 1]; ::strcpy (mV5Creds.client, tempString); ::krb5_free_unparsed_name (context.Get (), tempString); // Server: v5err = ::krb5_unparse_name (context.Get (), inCreds.server, &tempString); Assert_ ((v5err == KRB5_PARSE_MALFORMED) || (v5err == ENOMEM) || (v5err == 0)); if (v5err == ENOMEM) { std::bad_alloc foo; // Mac OS X gcc sucks. You have to do it this stupid way DebugThrow_ (foo); } else if (v5err == KRB5_PARSE_MALFORMED) DebugThrow_ (std::logic_error ("StCredentialsUnion: Principal is not valid")); mV5Creds.server = new char [::strlen(tempString) + 1]; ::strcpy (mV5Creds.server, tempString); ::krb5_free_unparsed_name (context.Get (), tempString); // Keyblock: mV5Creds.keyblock.type = inCreds.keyblock.enctype; mV5Creds.keyblock.length = inCreds.keyblock.length; mV5Creds.keyblock.data = new char [mV5Creds.keyblock.length]; ::memmove(mV5Creds.keyblock.data, inCreds.keyblock.contents, mV5Creds.keyblock.length); // Times: v5err = ::krb5_get_time_offsets(context.Get(), &offset_seconds, &offset_microseconds); Assert_ (v5err == 0); if (v5err != 0) offset_seconds = 0; mV5Creds.authtime = inCreds.times.authtime + offset_seconds; mV5Creds.starttime = inCreds.times.starttime + offset_seconds; mV5Creds.endtime = inCreds.times.endtime + offset_seconds; mV5Creds.renew_till = inCreds.times.renew_till + offset_seconds; // Flags: mV5Creds.is_skey = inCreds.is_skey; mV5Creds.ticket_flags = inCreds.ticket_flags; // Addresses: if (inCreds.addresses == NULL) { mV5Creds.addresses = NULL; } else { krb5_address **addrPtr, *addr; cc_data **dataPtr, *data; u_int32_t numRecords = 0; // Allocate the array of pointers: for (addrPtr = inCreds.addresses; *addrPtr != NULL; numRecords++, addrPtr++) {} mV5Creds.addresses = new cc_data *[numRecords + 1]; // Fill in the array, allocating the address structures: for (dataPtr = mV5Creds.addresses, addrPtr = inCreds.addresses; *addrPtr != NULL; addrPtr++, dataPtr++) { *dataPtr = new cc_data; data = *dataPtr; addr = *addrPtr; data->type = addr->addrtype; data->length = addr->length; data->data = new char [data->length]; ::memmove(data->data, addr->contents, data->length); // copy pointer } // Write terminator: *dataPtr = NULL; } // Ticket: mV5Creds.ticket.length = inCreds.ticket.length; mV5Creds.ticket.data = new char [mV5Creds.ticket.length]; ::memmove(mV5Creds.ticket.data, inCreds.ticket.data, mV5Creds.ticket.length); // Second Ticket: mV5Creds.second_ticket.length = inCreds.second_ticket.length; mV5Creds.second_ticket.data = new char [mV5Creds.second_ticket.length]; ::memmove(mV5Creds.second_ticket.data, inCreds.second_ticket.data, mV5Creds.second_ticket.length); // Authdata: if (inCreds.authdata == NULL) { mV5Creds.authdata = NULL; } else { krb5_authdata **authPtr, *auth; cc_data **dataPtr, *data; u_int32_t numRecords = 0; // Allocate the array of pointers: for (authPtr = inCreds.authdata; *authPtr != NULL; numRecords++, authPtr++) {} mV5Creds.authdata = new cc_data* [numRecords + 1]; // Fill in the array, allocating the address structures: for (dataPtr = mV5Creds.authdata, authPtr = inCreds.authdata; *authPtr != NULL; authPtr++, dataPtr++) { *dataPtr = new cc_data; data = *dataPtr; auth = *authPtr; data->type = auth->ad_type; data->length = auth->length; data->data = new char [data->length]; ::memmove(data->data, auth->contents, data->length); // copy pointer } // Write terminator: *dataPtr = NULL; } } StCredentialsUnion::~StCredentialsUnion () { if (mCredentialsUnion.version == cc_credentials_v5) { // Free the client and server strings: delete [] mV5Creds.client; delete [] mV5Creds.server; // Free the data structures: delete [] static_cast<char *>(mV5Creds.keyblock.data); delete [] static_cast<char *>(mV5Creds.ticket.data); delete [] static_cast<char *>(mV5Creds.second_ticket.data); // Free the addresses: if (mV5Creds.addresses != NULL) { cc_data **dataPtr, *data; for (dataPtr = mV5Creds.addresses; *dataPtr != NULL; dataPtr++) { data = *dataPtr; delete [] static_cast<char *>(data->data); delete data; } delete [] mV5Creds.addresses; } // Free the authdata: if (mV5Creds.authdata != NULL) { cc_data **dataPtr, *data; for (dataPtr = mV5Creds.authdata; *dataPtr != NULL; dataPtr++) { data = *dataPtr; delete [] static_cast<char *>(data->data); delete data; } delete [] mV5Creds.authdata; } } } #pragma mark - // Iterate over credentials of a specific version bool UCredentialsIterator::Next ( UCredentials& ioCredentials) { ThrowIfInvalid (*this); cc_credentials_t credentials; // Must find credentials of the appropriate version for (;;) { cc_int32 ccErr = cc_credentials_iterator_next (Get (), &credentials); if (ccErr == ccIteratorEnd) return false; ThrowIfCCacheError (ccErr); if ((mVersion == UPrincipal::kerberosV4And5) || ((mVersion == UPrincipal::kerberosV4) && (credentials -> data -> version == cc_credentials_v4)) || ((mVersion == UPrincipal::kerberosV5) && (credentials -> data -> version == cc_credentials_v5))) { // Version matches, return UCredentials result (credentials); ioCredentials = result; return true; } else { // Version doesn't match, try again. cc_credentials_release (credentials); } } }