From 9231d8d2ddec35eeec473904034ccd333a008875 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Thu, 22 Jun 2006 16:57:14 +0000 Subject: [PATCH] This commit updates lib/krb5/ccache/ccapi to support CCAPI Version 3 and above. Specify -DUSE_CCAPI_V3=1 when compiling to use CCAPI Version 3 git-svn-id: svn://anonsvn.mit.edu/krb5/branches/ccapi@18193 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/krb5/ccache/ccapi/stdcc.c | 614 ++++++++++++++++++++++++- src/lib/krb5/ccache/ccapi/stdcc.h | 72 ++- src/lib/krb5/ccache/ccapi/stdcc_util.c | 552 ++++++++++++++++++---- src/lib/krb5/ccache/ccapi/stdcc_util.h | 17 +- src/lib/krb5/ccache/ccapi/winccld.h | 19 + 5 files changed, 1177 insertions(+), 97 deletions(-) diff --git a/src/lib/krb5/ccache/ccapi/stdcc.c b/src/lib/krb5/ccache/ccapi/stdcc.c index 885abf5bb..ace895854 100644 --- a/src/lib/krb5/ccache/ccapi/stdcc.c +++ b/src/lib/krb5/ccache/ccapi/stdcc.c @@ -3,8 +3,9 @@ * 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 @@ -28,15 +29,12 @@ * */ -#define NEED_WINDOWS #include "k5-int.h" #include "stdcc.h" #include "stdcc_util.h" #include "string.h" #include -apiCB *gCntrlBlock = NULL; - #if defined(_WIN32) #include "winccld.h" #endif @@ -56,14 +54,37 @@ apiCB *gCntrlBlock = NULL; #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, @@ -78,7 +99,8 @@ krb5_cc_ops krb5_cc_stdcc_ops = { krb5_stdcc_end_seq_get, krb5_stdcc_remove, krb5_stdcc_set_flags, - krb5_stdcc_get_flags, + krb5_stdcc_get_flags +#endif }; #if defined(_WIN32) @@ -114,6 +136,36 @@ struct err_xlate 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 }, @@ -131,6 +183,7 @@ static const struct err_xlate err_xlate_table[] = { 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 } }; @@ -138,7 +191,7 @@ static krb5_error_code cc_err_xlate(int err) { const struct err_xlate *p; - if (err == CC_NOERROR) + if (err == ccNoError) return 0; for (p = err_xlate_table; p->cc_err; p++) { @@ -148,6 +201,536 @@ static krb5_error_code cc_err_xlate(int err) 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) { @@ -192,7 +775,7 @@ void krb5_stdcc_shutdown() { if (gCntrlBlock) cc_shutdown(&gCntrlBlock); - gCntrlBlock = 0; + gCntrlBlock = NULL; } /* @@ -289,9 +872,10 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_resolve 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; @@ -388,7 +972,7 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_store /* 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; @@ -523,7 +1107,6 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_retrieve return KRB5_CC_NOTFOUND; } #else -#include "k5-int.h" krb5_error_code KRB5_CALLCONV krb5_stdcc_retrieve(context, id, whichfields, mcreds, creds) @@ -763,10 +1346,11 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_remove /* 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 diff --git a/src/lib/krb5/ccache/ccapi/stdcc.h b/src/lib/krb5/ccache/ccapi/stdcc.h index 81ce883cb..c0ce13b42 100644 --- a/src/lib/krb5/ccache/ccapi/stdcc.h +++ b/src/lib/krb5/ccache/ccapi/stdcc.h @@ -1,13 +1,17 @@ -#include "krb5.h" -#include "k5-int.h" +#include "k5-int.h" /* loads krb5.h */ +#ifdef USE_CCAPI_V3 +#include +#else #ifdef USE_CCAPI #include -#endif - +#else #if defined(_WIN32) #include "cacheapi.h" #endif +#endif +#endif + #define kStringLiteralLen 255 @@ -19,12 +23,71 @@ extern krb5_cc_ops krb5_cc_stdcc_ops; */ 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 @@ -78,3 +141,4 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_get_flags 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 diff --git a/src/lib/krb5/ccache/ccapi/stdcc_util.c b/src/lib/krb5/ccache/ccapi/stdcc_util.c index 7f9358dca..1969b6e71 100644 --- a/src/lib/krb5/ccache/ccapi/stdcc_util.c +++ b/src/lib/krb5/ccache/ccapi/stdcc_util.c @@ -19,6 +19,401 @@ #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 @@ -323,6 +718,86 @@ void dupK5toCC(krb5_context context, krb5_creds *creds, cred_union **cu) 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... */ @@ -475,81 +950,4 @@ int stdccCredsMatch(krb5_context context, krb5_creds *base, 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; -} diff --git a/src/lib/krb5/ccache/ccapi/stdcc_util.h b/src/lib/krb5/ccache/ccapi/stdcc_util.h index 92bafc8fa..7476313df 100644 --- a/src/lib/krb5/ccache/ccapi/stdcc_util.h +++ b/src/lib/krb5/ccache/ccapi/stdcc_util.h @@ -5,6 +5,9 @@ #include "autoconf.h" +#if USE_CCAPI_V3 +#include +#else #if USE_CCAPI #include #endif @@ -12,17 +15,29 @@ #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 diff --git a/src/lib/krb5/ccache/ccapi/winccld.h b/src/lib/krb5/ccache/ccapi/winccld.h index e285d1faf..245ae245e 100644 --- a/src/lib/krb5/ccache/ccapi/winccld.h +++ b/src/lib/krb5/ccache/ccapi/winccld.h @@ -6,12 +6,24 @@ #ifndef KRB5_WINCCLD_H_ #define KRB5_WINCCLD_H_ +#ifdef USE_CCAPI_V3 +#include +#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**); @@ -49,6 +61,7 @@ typedef cc_int32 (*FP_cc_seq_fetch_creds_end)(apiCB*, ccache_cit**); 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 { @@ -64,6 +77,7 @@ 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); @@ -100,10 +114,12 @@ DECL_FUNC_PTR(cc_seq_fetch_creds); 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), @@ -134,6 +150,7 @@ FUNC_INFO krbcc_fi[] = { 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 @@ -141,6 +158,7 @@ FUNC_INFO krbcc_fi[] = { #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 @@ -178,6 +196,7 @@ FUNC_INFO krbcc_fi[] = { #define cc_free_name pcc_free_name #define cc_free_creds pcc_free_creds #endif +#endif #undef DECL_FUNC_PTR -- 2.26.2