KLCCacheManagement.c [plain text]
typedef struct OpaqueKLCCache {
krb5_context context;
krb5_ccache cache;
} CCache;
#pragma mark -
static pthread_mutex_t gUnusedContextMutex = PTHREAD_MUTEX_INITIALIZER;
krb5_context gUnusedContext = NULL;
static KLStatus __KLGetUnusedKerberos5Context (krb5_context *outContext)
{
KLStatus err = klNoErr;
if (gUnusedContext == NULL) {
KLStatus lockErr = err = pthread_mutex_lock (&gUnusedContextMutex);
if (!err) {
err = krb5_init_context (&gUnusedContext);
}
if (!lockErr) { pthread_mutex_unlock (&gUnusedContextMutex); }
}
if (!err) {
*outContext = gUnusedContext;
}
return KLError_ (err);
}
#pragma mark -
#pragma mark -- Local Address Management --
#pragma mark -
static pthread_mutex_t gAddressesChangeTimeMutex = PTHREAD_MUTEX_INITIALIZER;
krb5_address** gAddresses = NULL;
KLTime gAddressChangeTime = 0;
static KLStatus __KLSetAddresses (krb5_address **inAddresses,
KLTime *outNewChangeTime)
{
KLStatus lockErr = pthread_mutex_lock (&gAddressesChangeTimeMutex);
KLStatus err = lockErr;
krb5_context context = NULL;
if (!err) {
err = __KLGetUnusedKerberos5Context (&context);
}
if (!err) {
if (gAddresses != NULL) { krb5_free_addresses (context, gAddresses); }
gAddresses = inAddresses;
gAddressChangeTime = time (NULL);
if (outNewChangeTime != NULL) { *outNewChangeTime = gAddressChangeTime; }
}
if (!lockErr) { pthread_mutex_unlock (&gAddressesChangeTimeMutex); }
return KLError_ (err);
}
static KLStatus __KLGetAddresses (krb5_address ***outAddresses)
{
KLStatus lockErr = pthread_mutex_lock (&gAddressesChangeTimeMutex);
KLStatus err = lockErr;
if (outAddresses == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
*outAddresses = gAddresses;
}
if (!lockErr) { pthread_mutex_unlock (&gAddressesChangeTimeMutex); }
return KLError_ (err);
}
static KLStatus __KLAddressIsValid (krb5_context inContext,
krb5_address *inAddress)
{
KLStatus err = klNoErr;
krb5_address **addresses = NULL;
krb5_context context = NULL;
if (inAddress == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = __KLGetUnusedKerberos5Context (&context);
}
if (!err) {
__KLCheckAddresses ();
}
if (!err) {
err = __KLGetAddresses (&addresses);
}
if (!err) {
if ((addresses != NULL) && (addresses[0] != NULL)) {
if (krb5_address_search (context, inAddress, addresses) != TRUE) {
err = KLError_ (klCredentialsBadAddressErr);
}
}
}
return KLError_ (err);
}
KLTime __KLCheckAddresses ()
{
KLStatus err = klNoErr;
krb5_context context = NULL;
krb5_address **oldAddresses = NULL;
krb5_address **newAddresses = NULL;
KLIndex i;
KLTime newChangeTime = 0;
if (!err) {
err = __KLGetUnusedKerberos5Context (&context);
}
if (!err) {
err = __KLGetAddresses (&oldAddresses);
}
if (!err) {
err = krb5_os_localaddr (context, &newAddresses);
if (err) { newAddresses = NULL; err = klNoErr; } }
if (!err) {
KLBoolean addressesChanged = false;
if (oldAddresses == NULL || newAddresses == NULL) {
addressesChanged = (oldAddresses != newAddresses);
} else {
for (i = 0; newAddresses[i] != NULL && !addressesChanged; i++) {
if (krb5_address_search (context, newAddresses[i], oldAddresses) == false) {
addressesChanged = true;
}
}
for (i = 0; oldAddresses[i] != NULL && !addressesChanged; i++) {
if (krb5_address_search (context, oldAddresses[i], newAddresses) == false) {
addressesChanged = true;
}
}
}
if (addressesChanged) {
err = __KLSetAddresses (newAddresses, &newChangeTime);
if (!err) {
dprintf ("__KLCheckAddresses(): ADDRESS CHANGED, returning new time %d", newChangeTime);
newAddresses = NULL; }
}
}
if (err) {
dprintf ("__KLCheckAddresses(): got fatal error %d (%s)", err, error_message (err));
}
if (newAddresses != NULL) { krb5_free_addresses (context, newAddresses); }
return err ? 0xFFFFFFFF : newChangeTime;
}
KLStatus __KLFreeAddressList ()
{
return KLError_ (__KLSetAddresses (NULL, NULL));
}
#pragma mark -
#pragma mark -- Credentials --
#pragma mark -
static KLStatus __KLV5CredsAreValid (krb5_context inContext,
krb5_creds *inV5Creds)
{
KLStatus err = klNoErr;
krb5_int32 now = 0;
if (inContext == NULL) { err = KLError_ (klParameterErr); }
if (inV5Creds == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
krb5_int32 usec;
err = krb5_us_timeofday (inContext, &now, &usec);
}
if (!err) {
if (inV5Creds->times.endtime <= now) {
err = KLError_ (klCredentialsExpiredErr);
}
}
if (!err) {
if ((inV5Creds->ticket_flags & TKT_FLG_POSTDATED) &&
(inV5Creds->ticket_flags & TKT_FLG_INVALID)) {
err = KLError_ (klCredentialsNeedValidationErr);
}
}
if (!err) {
if (inV5Creds->addresses != NULL) { krb5_address **addressPtr = inV5Creds->addresses;
for (; *addressPtr != NULL; *addressPtr++) {
err = __KLAddressIsValid (inContext, *addressPtr);
if (!err) { break; } }
}
}
return KLError_ (err);
}
#pragma mark -
#pragma mark -- krb5_ccaches --
#pragma mark -
static KLStatus __KLGetCCacheResolveName (char *inCCacheType,
char *inCCacheName,
char **outResolveName)
{
KLStatus err = klNoErr;
char *resolveName = NULL;
if (inCCacheType == NULL) { err = KLError_ (klParameterErr); }
if (inCCacheName == NULL) { err = KLError_ (klParameterErr); }
if (outResolveName == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = __KLCreateString (inCCacheName, &resolveName);
if (!err) {
err = __KLAddPrefixToString (":", &resolveName);
}
if (!err) {
err = __KLAddPrefixToString (inCCacheType, &resolveName);
}
}
if (!err) {
*outResolveName = resolveName;
resolveName = NULL;
}
if (resolveName != NULL) { KLDisposeString (resolveName); }
return KLError_ (err);
}
static KLStatus __KLGetCCacheTypeAndName (krb5_context inContext,
krb5_ccache inCCache,
char **outCCacheType,
char **outCCacheName)
{
KLStatus err = klNoErr;
char *type = NULL;
char *name = NULL;
if (inContext == NULL) { err = KLError_ (klParameterErr); }
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
const char *v5Type = NULL;
v5Type = krb5_cc_get_type (inContext, inCCache);
if (v5Type == NULL) { err = KLError_ (klCacheDoesNotExistErr); }
if (!err) {
err = __KLCreateString (v5Type, &type);
}
}
if (!err) {
const char *v5Name = NULL;
v5Name = krb5_cc_get_name (inContext, inCCache);
if (v5Name == NULL) { err = KLError_ (klCacheDoesNotExistErr); }
if (!err) {
err = __KLCreateString (v5Name, &name);
}
}
if (!err) {
if (outCCacheType != NULL) {
*outCCacheType = type;
type = NULL;
}
if (outCCacheName != NULL) {
*outCCacheName = name;
name = NULL;
}
}
if (type != NULL) { KLDisposeString (type); }
if (name != NULL) { KLDisposeString (name); }
return KLError_ (err);
}
#pragma mark -
static KLBoolean __KLKrb5CCacheIsCCAPICCache (krb5_context inContext,
krb5_ccache inCCache)
{
KLStatus err = klNoErr;
char *type = NULL;
KLBoolean isAPICCache = FALSE;
if (inContext == NULL) { err = KLError_ (klParameterErr); }
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = __KLGetCCacheTypeAndName (inContext, inCCache, &type, NULL);
}
if (!err) {
if (strcmp (type, "API") == 0) {
isAPICCache = TRUE;
}
}
if (type != NULL) { KLDisposeString (type); }
return isAPICCache;
}
static KLStatus __KLGetCCAPICCacheForKrb5CCache (krb5_context inContext,
krb5_ccache inCCache,
cc_ccache_t *outCCache)
{
KLStatus err = klNoErr;
char *name = NULL;
cc_context_t cc_context = NULL;
if (inContext == NULL) { err = KLError_ (klParameterErr); }
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (outCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
if (!__KLKrb5CCacheIsCCAPICCache (inContext, inCCache)) { err = KLError_ (klParameterErr); }
}
if (!err) {
err = __KLGetCCacheTypeAndName (inContext, inCCache, NULL, &name);
}
if (!err) {
err = cc_initialize (&cc_context, ccapi_version_4, NULL, NULL);
}
if (!err) {
err = cc_context_open_ccache (cc_context, name, outCCache);
if (err == ccErrCCacheNotFound || err == ccErrBadName) {
err = KLError_ (klCacheDoesNotExistErr);
}
}
if (name != NULL) { KLDisposeString (name); }
if (cc_context != NULL) { cc_context_release (cc_context); }
return KLError_ (err);
}
static KLStatus __KLGetKrb5CCacheForCCAPICCache (krb5_context inContext,
cc_ccache_t inCCache,
krb5_ccache *outCCache)
{
KLStatus err = klNoErr;
cc_string_t name = NULL;
char *resolveName = NULL;
if (inContext == NULL) { err = KLError_ (klParameterErr); }
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (outCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = cc_ccache_get_name (inCCache, &name);
}
if (!err) {
err = __KLGetCCacheResolveName ("API", (char *) name->data, &resolveName);
}
if (!err) {
err = krb5_cc_resolve (inContext, resolveName, outCCache);
}
if (name != NULL) { cc_string_release (name); }
if (resolveName != NULL) { KLDisposeString (resolveName); }
return KLError_ (err);
}
#pragma mark -
static KLStatus __KLCloseKrb5CCache (krb5_context inContext, krb5_ccache inCCache)
{
KLStatus err = klNoErr;
if (inContext == NULL) { err = KLError_ (klParameterErr); }
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = krb5_cc_close (inContext, inCCache);
}
return KLError_ (err);
}
static KLStatus __KLDestroyKrb5CCache (krb5_context inContext, krb5_ccache inCCache)
{
KLStatus err = klNoErr;
if (inContext == NULL) { err = KLError_ (klParameterErr); }
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = krb5_cc_destroy (inContext, inCCache);
}
return KLError_ (err);
}
#pragma mark -
static KLBoolean __KLKrb5CCachesAreEqual (krb5_context inContextA,
krb5_ccache inCCacheA,
krb5_context inContextB,
krb5_ccache inCCacheB)
{
KLStatus err = klNoErr;
KLBoolean equal = FALSE;
char *typeA = NULL;
char *nameA = NULL;
char *typeB = NULL;
char *nameB = NULL;
if (inContextA == NULL) { err = KLError_ (klParameterErr); }
if (inCCacheA == NULL) { err = KLError_ (klParameterErr); }
if (inContextB == NULL) { err = KLError_ (klParameterErr); }
if (inCCacheB == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = __KLGetCCacheTypeAndName (inContextA, inCCacheA, &typeA, &nameA);
}
if (!err) {
err = __KLGetCCacheTypeAndName (inContextB, inCCacheB, &typeB, &nameB);
}
if (!err) {
if ((strcmp (typeA, typeB) == 0) && (strcmp (nameA, nameB) == 0)) {
equal = TRUE;
}
}
if (typeA != NULL) { KLDisposeString (typeA); }
if (nameA != NULL) { KLDisposeString (nameA); }
if (typeB != NULL) { KLDisposeString (typeB); }
if (nameB != NULL) { KLDisposeString (nameB); }
return equal;
}
static KLBoolean __KLKrb5CCacheExists (krb5_context inContext, krb5_ccache inCCache)
{
KLStatus err = klNoErr;
krb5_principal principal = NULL;
if (inContext == NULL) { err = KLError_ (klParameterErr); }
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = krb5_cc_get_principal (inContext, inCCache, &principal);
}
if (principal != NULL) { krb5_free_principal (inContext, principal); }
return !KLError_ (err);
}
#pragma mark -
#pragma mark -- KLCCache Creation/Destruction --
#pragma mark -
static KLStatus __KLStoreKerberos5CredentialsInCCache (KLPrincipal inPrincipal,
krb5_creds *inV5Creds,
KLCCache inCCache)
{
KLStatus err = klNoErr;
krb5_principal principal = NULL;
if (inPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (inV5Creds == NULL) { err = KLError_ (klParameterErr); }
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
principal = __KLPrincipalGetKerberos5Principal (inPrincipal);
if (principal == NULL) { err = KLError_ (klParameterErr); }
}
if (!err) {
err = krb5_cc_initialize (inCCache->context, inCCache->cache, principal);
}
if (!err) {
err = krb5_cc_store_cred (inCCache->context, inCCache->cache, inV5Creds);
}
return KLError_ (err);
}
#pragma mark -
static KLStatus __KLCreateNewCCAPICCache (KLPrincipal inPrincipal,
krb5_context inV5Context,
KLCCache *outCCache)
{
KLStatus err = klNoErr;
KLCCache ccache = NULL;
if (inPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (outCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
ccache = (KLCCache) calloc (1, sizeof (CCache));
if (ccache == NULL) { err = KLError_ (klMemFullErr); }
}
if (!err) {
err = krb5_copy_context (inV5Context, &ccache->context);
}
if (!err) {
err = krb5_cc_new_unique (ccache->context, "API", NULL, &ccache->cache);
}
if (!err) {
err = krb5_cc_initialize (ccache->context, ccache->cache,
__KLPrincipalGetKerberos5Principal (inPrincipal));
}
if (!err) {
*outCCache = ccache;
} else {
if (ccache != NULL) { __KLDestroyCCache (ccache); }
}
return KLError_ (err);
}
KLStatus __KLCreateNewCCacheWithCredentials (KLPrincipal inPrincipal,
krb5_context inV5Context,
krb5_creds *inV5Creds,
KLCCache *outCCache)
{
KLStatus err = klNoErr;
KLCCache ccache = NULL;
if (inPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (outCCache == NULL) { err = KLError_ (klParameterErr); }
if (inV5Creds == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = __KLCreateNewCCAPICCache (inPrincipal, inV5Context, &ccache);
}
if (!err && (inV5Creds != NULL)) {
err = __KLStoreKerberos5CredentialsInCCache (inPrincipal, inV5Creds, ccache);
}
if (!err) {
*outCCache = ccache;
} else {
if (ccache != NULL) { __KLDestroyCCache (ccache); }
}
return KLError_ (err);
}
KLStatus __KLGetCCacheByName (const char *inCacheName,
KLCCache *outCCache)
{
KLStatus err = klNoErr;
KLCCache ccache = NULL;
if (inCacheName == NULL) { err = KLError_ (klParameterErr); }
if (outCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
ccache = (KLCCache) calloc (1, sizeof (CCache));
if (ccache == NULL) { err = KLError_ (klMemFullErr); }
}
if (!err) {
err = krb5_init_context (&ccache->context);
}
if (!err) {
err = krb5_cc_resolve (ccache->context, inCacheName, &ccache->cache);
}
if (!err) {
*outCCache = ccache;
ccache = NULL;
}
if (ccache != NULL) { __KLCloseCCache (ccache); }
return KLError_ (err);
}
KLStatus __KLGetSystemDefaultCCache (KLCCache *outCCache)
{
KLStatus err = klNoErr;
KLCCache ccache = NULL;
if (outCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
ccache = (KLCCache) calloc (1, sizeof (CCache));
if (ccache == NULL) { err = KLError_ (klMemFullErr); }
}
if (!err) {
err = krb5_init_context (&ccache->context);
}
if (!err) {
err = krb5_cc_default (ccache->context, &ccache->cache);
}
if (!err) {
err = __KLCCacheExists (ccache); if (err) { err = KLError_ (klSystemDefaultDoesNotExistErr); }
}
if (!err) {
*outCCache = ccache;
} else {
if (ccache != NULL) { __KLCloseCCache (ccache); }
}
return KLError_ (err);
}
static KLStatus __KLGetCCAPICCacheForPrincipal (KLPrincipal inPrincipal, krb5_context inContext, krb5_ccache *outCCache)
{
KLStatus err = klNoErr;
KLBoolean found = FALSE;
char *principalV5String = NULL;
cc_context_t cc_context = NULL;
cc_ccache_iterator_t iterator = NULL;
krb5_ccache ccache = NULL;
if (inPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (inContext == NULL) { err = KLError_ (klParameterErr); }
if (outCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = cc_initialize (&cc_context, ccapi_version_4, NULL, NULL);
}
if (!err) {
err = cc_context_new_ccache_iterator (cc_context, &iterator);
}
while (!err && !found) {
cc_ccache_t cc_ccache = NULL;
krb5_principal ccachePrincipal = NULL;
err = cc_ccache_iterator_next (iterator, &cc_ccache);
if (!err) {
err = __KLGetKrb5CCacheForCCAPICCache (inContext, cc_ccache, &ccache);
}
if (!err && (krb5_cc_get_principal (inContext, ccache, &ccachePrincipal) == 0)) {
found = krb5_principal_compare (inContext,
__KLPrincipalGetKerberos5Principal (inPrincipal),
ccachePrincipal);
}
if (ccachePrincipal != NULL) { krb5_free_principal (inContext, ccachePrincipal); }
if (cc_ccache != NULL) { cc_ccache_release (cc_ccache); }
}
if ((err == ccIteratorEnd) || (err == ccErrCCacheNotFound) || (err == ccErrBadName)) {
err = KLError_ (klPrincipalDoesNotExistErr);
}
if (!err) {
*outCCache = ccache;
} else {
if (ccache != NULL) { __KLCloseKrb5CCache (inContext, ccache); }
}
if (principalV5String != NULL) { KLDisposeString (principalV5String); }
if (iterator != NULL) { cc_ccache_iterator_release (iterator); }
if (cc_context != NULL) { cc_context_release (cc_context); }
return KLError_ (err);
}
KLStatus __KLGetFirstCCacheForPrincipal (KLPrincipal inPrincipal,
KLCCache *outCCache)
{
KLStatus err = klNoErr;
KLCCache ccache = NULL;
if (inPrincipal == NULL) { err = KLError_ (klParameterErr); }
if (outCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
ccache = (KLCCache) calloc (1, sizeof (CCache));
if (ccache == NULL) { err = KLError_ (klMemFullErr); }
}
if (!err) {
err = krb5_init_context (&ccache->context);
}
if (!err) {
char *environmentName = getenv ("KRB5CCNAME");
krb5_ccache defaultCCache = NULL;
if ((environmentName != NULL) && (krb5_cc_default (ccache->context, &defaultCCache) == klNoErr)) {
krb5_principal defaultPrincipal = NULL;
if (krb5_cc_get_principal (ccache->context, defaultCCache, &defaultPrincipal) == klNoErr) {
if (krb5_principal_compare (ccache->context, defaultPrincipal,
__KLPrincipalGetKerberos5Principal (inPrincipal))) {
ccache->cache = defaultCCache;
defaultCCache = NULL; }
}
if (defaultPrincipal != NULL) { krb5_free_principal (ccache->context, defaultPrincipal); }
}
if (defaultCCache != NULL) { __KLCloseKrb5CCache (ccache->context, defaultCCache); }
}
if (!err && (ccache->cache == NULL)) {
err = __KLGetCCAPICCacheForPrincipal (inPrincipal, ccache->context, &ccache->cache);
}
if (!err) {
*outCCache = ccache;
} else {
if (ccache != NULL) { __KLCloseCCache (ccache); }
}
return KLError_ (err);
}
KLStatus __KLCloseCCache (KLCCache inCCache)
{
KLStatus err = klNoErr;
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
if (inCCache->cache != NULL) { __KLCloseKrb5CCache (inCCache->context, inCCache->cache); }
if (inCCache->context != NULL) { krb5_free_context (inCCache->context); }
free (inCCache);
}
return KLError_ (err);
}
KLStatus __KLDestroyCCache (KLCCache inCCache)
{
KLStatus err = klNoErr;
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
if (inCCache->cache != NULL) { __KLDestroyKrb5CCache (inCCache->context, inCCache->cache); }
if (inCCache->context != NULL) { krb5_free_context (inCCache->context); }
free (inCCache);
}
return KLError_ (err);
}
#pragma mark -
#pragma mark -- Operations on KLCCaches --
#pragma mark -
static KLStatus __KLOverwriteV5Credentials (krb5_context inSourceContext,
krb5_ccache inSourceCCache,
krb5_context inDestinationContext,
krb5_ccache inDestinationCCache)
{
KLStatus err = klNoErr;
if (inSourceContext == NULL) { err = KLError_ (klParameterErr); }
if (inSourceCCache == NULL) { err = KLError_ (klParameterErr); }
if (inDestinationContext == NULL) { err = KLError_ (klParameterErr); }
if (inDestinationCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err && !__KLKrb5CCachesAreEqual (inSourceContext, inSourceCCache, inDestinationContext, inDestinationCCache)) {
krb5_principal v5Principal = NULL;
err = krb5_cc_get_principal (inSourceContext, inSourceCCache, &v5Principal);
if (!err) {
err = krb5_cc_initialize (inDestinationContext, inDestinationCCache, v5Principal);
}
if (!err) {
err = krb5_cc_copy_creds (inSourceContext, inSourceCCache, inDestinationCCache);
}
if (v5Principal != NULL) { krb5_free_principal (inSourceContext, v5Principal); }
}
return KLError_ (err);
}
KLStatus __KLMoveCCache (KLCCache inSourceCCache, KLCCache inDestinationCCache)
{
KLStatus err = klNoErr;
KLBoolean sourceIsCCAPI = FALSE;
KLBoolean destinationIsCCAPI = FALSE;
if (inSourceCCache == NULL) { err = KLError_ (klParameterErr); }
if (inDestinationCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
sourceIsCCAPI = __KLKrb5CCacheIsCCAPICCache (inSourceCCache->context, inSourceCCache->cache);
destinationIsCCAPI = __KLKrb5CCacheIsCCAPICCache (inDestinationCCache->context, inDestinationCCache->cache);
if (!__KLKrb5CCacheExists (inSourceCCache->context, inSourceCCache->cache)) {
err = KLError_ (klCacheDoesNotExistErr);
}
}
if (!err) {
if (destinationIsCCAPI) {
KLCCache temporaryCCache = NULL;
cc_ccache_t sourceCCache = NULL;
cc_ccache_t destinationCCache = NULL;
if (sourceIsCCAPI) {
err = __KLGetCCAPICCacheForKrb5CCache (inSourceCCache->context, inSourceCCache->cache, &sourceCCache);
} else {
KLPrincipal principal = NULL;
err = __KLGetPrincipalForCCache (inSourceCCache, &principal);
if (!err) {
err = __KLCreateNewCCAPICCache (principal, inSourceCCache->context, &temporaryCCache);
}
if (!err) {
err = __KLOverwriteV5Credentials (inSourceCCache->context, inSourceCCache->cache,
temporaryCCache->context, temporaryCCache->cache);
}
if (!err) {
err = __KLGetCCAPICCacheForKrb5CCache (temporaryCCache->context, temporaryCCache->cache, &sourceCCache);
}
if (principal != NULL) { KLDisposePrincipal (principal); }
}
if (!err) {
err = __KLGetCCAPICCacheForKrb5CCache (inDestinationCCache->context, inDestinationCCache->cache, &destinationCCache);
}
if (!err) {
err = cc_ccache_move (sourceCCache, destinationCCache);
if (!err) { sourceCCache = NULL; }
}
if (sourceCCache != NULL) { cc_ccache_release (sourceCCache); }
if (destinationCCache != NULL) { cc_ccache_release (destinationCCache); }
if (temporaryCCache != NULL) { __KLDestroyCCache (temporaryCCache); }
} else {
if (!err) {
err = __KLOverwriteV5Credentials (inSourceCCache->context, inSourceCCache->cache,
inDestinationCCache->context, inDestinationCCache->cache);
}
}
if (!err) {
if (!__KLKrb5CCachesAreEqual (inSourceCCache->context, inSourceCCache->cache,
inDestinationCCache->context, inDestinationCCache->cache)) {
__KLDestroyKrb5CCache (inSourceCCache->context, inSourceCCache->cache);
inSourceCCache->cache = NULL;
}
err = __KLCloseCCache (inSourceCCache);
}
}
return KLError_ (err);
}
#pragma mark -
static KLStatus __KLSetKrb5CCacheToCCAPIDefault (krb5_context inContext,
krb5_ccache inV5CCache)
{
KLStatus err = klNoErr;
cc_ccache_t cc_ccache = NULL;
if (inContext == NULL) { err = KLError_ (klParameterErr); }
if (inV5CCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = __KLGetCCAPICCacheForKrb5CCache (inContext, inV5CCache, &cc_ccache);
}
if (!err) {
err = cc_ccache_set_default (cc_ccache);
}
if (cc_ccache != NULL) { cc_ccache_release (cc_ccache); }
return KLError_ (err);
}
KLStatus __KLSetDefaultCCache (KLCCache *ioCCache)
{
KLStatus err = klNoErr;
if ((ioCCache == NULL) || (*ioCCache == NULL)) { err = KLError_ (klParameterErr); }
if (!err) {
char *environmentName = getenv ("KRB5CCNAME");
if (environmentName != NULL) {
KLCCache environmentCCache = NULL;
err = __KLGetCCacheByName (environmentName, &environmentCCache);
if (!err) {
err = __KLMoveCCache (*ioCCache, environmentCCache);
}
if (!err) {
*ioCCache = environmentCCache;
environmentCCache = NULL;
}
if (environmentCCache != NULL) { __KLCloseCCache (environmentCCache); }
} else {
if (__KLKrb5CCacheIsCCAPICCache ((*ioCCache)->context, (*ioCCache)->cache)) {
err = __KLSetKrb5CCacheToCCAPIDefault ((*ioCCache)->context, (*ioCCache)->cache);
} else {
KLCCache destinationCCache = NULL;
KLPrincipal principal = NULL;
err = __KLGetPrincipalForCCache (*ioCCache, &principal);
if (!err) {
err = __KLGetFirstCCacheForPrincipal (principal, &destinationCCache);
if (err) {
err = __KLCreateNewCCAPICCache (principal, (*ioCCache)->context, &destinationCCache);
}
}
if (!err) {
err = __KLMoveCCache (*ioCCache, destinationCCache);
}
if (!err) {
err = __KLSetKrb5CCacheToCCAPIDefault (destinationCCache->context, destinationCCache->cache);
}
if (!err) {
err = __KLDestroyCCache (*ioCCache);
}
if (!err) {
*ioCCache = destinationCCache;
destinationCCache = NULL;
}
if (principal != NULL) { KLDisposePrincipal (principal); }
if (destinationCCache != NULL) { __KLCloseCCache (destinationCCache); }
}
}
}
return KLError_ (err);
}
#pragma mark -
#pragma mark -- KLCCache Validity --
#pragma mark -
KLStatus __KLCCacheExists (KLCCache inCCache)
{
KLStatus err = klNoErr;
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
if (!__KLKrb5CCacheExists (inCCache->context, inCCache->cache)) {
err = KLError_ (klCacheDoesNotExistErr);
}
}
return KLError_ (err);
}
#pragma mark -
KLStatus __KLGetValidV5TicketForCCache (KLCCache inCCache,
krb5_creds **outV5Creds,
KLBoolean *outV5CredsAreTGT)
{
KLStatus err = klNoErr;
krb5_cc_cursor cursor = NULL;
krb5_creds *validCreds = NULL;
KLBoolean foundValidTGT = FALSE;
KLBoolean foundInvalidTGT = FALSE;
KLStatus invalidTGTErr = klNoErr;
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = krb5_cc_start_seq_get (inCCache->context, inCCache->cache, &cursor);
}
while (!err && !foundValidTGT) {
krb5_creds creds;
KLBoolean freeCreds = FALSE;
KLPrincipal servicePrincipal = NULL;
err = krb5_cc_next_cred (inCCache->context, inCCache->cache, &cursor, &creds);
if (!err) { freeCreds = TRUE; }
if (!err) {
err = __KLCreatePrincipalFromKerberos5Principal (creds.server, &servicePrincipal);
}
if (!err) {
KLBoolean credsAreTGT = __KLPrincipalIsTicketGrantingService (servicePrincipal);
KLStatus credsErr = __KLV5CredsAreValid (inCCache->context, &creds);
if (credsAreTGT && credsErr) {
foundInvalidTGT = TRUE;
invalidTGTErr = credsErr;
} else if (!credsErr && ((validCreds == NULL) || (!foundValidTGT && credsAreTGT))) {
if (validCreds != NULL) { krb5_free_creds (inCCache->context, validCreds); }
err = krb5_copy_creds (inCCache->context, &creds, &validCreds);
if (!err) { foundValidTGT = credsAreTGT; }
}
}
if (servicePrincipal != NULL) { KLDisposePrincipal (servicePrincipal); }
if (freeCreds ) { krb5_free_cred_contents (inCCache->context, &creds); }
}
if (!err || (err == KRB5_CC_END)) {
if (foundInvalidTGT && !foundValidTGT) {
err = KLError_ (invalidTGTErr);
} else {
if (validCreds == NULL) { err = KLError_ (klNoCredentialsErr); } else { err = klNoErr; }
}
}
if (!err) {
if (outV5Creds != NULL) {
*outV5Creds = validCreds;
validCreds = NULL; }
if (outV5CredsAreTGT != NULL) {
*outV5CredsAreTGT = foundValidTGT;
}
}
if (validCreds != NULL) { krb5_free_creds (inCCache->context, validCreds); }
if (cursor != NULL) { krb5_cc_end_seq_get (inCCache->context, inCCache->cache, &cursor); }
return KLError_ (err);
}
KLStatus __KLGetValidV5TgtForCCache (KLCCache inCCache,
krb5_creds **outV5Creds)
{
KLStatus err = klNoErr;
krb5_creds *creds = NULL;
KLBoolean credsAreTGT = FALSE;
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = __KLGetValidV5TicketForCCache (inCCache, &creds, &credsAreTGT);
}
if (!err) {
if (credsAreTGT) {
if (outV5Creds != NULL) {
*outV5Creds = creds;
creds = NULL; }
} else {
err = KLError_ (klNoCredentialsErr);
}
}
if (creds != NULL) { krb5_free_creds (inCCache->context, creds); }
return KLError_ (err);
}
KLStatus __KLCacheHasValidTickets (KLCCache inCCache)
{
KLStatus err = __KLGetValidV5TicketForCCache (inCCache, NULL, NULL);
return KLError_ (err);
}
#pragma mark -
KLStatus __KLGetCCacheExpirationTime (KLCCache inCCache,
KLTime *outExpirationTime)
{
KLStatus err = klNoErr;
krb5_creds *v5Creds = NULL;
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (outExpirationTime == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = __KLCacheHasValidTickets (inCCache);
}
if (!err) {
err = __KLGetValidV5TicketForCCache (inCCache, &v5Creds, NULL);
}
if (!err) {
*outExpirationTime = v5Creds->times.endtime;
}
if (!err && (*outExpirationTime == 0 || *outExpirationTime == 0xFFFFFFFF)) {
dprintf ("__KLGetCCacheExpirationTime returning suspicious expiration time %d", *outExpirationTime);
}
if (v5Creds != NULL) { krb5_free_creds (inCCache->context, v5Creds); }
return KLError_ (err);
}
KLStatus __KLGetCCacheStartTime (KLCCache inCCache,
KLTime *outStartTime)
{
KLStatus err = klNoErr;
krb5_creds *v5Creds = NULL;
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (outStartTime == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = __KLCacheHasValidTickets (inCCache);
}
if (!err) {
err = __KLGetValidV5TicketForCCache (inCCache, &v5Creds, NULL);
}
if (!err) {
*outStartTime = v5Creds->times.starttime;
}
if (!err && (*outStartTime == 0 || *outStartTime == 0xFFFFFFFF)) {
dprintf ("__KLGetCCacheStartTime returning suspicious start time %d", *outStartTime);
}
return KLError_ (err);
}
#pragma mark -
#pragma mark -- Other Information About KLCCaches --
#pragma mark -
KLStatus __KLGetKrb5CCacheAndContextForCCache (KLCCache inCCache,
krb5_ccache *outCCache,
krb5_context *outContext)
{
KLStatus err = klNoErr;
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (outCCache == NULL) { err = KLError_ (klParameterErr); }
if (outContext == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
*outCCache = inCCache->cache;
*outContext = inCCache->context;
}
return KLError_ (err);
}
#pragma mark -
KLStatus __KLGetPrincipalForCCache (KLCCache inCCache,
KLPrincipal *outPrincipal)
{
KLStatus err = klNoErr;
KLPrincipal principal = NULL;
krb5_principal v5Principal = NULL;
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = krb5_cc_get_principal (inCCache->context, inCCache->cache, &v5Principal);
}
if (!err) {
err = __KLCreatePrincipalFromKerberos5Principal (v5Principal, &principal);
}
if (!err) {
if (outPrincipal != NULL) {
*outPrincipal = principal;
principal = NULL;
}
}
if (v5Principal != NULL) { krb5_free_principal (inCCache->context, v5Principal); }
if (principal != NULL) { KLDisposePrincipal (principal); }
return KLError_ (err);
}
KLStatus __KLGetNameForCCache (KLCCache inCCache,
char **outName)
{
KLStatus err = klNoErr;
char *name = NULL;
char *type = NULL;
char *resolveName = NULL;
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = __KLGetCCacheTypeAndName (inCCache->context, inCCache->cache, &type, &name);
}
if (!err) {
err = __KLGetCCacheResolveName (type, name, &resolveName);
}
if (!err) {
if (outName != NULL) {
*outName = resolveName;
resolveName = NULL;
}
}
if (resolveName != NULL) { KLDisposeString (resolveName); }
if (type != NULL) { KLDisposeString (type); }
if (name != NULL) { KLDisposeString (name); }
return KLError_ (err);
}
KLStatus __KLGetPrincipalAndNameForCCache (KLCCache inCCache,
KLPrincipal *outPrincipal,
char **outName)
{
KLStatus err = klNoErr;
KLPrincipal principal = NULL;
char *name = NULL;
if (inCCache == NULL) { err = KLError_ (klParameterErr); }
if (!err) {
err = __KLGetPrincipalForCCache (inCCache, &principal);
}
if (!err) {
err = __KLGetNameForCCache (inCCache, &name);
}
if (!err) {
if (outPrincipal != NULL) {
*outPrincipal = principal;
principal = NULL;
}
if (outName != NULL) {
*outName = name;
name = NULL;
}
}
if (principal != NULL) { KLDisposePrincipal (principal); }
if (name != NULL) { KLDisposeString (name); }
return KLError_ (err);
}