* credentical cache API
*
* Written by Frank Dabek July 1998
+ * Updated by Jeffrey Altman June 2006
*
- * Copyright 1998, 1999 by the Massachusetts Institute of Technology.
+ * Copyright 1998, 1999, 2006 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
*
*/
-#define NEED_WINDOWS
#include "k5-int.h"
#include "stdcc.h"
#include "stdcc_util.h"
#include "string.h"
#include <stdio.h>
-apiCB *gCntrlBlock = NULL;
-
#if defined(_WIN32)
#include "winccld.h"
#endif
#define SHOW_DEBUG(buf)
#endif
+#ifdef USE_CCAPI_V3
+cc_context_t gCntrlBlock = NULL;
+#else
+apiCB *gCntrlBlock = NULL;
+#endif
+
/*
* declare our global object wanna-be
* must be installed in ccdefops.c
*/
krb5_cc_ops krb5_cc_stdcc_ops = {
- 0,
- "API",
+ 0,
+ "API",
+#ifdef USE_CCAPI_V3
+ krb5_stdccv3_get_name,
+ krb5_stdccv3_resolve,
+ krb5_stdccv3_generate_new,
+ krb5_stdccv3_initialize,
+ krb5_stdccv3_destroy,
+ krb5_stdccv3_close,
+ krb5_stdccv3_store,
+ krb5_stdccv3_retrieve,
+ krb5_stdccv3_get_principal,
+ krb5_stdccv3_start_seq_get,
+ krb5_stdccv3_next_cred,
+ krb5_stdccv3_end_seq_get,
+ krb5_stdccv3_remove,
+ krb5_stdccv3_set_flags,
+ krb5_stdccv3_get_flags
+#else
krb5_stdcc_get_name,
krb5_stdcc_resolve,
krb5_stdcc_generate_new,
krb5_stdcc_end_seq_get,
krb5_stdcc_remove,
krb5_stdcc_set_flags,
- krb5_stdcc_get_flags,
+ krb5_stdcc_get_flags
+#endif
};
#if defined(_WIN32)
static const struct err_xlate err_xlate_table[] =
{
+#ifdef USE_CCAPI_V3
+ { ccIteratorEnd, KRB5_CC_END },
+ { ccErrBadParam, KRB5_FCC_INTERNAL },
+ { ccErrNoMem, KRB5_CC_NOMEM },
+ { ccErrInvalidContext, KRB5_FCC_INTERNAL },
+ { ccErrInvalidCCache, KRB5_FCC_INTERNAL },
+ { ccErrInvalidString, KRB5_FCC_INTERNAL },
+ { ccErrInvalidCredentials, KRB5_FCC_INTERNAL },
+ { ccErrInvalidCCacheIterator, KRB5_FCC_INTERNAL },
+ { ccErrInvalidCredentialsIterator, KRB5_FCC_INTERNAL },
+ { ccErrInvalidLock, KRB5_FCC_INTERNAL },
+ { ccErrBadName, KRB5_CC_BADNAME },
+ { ccErrBadCredentialsVersion, KRB5_FCC_INTERNAL },
+ { ccErrBadAPIVersion, KRB5_FCC_INTERNAL },
+ { ccErrContextLocked, KRB5_FCC_INTERNAL },
+ { ccErrContextUnlocked, KRB5_FCC_INTERNAL },
+ { ccErrCCacheLocked, KRB5_FCC_INTERNAL },
+ { ccErrCCacheUnlocked, KRB5_FCC_INTERNAL },
+ { ccErrBadLockType, KRB5_FCC_INTERNAL },
+ { ccErrNeverDefault, KRB5_FCC_INTERNAL },
+ { ccErrCredentialsNotFound, KRB5_CC_NOTFOUND },
+ { ccErrCCacheNotFound, KRB5_FCC_NOFILE },
+ { ccErrContextNotFound, KRB5_FCC_INTERNAL },
+ { ccErrServerUnavailable, KRB5_FCC_NOFILE },
+ { ccErrServerInsecure, KRB5_FCC_INTERNAL },
+ { ccErrServerCantBecomeUID, KRB5_FCC_INTERNAL },
+ { ccErrTimeOffsetNotSet, KRB5_FCC_INTERNAL },
+ { ccErrBadInternalMessage, KRB5_FCC_INTERNAL },
+ { ccErrNotImplemented, KRB5_FCC_INTERNAL },
+#else
{ CC_BADNAME, KRB5_CC_BADNAME },
{ CC_NOTFOUND, KRB5_CC_NOTFOUND },
{ CC_END, KRB5_CC_END },
{ CC_ERR_CACHE_RELEASE, KRB5_FCC_INTERNAL /* XXX */ },
{ CC_ERR_CACHE_FULL, KRB5_FCC_INTERNAL /* XXX */ },
{ CC_ERR_CRED_VERSION, KRB5_FCC_INTERNAL /* XXX */ },
+#endif
{ 0, 0 }
};
{
const struct err_xlate *p;
- if (err == CC_NOERROR)
+ if (err == ccNoError)
return 0;
for (p = err_xlate_table; p->cc_err; p++) {
return KRB5_FCC_INTERNAL; /* XXX we need a miscellaneous return */
}
+
+#ifdef USE_CCAPI_V3
+static krb5_error_code stdccv3_setup(krb5_context context,
+ stdccCacheDataPtr ccapi_data)
+{
+ cc_int32 err;
+
+ /* make sure the API has been intialized */
+ if (gCntrlBlock == NULL) {
+ err = cc_initialize(&gCntrlBlock, ccapi_version_max, NULL, NULL);
+ if (err != ccNoError)
+ return cc_err_xlate(err);
+ }
+
+ /*
+ * No ccapi_data structure, so we don't need to make sure the
+ * ccache exists.
+ */
+ if (!ccapi_data)
+ return 0;
+
+ /*
+ * The ccache already exists
+ */
+ if (ccapi_data->NamedCache)
+ return 0;
+
+ err = cc_context_open_ccache(gCntrlBlock, ccapi_data->cache_name,
+ &ccapi_data->NamedCache);
+ if (err == ccNoError)
+ return 0;
+
+ ccapi_data->NamedCache = NULL;
+ return cc_err_xlate(err);
+}
+
+void krb5_stdccv3_shutdown()
+{
+ if (gCntrlBlock)
+ cc_context_release(gCntrlBlock);
+ gCntrlBlock = NULL;
+}
+
+/*
+ * -- generate_new --------------------------------
+ *
+ * create a new cache with a unique name, corresponds to creating a
+ * named cache initialize the API here if we have to.
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_generate_new
+ (krb5_context context, krb5_ccache *id )
+{
+ krb5_ccache newCache = NULL;
+ krb5_error_code retval;
+ stdccCacheDataPtr ccapi_data = NULL;
+ char *name = NULL;
+ cc_time time;
+ int err;
+
+ if ((retval = stdccv3_setup(context, NULL)))
+ return retval;
+
+ retval = KRB5_CC_NOMEM;
+ if (!(newCache = (krb5_ccache) malloc(sizeof(struct _krb5_ccache))))
+ goto errout;
+ if (!(ccapi_data = (stdccCacheDataPtr)malloc(sizeof(stdccCacheData))))
+ goto errout;
+ if (!(name = malloc(256)))
+ goto errout;
+
+ /* create a unique name */
+ if (retval = cc_context_get_change_time(gCntrlBlock, &time))
+ goto errout;
+ sprintf(name, "gen_new_cache%d", time);
+
+ /* create the new cache */
+ err = cc_context_create_ccache(gCntrlBlock, name, cc_credentials_v5, 0L,
+ &ccapi_data->NamedCache);
+ if (err != ccNoError) {
+ retval = cc_err_xlate(err);
+ goto errout;
+ }
+
+ /* setup some fields */
+ newCache->ops = &krb5_cc_stdcc_ops;
+ newCache->data = ccapi_data;
+ ccapi_data->cache_name = name;
+
+ /* return a pointer to the new cache */
+ *id = newCache;
+
+ return 0;
+
+errout:
+ if (newCache)
+ free(newCache);
+ if (ccapi_data)
+ free(ccapi_data);
+ if (name)
+ free(name);
+ return retval;
+}
+
+/*
+ * resolve
+ *
+ * create a new cache with the name stored in residual
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_resolve
+ (krb5_context context, krb5_ccache *id , const char *residual )
+{
+ krb5_ccache newCache = NULL;
+ stdccCacheDataPtr ccapi_data = NULL;
+ int err;
+ krb5_error_code retval;
+ char *cName = NULL;
+
+ if ((retval = stdccv3_setup(context, NULL)))
+ return retval;
+
+ retval = KRB5_CC_NOMEM;
+ if (!(newCache = (krb5_ccache) malloc(sizeof(struct _krb5_ccache))))
+ goto errout;
+
+ if (!(ccapi_data = (stdccCacheDataPtr)malloc(sizeof(stdccCacheData))))
+ goto errout;
+
+ if (!(cName = malloc(strlen(residual)+1)))
+ goto errout;
+
+ newCache->ops = &krb5_cc_stdcc_ops;
+ newCache->data = ccapi_data;
+ ccapi_data->cache_name = cName;
+
+ strcpy(cName, residual);
+
+ err = cc_context_open_ccache(gCntrlBlock, cName,
+ &ccapi_data->NamedCache);
+ if (err != ccNoError) {
+ ccapi_data->NamedCache = NULL;
+ goto errout;
+ }
+
+ /* return new cache structure */
+ *id = newCache;
+
+ return 0;
+
+errout:
+ if (newCache)
+ free(newCache);
+ if (ccapi_data)
+ free(ccapi_data);
+ if (cName)
+ free(cName);
+ return retval;
+}
+
+/*
+ * initialize
+ *
+ * initialize the cache, check to see if one already exists for this
+ * principal if not set our principal to this principal. This
+ * searching enables ticket sharing
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_initialize
+ (krb5_context context, krb5_ccache id, krb5_principal princ)
+{
+ stdccCacheDataPtr ccapi_data = NULL;
+ int err;
+ char *cName = NULL;
+ krb5_error_code retval;
+
+ if ((retval = stdccv3_setup(context, NULL)))
+ return retval;
+
+ /* test id for null */
+ if (id == NULL) return KRB5_CC_NOMEM;
+
+ if ((retval = krb5_unparse_name(context, princ, &cName)))
+ return retval;
+
+ ccapi_data = id->data;
+
+
+ if (ccapi_data->NamedCache) {
+ err = cc_ccache_release(ccapi_data->NamedCache);
+ ccapi_data->NamedCache = NULL;
+ }
+
+ err = cc_context_create_ccache(gCntrlBlock, ccapi_data->cache_name,
+ cc_credentials_v5, cName,
+ &ccapi_data->NamedCache);
+ if (err != ccNoError) {
+ krb5_free_unparsed_name(context, cName);
+ return cc_err_xlate(err);
+ }
+
+ krb5_free_unparsed_name(context, cName);
+ cache_changed();
+
+ return cc_err_xlate(err);
+}
+
+/*
+ * store
+ *
+ * store some credentials in our cache
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_store
+ (krb5_context context, krb5_ccache id, krb5_creds *creds )
+{
+ krb5_error_code retval;
+ stdccCacheDataPtr ccapi_data = id->data;
+ cc_credentials_t c = NULL;
+ int err;
+
+ if ((retval = stdccv3_setup(context, ccapi_data)))
+ return retval;
+
+ /* copy the fields from the almost identical structures */
+ dupK5toCC3(context, creds, &c);
+
+ /*
+ * finally store the credential
+ * store will copy (that is duplicate) everything
+ */
+ err = cc_ccache_store_credentials(((stdccCacheDataPtr)(id->data))->NamedCache, c->data);
+ if (err != ccNoError)
+ return cc_err_xlate(err);
+
+ err = cc_credentials_release(c);
+
+ cache_changed();
+ return err;
+}
+
+/*
+ * start_seq_get
+ *
+ * begin an iterator call to get all of the credentials in the cache
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_start_seq_get
+(krb5_context context, krb5_ccache id , krb5_cc_cursor *cursor )
+{
+ stdccCacheDataPtr ccapi_data = id->data;
+ krb5_error_code retval;
+ int err;
+ cc_credentials_iterator_t iterator;
+
+ if ((retval = stdccv3_setup(context, ccapi_data)))
+ return retval;
+
+ err = cc_ccache_new_credentials_iterator(ccapi_data->NamedCache,
+ &iterator);
+ if (err != ccNoError)
+ return cc_err_xlate(err);
+ *cursor = iterator;
+ return 0;
+}
+
+/*
+ * next cred
+ *
+ * - get the next credential in the cache as part of an iterator call
+ * - this maps to call to cc_seq_fetch_creds
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_next_cred
+ (krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor,
+ krb5_creds *creds)
+{
+ krb5_error_code retval;
+ stdccCacheDataPtr ccapi_data = id->data;
+ int err;
+ cc_credentials_t cu;
+ cc_credentials_iterator_t iterator;
+
+ if ((retval = stdccv3_setup(context, ccapi_data)))
+ return retval;
+
+ iterator = *cursor;
+ if (iterator == 0)
+ return KRB5_CC_END;
+ err = cc_credentials_iterator_next(iterator, &cu);
+
+ if (err == ccIteratorEnd) {
+ cc_credentials_iterator_release(iterator);
+ *cursor = 0;
+ }
+ if (err != ccNoError)
+ return cc_err_xlate(err);
+
+ /* copy data (with translation) */
+ dupCC3toK5(context, cu, creds);
+
+ cc_credentials_release(cu);
+
+ return 0;
+}
+
+
+/*
+ * retrieve
+ *
+ * - try to find a matching credential in the cache
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_stdccv3_retrieve(context, id, whichfields, mcreds, creds)
+ krb5_context context;
+ krb5_ccache id;
+ krb5_flags whichfields;
+ krb5_creds *mcreds;
+ krb5_creds *creds;
+{
+ return krb5_cc_retrieve_cred_default (context, id, whichfields,
+ mcreds, creds);
+}
+
+/*
+ * end seq
+ *
+ * just free up the storage assoicated with the cursor (if we can)
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_end_seq_get
+ (krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
+{
+ krb5_error_code retval;
+ stdccCacheDataPtr ccapi_data = NULL;
+ int err;
+ cc_credentials_iterator_t iterator;
+
+ ccapi_data = id->data;
+
+ if ((retval = stdccv3_setup(context, ccapi_data)))
+ return retval;
+
+ if (*cursor == NULL)
+ return 0;
+
+ iterator = *cursor;
+
+ err = cc_credentials_iterator_release(iterator);
+ if (err != ccNoError)
+ return cc_err_xlate(err);
+ return(0);
+}
+
+/*
+ * close
+ *
+ * - free our pointers to the NC
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_stdccv3_close(krb5_context context, krb5_ccache id)
+{
+ krb5_error_code retval;
+ stdccCacheDataPtr ccapi_data = id->data;
+
+ if ((retval = stdccv3_setup(context, NULL)))
+ return retval;
+
+ /* free it */
+ if (ccapi_data) {
+ if (ccapi_data->cache_name)
+ free(ccapi_data->cache_name);
+ if (ccapi_data->NamedCache)
+ cc_ccache_release(ccapi_data->NamedCache);
+ free(ccapi_data);
+ id->data = NULL;
+ }
+ free(id);
+
+ return 0;
+}
+
+/*
+ * destroy
+ *
+ * - free our storage and the cache
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_stdccv3_destroy (krb5_context context, krb5_ccache id)
+{
+ int err;
+ krb5_error_code retval;
+ stdccCacheDataPtr ccapi_data = id->data;
+
+ if ((retval = stdccv3_setup(context, ccapi_data))) {
+ return retval;
+ }
+
+ /* free memory associated with the krb5_ccache */
+ if (ccapi_data) {
+ if (ccapi_data->cache_name)
+ free(ccapi_data->cache_name);
+ if (ccapi_data->NamedCache) {
+ /* destroy the named cache */
+ err = cc_ccache_destroy(ccapi_data->NamedCache);
+ retval = cc_err_xlate(err);
+ cache_changed();
+ }
+ free(ccapi_data);
+ id->data = NULL;
+ }
+ free(id);
+
+ /* If the cache does not exist when we tried to destroy it,
+ that's fine. That means someone else destroyed it since
+ we resolved it. */
+ if (retval == ccErrCCacheNotFound)
+ return 0;
+ return retval;
+}
+
+/*
+ * getname
+ *
+ * - return the name of the named cache
+ */
+const char * KRB5_CALLCONV krb5_stdccv3_get_name
+ (krb5_context context, krb5_ccache id )
+{
+ stdccCacheDataPtr ccapi_data = id->data;
+
+ if (!ccapi_data)
+ return 0;
+
+ return (ccapi_data->cache_name);
+}
+
+
+/* get_principal
+ *
+ * - return the principal associated with the named cache
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_get_principal
+ (krb5_context context, krb5_ccache id , krb5_principal *princ)
+{
+ int err;
+ cc_string_t name = NULL;
+ stdccCacheDataPtr ccapi_data = id->data;
+ krb5_error_code retval;
+
+ if ((retval = stdccv3_setup(context, ccapi_data)))
+ return retval;
+
+ /* another wrapper */
+ err = cc_ccache_get_principal(ccapi_data->NamedCache, cc_credentials_v5, &name);
+
+ if (err != ccNoError)
+ return cc_err_xlate(err);
+
+ /* turn it into a krb principal */
+ err = krb5_parse_name(context, name->data, princ);
+
+ cc_string_release(name);
+
+ return err;
+}
+
+/*
+ * set_flags
+ *
+ * - currently a NOP since we don't store any flags in the NC
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_set_flags
+ (krb5_context context, krb5_ccache id , krb5_flags flags)
+{
+ stdccCacheDataPtr ccapi_data = id->data;
+ krb5_error_code retval;
+
+ if ((retval = stdccv3_setup(context, ccapi_data)))
+ return retval;
+
+ return 0;
+}
+
+/*
+ * get_flags
+ *
+ * - currently a NOP since we don't store any flags in the NC
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_get_flags
+ (krb5_context context, krb5_ccache id , krb5_flags *flags)
+{
+ stdccCacheDataPtr ccapi_data = id->data;
+ krb5_error_code retval;
+
+ if ((retval = stdccv3_setup(context, ccapi_data)))
+ return retval;
+
+ return 0;
+}
+
+/*
+ * remove
+ *
+ * - remove the specified credentials from the NC
+ */
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_remove
+ (krb5_context context, krb5_ccache id,
+ krb5_flags flags, krb5_creds *creds)
+{
+ cc_credentials_t c = NULL;
+ int err;
+ stdccCacheDataPtr ccapi_data = id->data;
+ krb5_error_code retval;
+
+ if ((retval = stdccv3_setup(context, ccapi_data))) {
+ if (retval == KRB5_FCC_NOFILE)
+ return 0;
+ return retval;
+ }
+
+ /* convert to a cred union */
+ dupK5toCC3(context, creds, &c);
+
+ /* remove it */
+ err = cc_ccache_remove_credentials(ccapi_data->NamedCache, c);
+ if (err != ccNoError)
+ return cc_err_xlate(err);
+
+ err = cc_credentials_release(c);
+ cache_changed();
+ if (err != ccNoError)
+ return cc_err_xlate(err);
+
+ return 0;
+}
+#else /* !USE_CCAPI_V3 */
static krb5_error_code stdcc_setup(krb5_context context,
stdccCacheDataPtr ccapi_data)
{
{
if (gCntrlBlock)
cc_shutdown(&gCntrlBlock);
- gCntrlBlock = 0;
+ gCntrlBlock = NULL;
}
/*
err = cc_open(gCntrlBlock, cName, CC_CRED_V5, 0L,
&ccapi_data->NamedCache);
- if (err != CC_NOERROR)
- ccapi_data->NamedCache = NULL;
-
+ if (err != CC_NOERROR) {
+ ccapi_data->NamedCache = NULL;
+ goto errout;
+ }
/* return new cache structure */
*id = newCache;
/* free the cred union using our local version of cc_free_creds()
since we allocated it locally */
- err = krb5_free_cc_cred_union(&cu);
+ err = krb5int_free_cc_cred_union(&cu);
cache_changed();
return err;
return KRB5_CC_NOTFOUND;
}
#else
-#include "k5-int.h"
krb5_error_code KRB5_CALLCONV
krb5_stdcc_retrieve(context, id, whichfields, mcreds, creds)
/* free the cred union using our local version of cc_free_creds()
since we allocated it locally */
- err = krb5_free_cc_cred_union(&cu);
+ err = krb5int_free_cc_cred_union(&cu);
cache_changed();
if (err != CC_NOERROR)
return cc_err_xlate(err);
return 0;
}
+#endif /* !USE_CCAPI_V3 */
\ No newline at end of file
-#include "krb5.h"
-#include "k5-int.h"
+#include "k5-int.h" /* loads krb5.h */
+#ifdef USE_CCAPI_V3
+#include <CredentialsCache.h>
+#else
#ifdef USE_CCAPI
#include <CredentialsCache2.h>
-#endif
-
+#else
#if defined(_WIN32)
#include "cacheapi.h"
#endif
+#endif
+#endif
+
#define kStringLiteralLen 255
*/
typedef struct _stdccCacheData {
char *cache_name;
+#ifdef USE_CCAPI_V3
+ cc_ccache_t NamedCache;
+#else
ccache_p *NamedCache;
+#endif
} stdccCacheData, *stdccCacheDataPtr;
/* function protoypes */
+#ifdef USE_CCAPI_V3
+void krb5_stdccv3_shutdown(void);
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_close
+ (krb5_context, krb5_ccache id );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_destroy
+ (krb5_context, krb5_ccache id );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_end_seq_get
+ (krb5_context, krb5_ccache id , krb5_cc_cursor *cursor );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_generate_new
+ (krb5_context, krb5_ccache *id );
+
+const char * KRB5_CALLCONV krb5_stdccv3_get_name
+ (krb5_context, krb5_ccache id );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_get_principal
+ (krb5_context, krb5_ccache id , krb5_principal *princ );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_initialize
+ (krb5_context, krb5_ccache id , krb5_principal princ );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_next_cred
+ (krb5_context,
+ krb5_ccache id ,
+ krb5_cc_cursor *cursor ,
+ krb5_creds *creds );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_resolve
+ (krb5_context, krb5_ccache *id , const char *residual );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_retrieve
+ (krb5_context,
+ krb5_ccache id ,
+ krb5_flags whichfields ,
+ krb5_creds *mcreds ,
+ krb5_creds *creds );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_start_seq_get
+ (krb5_context, krb5_ccache id , krb5_cc_cursor *cursor );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_store
+ (krb5_context, krb5_ccache id , krb5_creds *creds );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_set_flags
+ (krb5_context, krb5_ccache id , krb5_flags flags );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_get_flags
+ (krb5_context, krb5_ccache id , krb5_flags *flags );
+
+krb5_error_code KRB5_CALLCONV krb5_stdccv3_remove
+ (krb5_context, krb5_ccache id , krb5_flags flags, krb5_creds *creds);
+#else
void krb5_stdcc_shutdown(void);
krb5_error_code KRB5_CALLCONV krb5_stdcc_close
krb5_error_code KRB5_CALLCONV krb5_stdcc_remove
(krb5_context, krb5_ccache id , krb5_flags flags, krb5_creds *creds);
+#endif
\ No newline at end of file
#define fieldSize 255
+#ifdef USE_CCAPI_V3
+/* krb5int_cc_credentials_release(cc_credentials_t creds)
+ * - function used to release internally generated cc_credentials_t objects
+ */
+static cc_int32
+krb5int_cc_credentials_release(cc_credentials_t creds) {
+ free(creds);
+ return ccNoError;
+}
+
+static cc_int32
+krb5int_cc_credentials_compare(cc_credentials_t creds,
+ cc_credentials_t compare_to,
+ cc_uint32* equal) {
+ return ccErrNotImplemented;
+}
+
+/*
+ * CopyCC3DataArrayToK5
+ * - copy and translate the null terminated arrays of data records
+ * used in k5 tickets
+ */
+int
+copyCC3DataArrayToK5(cc_credentials_v5_t *ccCreds, krb5_creds *v5Creds, char whichArray) {
+
+ switch (whichArray) {
+ case 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;
+ }
+ break;
+ case 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;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * copyK5DataArrayToCC
+ * - analagous to above, but in the other direction
+ */
+int
+copyK5DataArrayToCC3(krb5_creds *v5Creds, cc_credentials_v5_t * ccCreds, char whichArray)
+{
+ switch (whichArray) {
+ case 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;
+ }
+ break;
+ case 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;
+ }
+ break;
+ }
+
+ return 0;
+
+}
+
+/*
+ * dupCC3toK5
+ * - allocate an empty k5 style ticket and copy info from the cc_creds ticket
+ */
+
+krb5_error_code
+dupCC3toK5(krb5_context context, cc_credentials_t src, krb5_creds *dest)
+{
+ const cc_credentials_union *cu = src->data;
+ cc_credentials_v5_t *cv5;
+ krb5_int32 offset_seconds = 0, offset_microseconds = 0;
+ krb5_error_code err;
+
+ if (cu->version != cc_credentials_v5)
+ return KRB5_CC_NOT_KTYPE;
+
+ cv5 = cu->credentials.credentials_v5;
+
+ /*
+ * allocate and copy
+ * copy all of those damn fields back
+ */
+ err = krb5_parse_name(context, cv5->client, &(dest->client));
+ err = krb5_parse_name(context, cv5->server, &(dest->server));
+ if (err)
+ return err; /* parsename fails w/o krb5.ini for example */
+
+ /* copy keyblock */
+ dest->keyblock.enctype = cv5->keyblock.type;
+ dest->keyblock.length = cv5->keyblock.length;
+ dest->keyblock.contents = (krb5_octet *)malloc(dest->keyblock.length);
+ memcpy(dest->keyblock.contents, cv5->keyblock.data, dest->keyblock.length);
+
+ /* copy times */
+#if TARGET_OS_MAC
+ err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds);
+ if (err)
+ return err;
+#endif
+ dest->times.authtime = cv5->authtime + offset_seconds;
+ dest->times.starttime = cv5->starttime + offset_seconds;
+ dest->times.endtime = cv5->endtime + offset_seconds;
+ dest->times.renew_till = cv5->renew_till + offset_seconds;
+ dest->is_skey = cv5->is_skey;
+ dest->ticket_flags = cv5->ticket_flags;
+
+ /* more branching fields */
+ err = copyCC3DataArrayToK5(cv5, dest, kAddressArray);
+ if (err)
+ return err;
+
+ /* first ticket */
+ dest->ticket.length = cv5->ticket.length;
+ dest->ticket.data = (char *)malloc(cv5->ticket.length);
+ memcpy(dest->ticket.data, cv5->ticket.data, cv5->ticket.length);
+
+ /* second ticket */
+ dest->second_ticket.length = cv5->second_ticket.length;
+ (dest->second_ticket).data = ( char *)malloc(cv5->second_ticket.length);
+ memcpy(dest->second_ticket.data, cv5->second_ticket.data, cv5->second_ticket.length);
+
+ /* zero out magic number */
+ dest->magic = 0;
+
+ /* authdata */
+ err = copyCC3DataArrayToK5(cv5, dest, kAuthDataArray);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/*
+ * dupK5toCC3
+ * - analagous to above but in the reverse direction
+ */
+krb5_error_code
+dupK5toCC3(krb5_context context, krb5_creds *src, cc_credentials_t *dest)
+{
+ cc_credentials_v5_t *c;
+ cc_credentials_union *cu;
+ cc_credentials_f *f;
+ int err;
+ krb5_int32 offset_seconds = 0, offset_microseconds = 0;
+ cc_credentials_t creds = NULL;
+
+ if (dest == NULL)
+ return KRB5_CC_NOMEM;
+
+ /* allocate the cc_credentials_t */
+ creds = (cc_credentials_t)malloc(sizeof(cc_credentials_d));
+ if (!creds) {
+ err = KRB5_CC_NOMEM;
+ goto cleanup;
+ }
+
+ /* allocate the cred_union */
+ creds->data = NULL;
+ creds->functions = NULL;
+#ifdef TARGET_OS_MAC
+ creds->otherFunctions = NULL;
+#endif
+ f = (cc_credentials_f *)malloc(sizeof(cc_credentials_f));
+ if (!f) {
+ err = KRB5_CC_NOMEM;
+ goto cleanup;
+ }
+ creds->functions = f;
+
+ cu = (cc_credentials_union *)malloc(sizeof(cc_credentials_union));
+ if (!creds->data) {
+ err = KRB5_CC_NOMEM;
+ goto cleanup;
+ }
+ creds->data = cu;
+
+ f->release = krb5int_cc_credentials_release;
+ f->compare = krb5int_cc_credentials_compare;
+
+ cu->version = cc_credentials_v5;
+
+ c = (cc_credentials_v5_t*)malloc(sizeof(cc_credentials_v5_t));
+ if (!c) {
+ err = KRB5_CC_NOMEM;
+ goto cleanup;
+ }
+ cu->credentials.credentials_v5 = c;
+
+ /* convert krb5 principals to flat principals */
+ err = krb5_unparse_name(context, src->client, &(c->client));
+ if (err)
+ goto cleanup;
+
+ err = krb5_unparse_name(context, src->server, &(c->server));
+ if (err)
+ goto cleanup;
+
+ /* copy more fields */
+ c->keyblock.type = src->keyblock.enctype;
+ c->keyblock.length = src->keyblock.length;
+
+ if (src->keyblock.contents != NULL) {
+ c->keyblock.data = (unsigned char *)malloc(src->keyblock.length);
+ memcpy(c->keyblock.data, src->keyblock.contents, src->keyblock.length);
+ } else {
+ c->keyblock.data = NULL;
+ }
+
+#if TARGET_OS_MAC
+ err = krb5_get_time_offsets(context, &offset_seconds, &offset_microseconds);
+ if (err)
+ goto cleanup;
+#endif
+ c->authtime = src->times.authtime - offset_seconds;
+ c->starttime = src->times.starttime - offset_seconds;
+ c->endtime = src->times.endtime - offset_seconds;
+ c->renew_till = src->times.renew_till - offset_seconds;
+ c->is_skey = src->is_skey;
+ c->ticket_flags = src->ticket_flags;
+
+ err = copyK5DataArrayToCC3(src, c, kAddressArray);
+ if (err)
+ goto cleanup;
+
+ c->ticket.length = src->ticket.length;
+ if (src->ticket.data != NULL) {
+ c->ticket.data = (unsigned char *)malloc(src->ticket.length);
+ memcpy(c->ticket.data, src->ticket.data, src->ticket.length);
+ } else {
+ c->ticket.data = NULL;
+ }
+
+ c->second_ticket.length = src->second_ticket.length;
+ if (src->second_ticket.data != NULL) {
+ c->second_ticket.data = (unsigned char *)malloc(src->second_ticket.length);
+ memcpy(c->second_ticket.data, src->second_ticket.data, src->second_ticket.length);
+ } else {
+ c->second_ticket.data = NULL;
+ }
+
+ err = copyK5DataArrayToCC3(src, c, kAuthDataArray);
+ if (err)
+ goto cleanup;
+
+ *dest = creds;
+ return 0;
+
+ cleanup:
+ if (creds) {
+ if (creds->functions)
+ free((void *)creds->functions);
+ if (creds->data) {
+ if (creds->data->credentials.credentials_v5)
+ free(creds->data->credentials.credentials_v5);
+ free((void *)creds->data);
+ }
+ free(creds);
+ }
+
+ return err;
+}
+#else /* !USE_CCAPI_V3 */
/*
* CopyCCDataArrayToK5
* - copy and translate the null terminated arrays of data records
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 index;
+
+ if (data == NULL)
+ return;
+
+ for (index = 0; data [index] != NULL; index++) {
+ deep_free_cc_data (*(data [index]));
+ free (data [index]);
+ }
+
+ 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...
*/
return FALSE;
}
-/* ----- 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 index;
-
- if (data == NULL)
- return;
- for (index = 0; data [index] != NULL; index++) {
- deep_free_cc_data (*(data [index]));
- free (data [index]);
- }
-
- 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 krb5_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;
-}
#include "autoconf.h"
+#if USE_CCAPI_V3
+#include <CredentialsCache.h>
+#else
#if USE_CCAPI
#include <CredentialsCache2.h>
#endif
#if defined(_WIN32)
#include "cacheapi.h"
#endif
+#endif
#include "krb5.h"
/* protoypes for private functions declared in stdcc_util.c */
+#ifdef USE_CCAPI_V3
+krb5_error_code dupCC3toK5(krb5_context context, cc_credentials_t src, krb5_creds *dest);
+krb5_error_code dupK5toCC3(krb5_context context, krb5_creds *src, cc_credentials_t *dest);
+cc_int32 krb5int_cc_credentials_release(cc_credentials_t creds);
+cc_int32 krb5int_cc_credentials_compare(cc_credentials_t creds,
+ cc_credentials_t compare_to,
+ cc_uint32* equal);
+int copyCC3DataArrayToK5(cc_credentials_v5_t *ccCreds, krb5_creds *v5Creds, char whichArray);
+int copyK5DataArrayToCC3(krb5_creds *v5Creds, cc_credentials_v5_t * ccCreds, char whichArray);
+#else
int copyCCDataArrayToK5(cc_creds *cc, krb5_creds *kc, char whichArray);
int copyK5DataArrayToCC(krb5_creds *kc, cc_creds *cc, char whichArray);
void dupCCtoK5(krb5_context context, cc_creds *src, krb5_creds *dest);
void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu);
+cc_int32 krb5int_free_cc_cred_union (cred_union** creds);
+#endif
int stdccCredsMatch(krb5_context context, krb5_creds *base, krb5_creds *match, int whichfields);
int bitTst(int var, int mask);
-cc_int32 krb5_free_cc_cred_union (cred_union** creds);
#define kAddressArray 4
#define kAuthDataArray 5
#ifndef KRB5_WINCCLD_H_
#define KRB5_WINCCLD_H_
+#ifdef USE_CCAPI_V3
+#include <CredentialsCache.h>
+#else
+
#ifndef CC_API_VER2
#define CC_API_VER2
#endif
#include "cacheapi.h"
+#endif
+#ifdef USE_CCAPI_V3
+typedef CCACHE_API cc_int32 (*FP_cc_initialize) (
+ cc_context_t* outContext,
+ cc_int32 inVersion,
+ cc_int32* outSupportedVersion,
+ char const** outVendor);
+#else
typedef cc_int32 (*FP_cc_initialize)(apiCB**, const cc_int32,
cc_int32*, const char**);
typedef cc_int32 (*FP_cc_shutdown)(apiCB**);
typedef cc_int32 (*FP_cc_free_principal)(apiCB*, char**);
typedef cc_int32 (*FP_cc_free_name)(apiCB*, char** name);
typedef cc_int32 (*FP_cc_free_creds)(apiCB*, cred_union** pCred);
+#endif
#ifdef KRB5_WINCCLD_C_
typedef struct _FUNC_INFO {
#endif
DECL_FUNC_PTR(cc_initialize);
+#ifndef USE_CCAPI_V3
DECL_FUNC_PTR(cc_shutdown);
DECL_FUNC_PTR(cc_get_change_time);
DECL_FUNC_PTR(cc_create);
DECL_FUNC_PTR(cc_free_principal);
DECL_FUNC_PTR(cc_free_name);
DECL_FUNC_PTR(cc_free_creds);
+#endif
#ifdef KRB5_WINCCLD_C_
FUNC_INFO krbcc_fi[] = {
MAKE_FUNC_INFO(cc_initialize),
+#ifndef USE_CCAPI_V3
MAKE_FUNC_INFO(cc_shutdown),
MAKE_FUNC_INFO(cc_get_change_time),
MAKE_FUNC_INFO(cc_create),
MAKE_FUNC_INFO(cc_free_principal),
MAKE_FUNC_INFO(cc_free_name),
MAKE_FUNC_INFO(cc_free_creds),
+#endif
END_FUNC_INFO
};
#undef MAKE_FUNC_INFO
#else
#define cc_initialize pcc_initialize
+#ifndef USE_CCAPI_V3
#define cc_shutdown pcc_shutdown
#define cc_get_change_time pcc_get_change_time
#define cc_create pcc_create
#define cc_free_name pcc_free_name
#define cc_free_creds pcc_free_creds
#endif
+#endif
#undef DECL_FUNC_PTR