#if defined(_WIN32) || defined(USE_CCAPI)
#include "k5-int.h"
#include "stdcc.h"
#include "stdcc_util.h"
#include "string.h"
#include <stdio.h>
#if defined(_WIN32)
#include "winccld.h"
#endif
#ifndef CC_API_VER2
#define CC_API_VER2
#endif
#ifdef DEBUG
#if defined(_WIN32)
#include <io.h>
#define SHOW_DEBUG(buf) MessageBox((HWND)NULL, (buf), "ccapi debug", MB_OK)
#endif
#else
#define SHOW_DEBUG(buf)
#endif
#ifdef USE_CCAPI_V3
cc_context_t gCntrlBlock = NULL;
cc_int32 gCCVersion = 0;
#else
apiCB *gCntrlBlock = NULL;
#endif
krb5_cc_ops krb5_cc_stdcc_ops = {
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,
krb5_stdccv3_ptcursor_new,
krb5_stdccv3_ptcursor_next,
krb5_stdccv3_ptcursor_free,
NULL,
krb5_stdccv3_last_change_time,
NULL,
krb5_stdccv3_lock,
krb5_stdccv3_unlock,
#else
krb5_stdcc_get_name,
krb5_stdcc_resolve,
krb5_stdcc_generate_new,
krb5_stdcc_initialize,
krb5_stdcc_destroy,
krb5_stdcc_close,
krb5_stdcc_store,
krb5_stdcc_retrieve,
krb5_stdcc_get_principal,
krb5_stdcc_start_seq_get,
krb5_stdcc_next_cred,
krb5_stdcc_end_seq_get,
krb5_stdcc_remove,
krb5_stdcc_set_flags,
krb5_stdcc_get_flags,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
#endif
};
#if defined(_WIN32)
static void cache_changed()
{
static unsigned int message = 0;
if (message == 0)
message = RegisterWindowMessage(WM_KERBEROS5_CHANGED);
PostMessage(HWND_BROADCAST, message, 0, 0);
}
#else
static void cache_changed()
{
return;
}
#endif
struct err_xlate
{
int cc_err;
krb5_error_code krb5_err;
};
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_NOFILE },
{ ccErrInvalidCCache, KRB5_FCC_NOFILE },
{ 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_NOFILE },
{ ccErrServerUnavailable, KRB5_CC_IO },
{ ccErrServerInsecure, KRB5_CC_IO },
{ ccErrServerCantBecomeUID, KRB5_CC_IO },
{ 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_IO, KRB5_CC_IO },
{ CC_WRITE, KRB5_CC_WRITE },
{ CC_NOMEM, KRB5_CC_NOMEM },
{ CC_FORMAT, KRB5_CC_FORMAT },
{ CC_WRITE, KRB5_CC_WRITE },
{ CC_LOCKED, KRB5_FCC_INTERNAL },
{ CC_BAD_API_VERSION, KRB5_FCC_INTERNAL },
{ CC_NO_EXIST, KRB5_FCC_NOFILE },
{ CC_NOT_SUPP, KRB5_FCC_INTERNAL },
{ CC_BAD_PARM, KRB5_FCC_INTERNAL },
{ CC_ERR_CACHE_ATTACH, KRB5_FCC_INTERNAL },
{ CC_ERR_CACHE_RELEASE, KRB5_FCC_INTERNAL },
{ CC_ERR_CACHE_FULL, KRB5_FCC_INTERNAL },
{ CC_ERR_CRED_VERSION, KRB5_FCC_INTERNAL },
#endif
{ 0, 0 }
};
static krb5_error_code cc_err_xlate(int err)
{
const struct err_xlate *p;
#ifdef USE_CCAPI_V3
if (err == ccNoError)
return 0;
#else
if (err == CC_NOERROR)
return 0;
#endif
for (p = err_xlate_table; p->cc_err; p++) {
if (err == p->cc_err)
return p->krb5_err;
}
return KRB5_FCC_INTERNAL;
}
#ifdef USE_CCAPI_V3
static krb5_error_code stdccv3_get_timeoffset (krb5_context in_context,
cc_ccache_t in_ccache)
{
krb5_error_code err = 0;
if (gCCVersion >= ccapi_version_5) {
krb5_os_context os_ctx = (krb5_os_context) &in_context->os_context;
cc_time_t time_offset = 0;
err = cc_ccache_get_kdc_time_offset (in_ccache, cc_credentials_v5,
&time_offset);
if (!err) {
os_ctx->time_offset = time_offset;
os_ctx->usec_offset = 0;
os_ctx->os_flags = ((os_ctx->os_flags & ~KRB5_OS_TOFFSET_TIME) |
KRB5_OS_TOFFSET_VALID);
}
if (err == ccErrTimeOffsetNotSet) {
err = 0;
}
}
return err;
}
static krb5_error_code stdccv3_set_timeoffset (krb5_context in_context,
cc_ccache_t in_ccache)
{
krb5_error_code err = 0;
if (gCCVersion >= ccapi_version_5) {
krb5_os_context os_ctx = (krb5_os_context) &in_context->os_context;
if (!err && os_ctx->os_flags & KRB5_OS_TOFFSET_VALID) {
err = cc_ccache_set_kdc_time_offset (in_ccache,
cc_credentials_v5,
os_ctx->time_offset);
}
}
return err;
}
static krb5_error_code stdccv3_setup (krb5_context context,
stdccCacheDataPtr ccapi_data)
{
krb5_error_code err = 0;
if (!err && !gCntrlBlock) {
err = cc_initialize (&gCntrlBlock, ccapi_version_max, &gCCVersion, NULL);
}
if (!err && ccapi_data && !ccapi_data->NamedCache) {
err = cc_context_open_ccache (gCntrlBlock, ccapi_data->cache_name,
&ccapi_data->NamedCache);
}
if (!err && ccapi_data && ccapi_data->NamedCache) {
err = stdccv3_get_timeoffset (context, ccapi_data->NamedCache);
}
return err;
}
void krb5_stdcc_shutdown()
{
if (gCntrlBlock) { cc_context_release(gCntrlBlock); }
gCntrlBlock = NULL;
gCCVersion = 0;
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_generate_new (krb5_context context, krb5_ccache *id )
{
krb5_error_code err = 0;
krb5_ccache newCache = NULL;
stdccCacheDataPtr ccapi_data = NULL;
cc_ccache_t ccache = NULL;
cc_string_t ccstring = NULL;
char *name = NULL;
if (!err) {
err = stdccv3_setup(context, NULL);
}
if (!err) {
newCache = (krb5_ccache) malloc (sizeof (*newCache));
if (!newCache) { err = KRB5_CC_NOMEM; }
}
if (!err) {
ccapi_data = (stdccCacheDataPtr) malloc (sizeof (*ccapi_data));
if (!ccapi_data) { err = KRB5_CC_NOMEM; }
}
if (!err) {
err = cc_context_create_new_ccache (gCntrlBlock, cc_credentials_v5, "",
&ccache);
}
if (!err) {
err = stdccv3_set_timeoffset (context, ccache);
}
if (!err) {
err = cc_ccache_get_name (ccache, &ccstring);
}
if (!err) {
name = strdup (ccstring->data);
if (!name) { err = KRB5_CC_NOMEM; }
}
if (!err) {
ccapi_data->cache_name = name;
name = NULL;
ccapi_data->NamedCache = ccache;
ccache = NULL;
newCache->ops = &krb5_cc_stdcc_ops;
newCache->data = ccapi_data;
ccapi_data = NULL;
*id = newCache;
newCache = NULL;
}
if (ccstring) { cc_string_release (ccstring); }
if (name) { free (name); }
if (ccache) { cc_ccache_release (ccache); }
if (ccapi_data) { free (ccapi_data); }
if (newCache) { free (newCache); }
return cc_err_xlate (err);
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_resolve (krb5_context context, krb5_ccache *id , const char *residual )
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = NULL;
krb5_ccache ccache = NULL;
char *name = NULL;
if (id == NULL) { err = KRB5_CC_NOMEM; }
if (!err) {
err = stdccv3_setup (context, NULL);
}
if (!err) {
ccapi_data = (stdccCacheDataPtr) malloc (sizeof (*ccapi_data));
if (!ccapi_data) { err = KRB5_CC_NOMEM; }
}
if (!err) {
ccache = (krb5_ccache ) malloc (sizeof (*ccache));
if (!ccache) { err = KRB5_CC_NOMEM; }
}
if (!err) {
name = strdup (residual);
if (!name) { err = KRB5_CC_NOMEM; }
}
if (!err) {
err = cc_context_open_ccache (gCntrlBlock, residual,
&ccapi_data->NamedCache);
if (err == ccErrCCacheNotFound) {
ccapi_data->NamedCache = NULL;
err = 0;
}
}
if (!err) {
ccapi_data->cache_name = name;
name = NULL;
ccache->ops = &krb5_cc_stdcc_ops;
ccache->data = ccapi_data;
ccapi_data = NULL;
*id = ccache;
ccache = NULL;
}
if (ccache) { free (ccache); }
if (ccapi_data) { free (ccapi_data); }
if (name) { free (name); }
return cc_err_xlate (err);
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_initialize (krb5_context context,
krb5_ccache id,
krb5_principal princ)
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
char *name = NULL;
cc_ccache_t ccache = NULL;
if (id == NULL) { err = KRB5_CC_NOMEM; }
if (!err) {
err = stdccv3_setup (context, NULL);
}
if (!err) {
err = krb5_unparse_name(context, princ, &name);
}
if (!err) {
err = cc_context_create_ccache (gCntrlBlock, ccapi_data->cache_name,
cc_credentials_v5, name,
&ccache);
}
if (!err) {
err = stdccv3_set_timeoffset (context, ccache);
}
if (!err) {
if (ccapi_data->NamedCache) {
err = cc_ccache_release (ccapi_data->NamedCache);
}
ccapi_data->NamedCache = ccache;
ccache = NULL;
cache_changed ();
}
if (ccache) { cc_ccache_release (ccache); }
if (name ) { krb5_free_unparsed_name(context, name); }
return cc_err_xlate(err);
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_store (krb5_context context, krb5_ccache id, krb5_creds *creds )
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
cc_credentials_union *cred_union = NULL;
if (!err) {
err = stdccv3_setup (context, ccapi_data);
}
if (!err) {
err = copy_krb5_creds_to_cc_cred_union (context, creds, &cred_union);
}
if (!err) {
err = cc_ccache_store_credentials (ccapi_data->NamedCache, cred_union);
}
if (!err) {
cache_changed();
}
if (cred_union) { cred_union_release (cred_union); }
return cc_err_xlate (err);
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_start_seq_get (krb5_context context,
krb5_ccache id,
krb5_cc_cursor *cursor )
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
cc_credentials_iterator_t iterator = NULL;
if (!err) {
err = stdccv3_setup (context, ccapi_data);
}
if (!err) {
err = cc_ccache_new_credentials_iterator(ccapi_data->NamedCache,
&iterator);
}
if (!err) {
*cursor = iterator;
}
return cc_err_xlate (err);
}
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 err = 0;
stdccCacheDataPtr ccapi_data = id->data;
cc_credentials_t credentials = NULL;
cc_credentials_iterator_t iterator = *cursor;
if (!iterator) { err = KRB5_CC_END; }
if (!err) {
err = stdccv3_setup (context, ccapi_data);
}
while (!err) {
err = cc_credentials_iterator_next (iterator, &credentials);
if (!err && (credentials->data->version == cc_credentials_v5)) {
copy_cc_cred_union_to_krb5_creds(context, credentials->data, creds);
break;
}
}
if (credentials) { cc_credentials_release (credentials); }
if (err == ccIteratorEnd) {
cc_credentials_iterator_release (iterator);
*cursor = 0;
}
return cc_err_xlate (err);
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_retrieve (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);
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_end_seq_get (krb5_context context,
krb5_ccache id,
krb5_cc_cursor *cursor)
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
cc_credentials_iterator_t iterator = *cursor;
if (!iterator) { return 0; }
if (!err) {
err = stdccv3_setup (context, ccapi_data);
}
if (!err) {
err = cc_credentials_iterator_release(iterator);
}
return cc_err_xlate(err);
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_close(krb5_context context,
krb5_ccache id)
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
if (!err) {
err = stdccv3_setup (context, NULL);
}
if (!err) {
if (ccapi_data) {
if (ccapi_data->cache_name) {
free (ccapi_data->cache_name);
}
if (ccapi_data->NamedCache) {
err = cc_ccache_release (ccapi_data->NamedCache);
}
free (ccapi_data);
id->data = NULL;
}
free (id);
}
return cc_err_xlate(err);
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_destroy (krb5_context context,
krb5_ccache id)
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
if (!err) {
err = stdccv3_setup(context, ccapi_data);
}
if (!err) {
if (ccapi_data) {
if (ccapi_data->cache_name) {
free(ccapi_data->cache_name);
}
if (ccapi_data->NamedCache) {
err = cc_ccache_destroy(ccapi_data->NamedCache);
if (err == ccErrCCacheNotFound) {
err = 0;
}
cache_changed();
}
free(ccapi_data);
id->data = NULL;
}
free(id);
}
return cc_err_xlate(err);
}
const char * KRB5_CALLCONV
krb5_stdccv3_get_name (krb5_context context,
krb5_ccache id )
{
stdccCacheDataPtr ccapi_data = id->data;
if (!ccapi_data) {
return NULL;
} else {
return (ccapi_data->cache_name);
}
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_get_principal (krb5_context context,
krb5_ccache id ,
krb5_principal *princ)
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
cc_string_t name = NULL;
if (!err) {
err = stdccv3_setup(context, ccapi_data);
}
if (!err) {
err = cc_ccache_get_principal (ccapi_data->NamedCache, cc_credentials_v5, &name);
}
if (!err) {
err = krb5_parse_name (context, name->data, princ);
}
if (name) { cc_string_release (name); }
return cc_err_xlate (err);
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_set_flags (krb5_context context,
krb5_ccache id,
krb5_flags flags)
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
err = stdccv3_setup (context, ccapi_data);
return cc_err_xlate (err);
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_get_flags (krb5_context context,
krb5_ccache id,
krb5_flags *flags)
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
err = stdccv3_setup (context, ccapi_data);
return cc_err_xlate (err);
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_remove (krb5_context context,
krb5_ccache id,
krb5_flags whichfields,
krb5_creds *in_creds)
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
cc_credentials_iterator_t iterator = NULL;
int found = 0;
if (!err) {
err = stdccv3_setup(context, ccapi_data);
}
if (!err) {
err = cc_ccache_new_credentials_iterator(ccapi_data->NamedCache,
&iterator);
}
while (!err && !found) {
cc_credentials_t credentials = NULL;
err = cc_credentials_iterator_next (iterator, &credentials);
if (!err && (credentials->data->version == cc_credentials_v5)) {
krb5_creds creds;
err = copy_cc_cred_union_to_krb5_creds(context,
credentials->data, &creds);
if (!err) {
found = krb5int_cc_creds_match_request(context,
whichfields,
in_creds,
&creds);
krb5_free_cred_contents (context, &creds);
}
if (!err && found) {
err = cc_ccache_remove_credentials (ccapi_data->NamedCache, credentials);
}
}
if (credentials) { cc_credentials_release (credentials); }
}
if (err == ccIteratorEnd) { err = ccErrCredentialsNotFound; }
if (iterator) cc_credentials_iterator_release (iterator);
if (!err) {
cache_changed ();
}
return cc_err_xlate (err);
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_ptcursor_new(krb5_context context,
krb5_cc_ptcursor *cursor)
{
krb5_error_code err = 0;
krb5_cc_ptcursor ptcursor = NULL;
cc_ccache_iterator_t iterator = NULL;
ptcursor = malloc(sizeof(*ptcursor));
if (ptcursor == NULL) {
err = ENOMEM;
}
else {
memset(ptcursor, 0, sizeof(*ptcursor));
}
if (!err) {
err = stdccv3_setup(context, NULL);
}
if (!err) {
ptcursor->ops = &krb5_cc_stdcc_ops;
err = cc_context_new_ccache_iterator(gCntrlBlock, &iterator);
}
if (!err) {
ptcursor->data = iterator;
}
if (err) {
if (ptcursor) { krb5_stdccv3_ptcursor_free(context, &ptcursor); }
}
*cursor = ptcursor;
return err;
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_ptcursor_next(
krb5_context context,
krb5_cc_ptcursor cursor,
krb5_ccache *ccache)
{
krb5_error_code err = 0;
cc_ccache_iterator_t iterator = NULL;
krb5_ccache newCache = NULL;
stdccCacheDataPtr ccapi_data = NULL;
cc_ccache_t ccCache = NULL;
cc_string_t ccstring = NULL;
char *name = NULL;
if (!cursor || !cursor->data) {
err = ccErrInvalidContext;
}
*ccache = NULL;
if (!err) {
newCache = (krb5_ccache) malloc (sizeof (*newCache));
if (!newCache) { err = KRB5_CC_NOMEM; }
}
if (!err) {
ccapi_data = (stdccCacheDataPtr) malloc (sizeof (*ccapi_data));
if (!ccapi_data) { err = KRB5_CC_NOMEM; }
}
if (!err) {
iterator = cursor->data;
err = cc_ccache_iterator_next(iterator, &ccCache);
}
if (!err) {
err = cc_ccache_get_name (ccCache, &ccstring);
}
if (!err) {
name = strdup (ccstring->data);
if (!name) { err = KRB5_CC_NOMEM; }
}
if (!err) {
ccapi_data->cache_name = name;
name = NULL;
ccapi_data->NamedCache = ccCache;
ccCache = NULL;
newCache->ops = &krb5_cc_stdcc_ops;
newCache->data = ccapi_data;
ccapi_data = NULL;
*ccache = newCache;
newCache = NULL;
}
if (name) { free (name); }
if (ccstring) { cc_string_release (ccstring); }
if (ccCache) { cc_ccache_release (ccCache); }
if (ccapi_data) { free (ccapi_data); }
if (newCache) { free (newCache); }
if (err == ccIteratorEnd) {
err = ccNoError;
}
return err;
}
krb5_error_code KRB5_CALLCONV
krb5_stdccv3_ptcursor_free(
krb5_context context,
krb5_cc_ptcursor *cursor)
{
if (*cursor != NULL) {
if ((*cursor)->data != NULL) {
cc_ccache_iterator_release((cc_ccache_iterator_t)((*cursor)->data));
}
free(*cursor);
*cursor = NULL;
}
return 0;
}
krb5_error_code KRB5_CALLCONV krb5_stdccv3_last_change_time
(krb5_context context, krb5_ccache id,
krb5_timestamp *change_time)
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
cc_time_t ccapi_change_time = 0;
*change_time = 0;
if (!err) {
err = stdccv3_setup(context, ccapi_data);
}
if (!err) {
err = cc_ccache_get_change_time (ccapi_data->NamedCache, &ccapi_change_time);
}
if (!err) {
*change_time = ccapi_change_time;
}
return cc_err_xlate (err);
}
krb5_error_code KRB5_CALLCONV krb5_stdccv3_lock
(krb5_context context, krb5_ccache id)
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
if (!err) {
err = stdccv3_setup(context, ccapi_data);
}
if (!err) {
err = cc_ccache_lock(ccapi_data->NamedCache, cc_lock_write, cc_lock_block);
}
return cc_err_xlate(err);
}
krb5_error_code KRB5_CALLCONV krb5_stdccv3_unlock
(krb5_context context, krb5_ccache id)
{
krb5_error_code err = 0;
stdccCacheDataPtr ccapi_data = id->data;
if (!err) {
err = stdccv3_setup(context, ccapi_data);
}
if (!err) {
err = cc_ccache_unlock(ccapi_data->NamedCache);
}
return cc_err_xlate(err);
}
krb5_error_code KRB5_CALLCONV krb5_stdccv3_context_lock
(krb5_context context)
{
krb5_error_code err = 0;
if (!err && !gCntrlBlock) {
err = cc_initialize (&gCntrlBlock, ccapi_version_max, &gCCVersion, NULL);
}
if (!err) {
err = cc_context_lock(gCntrlBlock, cc_lock_write, cc_lock_block);
}
return cc_err_xlate(err);
}
krb5_error_code KRB5_CALLCONV krb5_stdccv3_context_unlock
(krb5_context context)
{
krb5_error_code err = 0;
if (!err && !gCntrlBlock) {
err = cc_initialize (&gCntrlBlock, ccapi_version_max, &gCCVersion, NULL);
}
if (!err) {
err = cc_context_unlock(gCntrlBlock);
}
return cc_err_xlate(err);
}
#else
static krb5_error_code stdcc_setup(krb5_context context,
stdccCacheDataPtr ccapi_data)
{
int err;
if (gCntrlBlock == NULL) {
#ifdef CC_API_VER2
err = cc_initialize(&gCntrlBlock, CC_API_VER_2, NULL, NULL);
#else
err = cc_initialize(&gCntrlBlock, CC_API_VER_1, NULL, NULL);
#endif
if (err != CC_NOERROR)
return cc_err_xlate(err);
}
if (!ccapi_data)
return 0;
if (ccapi_data->NamedCache)
return 0;
err = cc_open(gCntrlBlock, ccapi_data->cache_name,
CC_CRED_V5, 0L, &ccapi_data->NamedCache);
if (err == CC_NOTFOUND)
err = CC_NO_EXIST;
if (err == CC_NOERROR)
return 0;
ccapi_data->NamedCache = NULL;
return cc_err_xlate(err);
}
void krb5_stdcc_shutdown()
{
if (gCntrlBlock)
cc_shutdown(&gCntrlBlock);
gCntrlBlock = NULL;
}
krb5_error_code KRB5_CALLCONV krb5_stdcc_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_t change_time;
int err;
if ((retval = stdcc_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;
cc_get_change_time(gCntrlBlock, &change_time);
snprintf(name, 256, "gen_new_cache%d", change_time);
err = cc_create(gCntrlBlock, name, name, CC_CRED_V5, 0L,
&ccapi_data->NamedCache);
if (err != CC_NOERROR) {
retval = cc_err_xlate(err);
goto errout;
}
newCache->ops = &krb5_cc_stdcc_ops;
newCache->data = ccapi_data;
ccapi_data->cache_name = name;
*id = newCache;
return 0;
errout:
if (newCache)
free(newCache);
if (ccapi_data)
free(ccapi_data);
if (name)
free(name);
return retval;
}
krb5_error_code KRB5_CALLCONV krb5_stdcc_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 = stdcc_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 = strdup(residual)))
goto errout;
newCache->ops = &krb5_cc_stdcc_ops;
newCache->data = ccapi_data;
ccapi_data->cache_name = cName;
err = cc_open(gCntrlBlock, cName, CC_CRED_V5, 0L,
&ccapi_data->NamedCache);
if (err != CC_NOERROR) {
ccapi_data->NamedCache = NULL;
if (err != CC_NO_EXIST) {
retval = cc_err_xlate(err);
goto errout;
}
}
*id = newCache;
return 0;
errout:
if (newCache)
free(newCache);
if (ccapi_data)
free(ccapi_data);
if (cName)
free(cName);
return retval;
}
krb5_error_code KRB5_CALLCONV krb5_stdcc_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 = stdcc_setup(context, NULL)))
return retval;
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)
cc_close(gCntrlBlock, &ccapi_data->NamedCache);
err = cc_create(gCntrlBlock, ccapi_data->cache_name, cName,
CC_CRED_V5, 0L, &ccapi_data->NamedCache);
if (err != CC_NOERROR) {
krb5_free_unparsed_name(context, cName);
return cc_err_xlate(err);
}
#if 0
err = cc_set_principal(gCntrlBlock, ccapi_data->NamedCache,
CC_CRED_V5, cName);
#endif
krb5_free_unparsed_name(context, cName);
cache_changed();
return cc_err_xlate(err);
}
krb5_error_code KRB5_CALLCONV krb5_stdcc_store
(krb5_context context, krb5_ccache id, krb5_creds *creds )
{
krb5_error_code retval;
stdccCacheDataPtr ccapi_data = id->data;
cred_union *cu = NULL;
int err;
if ((retval = stdcc_setup(context, ccapi_data)))
return retval;
dupK5toCC(context, creds, &cu);
err = cc_store(gCntrlBlock,
((stdccCacheDataPtr)(id->data))->NamedCache, *cu);
if (err != CC_NOERROR)
return cc_err_xlate(err);
err = krb5int_free_cc_cred_union(&cu);
cache_changed();
return err;
}
krb5_error_code KRB5_CALLCONV krb5_stdcc_start_seq_get
(krb5_context context, krb5_ccache id , krb5_cc_cursor *cursor )
{
stdccCacheDataPtr ccapi_data = id->data;
krb5_error_code retval;
int err;
ccache_cit *iterator;
if ((retval = stdcc_setup(context, ccapi_data)))
return retval;
#ifdef CC_API_VER2
err = cc_seq_fetch_creds_begin(gCntrlBlock, ccapi_data->NamedCache,
&iterator);
if (err != CC_NOERROR)
return cc_err_xlate(err);
*cursor = iterator;
#else
*cursor = NULL;
#endif
return 0;
}
krb5_error_code KRB5_CALLCONV krb5_stdcc_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;
cred_union *credU = NULL;
ccache_cit *iterator;
if ((retval = stdcc_setup(context, ccapi_data)))
return retval;
#ifdef CC_API_VER2
iterator = *cursor;
if (iterator == 0)
return KRB5_CC_END;
err = cc_seq_fetch_creds_next(gCntrlBlock, &credU, iterator);
if (err == CC_END) {
cc_seq_fetch_creds_end(gCntrlBlock, &iterator);
*cursor = 0;
}
#else
err = cc_seq_fetch_creds(gCntrlBlock, ccapi_data->NamedCache,
&credU, (ccache_cit **)cursor);
#endif
if (err != CC_NOERROR)
return cc_err_xlate(err);
dupCCtoK5(context, credU->cred.pV5Cred, creds);
cc_free_creds(gCntrlBlock, &credU);
return 0;
}
#if 0
krb5_error_code KRB5_CALLCONV krb5_stdcc_retrieve
(krb5_context context,
krb5_ccache id,
krb5_flags whichfields,
krb5_creds *mcreds,
krb5_creds *creds )
{
krb5_error_code retval;
krb5_cc_cursor curs = NULL;
krb5_creds *fetchcreds;
if ((retval = stdcc_setup(context, NULL)))
return retval;
fetchcreds = (krb5_creds *)malloc(sizeof(krb5_creds));
if (fetchcreds == NULL) return KRB5_CC_NOMEM;
krb5_stdcc_start_seq_get(context, id, &curs);
while (!krb5_stdcc_next_cred(context, id, &curs, fetchcreds)) {
if (stdccCredsMatch(context, fetchcreds,
mcreds, whichfields)) {
*creds = *fetchcreds;
krb5_stdcc_end_seq_get(context, id, &curs);
return 0;
}
krb5_free_cred_contents(context, fetchcreds);
}
krb5_stdcc_end_seq_get(context, id, &curs);
free(fetchcreds);
return KRB5_CC_NOTFOUND;
}
#else
krb5_error_code KRB5_CALLCONV
krb5_stdcc_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);
}
#endif
krb5_error_code KRB5_CALLCONV krb5_stdcc_end_seq_get
(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
{
krb5_error_code retval;
stdccCacheDataPtr ccapi_data = NULL;
int err;
#ifndef CC_API_VER2
cred_union *credU = NULL;
#endif
ccapi_data = id->data;
if ((retval = stdcc_setup(context, ccapi_data)))
return retval;
if (*cursor == NULL)
return 0;
#ifdef CC_API_VER2
err = cc_seq_fetch_creds_end(gCntrlBlock, (ccache_cit **)cursor);
if (err != CC_NOERROR)
return cc_err_xlate(err);
#else
while (*cursor) {
err = cc_seq_fetch_creds(gCntrlBlock, ccapi_data->NamedCache,
&credU, (ccache_cit **)cursor);
if (err)
break;
cc_free_creds(gCntrlBlock, &credU);
}
#endif
return(0);
}
krb5_error_code KRB5_CALLCONV
krb5_stdcc_close(krb5_context context, krb5_ccache id)
{
krb5_error_code retval;
stdccCacheDataPtr ccapi_data = id->data;
if ((retval = stdcc_setup(context, NULL)))
return retval;
if (ccapi_data) {
if (ccapi_data->cache_name)
free(ccapi_data->cache_name);
if (ccapi_data->NamedCache)
cc_close(gCntrlBlock, &ccapi_data->NamedCache);
free(ccapi_data);
id->data = NULL;
}
free(id);
return 0;
}
krb5_error_code KRB5_CALLCONV
krb5_stdcc_destroy (krb5_context context, krb5_ccache id)
{
int err;
krb5_error_code retval;
stdccCacheDataPtr ccapi_data = id->data;
if ((retval = stdcc_setup(context, ccapi_data))) {
return retval;
}
if (ccapi_data) {
if (ccapi_data->cache_name)
free(ccapi_data->cache_name);
if (ccapi_data->NamedCache) {
err = cc_destroy(gCntrlBlock, &ccapi_data->NamedCache);
retval = cc_err_xlate(err);
cache_changed();
}
free(ccapi_data);
id->data = NULL;
}
free(id);
if (retval == KRB5_FCC_NOFILE)
return 0;
return retval;
}
const char * KRB5_CALLCONV krb5_stdcc_get_name
(krb5_context context, krb5_ccache id )
{
stdccCacheDataPtr ccapi_data = id->data;
if (!ccapi_data)
return 0;
return (ccapi_data->cache_name);
}
krb5_error_code KRB5_CALLCONV krb5_stdcc_get_principal
(krb5_context context, krb5_ccache id , krb5_principal *princ)
{
int err;
char *name = NULL;
stdccCacheDataPtr ccapi_data = id->data;
krb5_error_code retval;
if ((retval = stdcc_setup(context, ccapi_data)))
return retval;
err = cc_get_principal(gCntrlBlock, ccapi_data->NamedCache,
&name);
if (err != CC_NOERROR)
return cc_err_xlate(err);
err = krb5_parse_name(context, name, princ);
cc_free_principal(gCntrlBlock, &name);
return err;
}
krb5_error_code KRB5_CALLCONV krb5_stdcc_set_flags
(krb5_context context, krb5_ccache id , krb5_flags flags)
{
stdccCacheDataPtr ccapi_data = id->data;
krb5_error_code retval;
if ((retval = stdcc_setup(context, ccapi_data)))
return retval;
return 0;
}
krb5_error_code KRB5_CALLCONV krb5_stdcc_get_flags
(krb5_context context, krb5_ccache id , krb5_flags *flags)
{
stdccCacheDataPtr ccapi_data = id->data;
krb5_error_code retval;
if ((retval = stdcc_setup(context, ccapi_data)))
return retval;
return 0;
}
krb5_error_code KRB5_CALLCONV krb5_stdcc_remove
(krb5_context context, krb5_ccache id,
krb5_flags flags, krb5_creds *creds)
{
cred_union *cu = NULL;
int err;
stdccCacheDataPtr ccapi_data = id->data;
krb5_error_code retval;
if ((retval = stdcc_setup(context, ccapi_data))) {
if (retval == KRB5_FCC_NOFILE)
return 0;
return retval;
}
dupK5toCC(context, creds, &cu);
err = cc_remove_cred(gCntrlBlock, ccapi_data->NamedCache, *cu);
if (err != CC_NOERROR)
return cc_err_xlate(err);
err = krb5int_free_cc_cred_union(&cu);
cache_changed();
if (err != CC_NOERROR)
return cc_err_xlate(err);
return 0;
}
#endif
#endif