#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "CredentialsCache.h"
#include "datastore.h"
cc_int32
cci_ccache_new( char *name, char *principal, int cred_vers,
cc_server_ccache_t** outCCachepp)
{
cc_server_ccache_t* ccache;
if (name == NULL || principal == NULL)
return ccErrInvalidString;
if (cred_vers != cc_credentials_v4 && cred_vers != cc_credentials_v5 &&
cred_vers != cc_credentials_v4_v5)
return ccErrBadCredentialsVersion;
if (outCCachepp == NULL)
return ccErrBadParam;
ccache = (cc_server_ccache_t*)malloc(sizeof(cc_server_ccache_t));
if (ccache == NULL)
return ccErrNoMem;
ccache->name = name;
ccache->principal_v4 = NULL;
ccache->principal_v5 = NULL;
ccache->changed = time(NULL);
ccache->kdc_offset = 0;
ccache->last_default = 0;
cci_generic_list_new(&ccache->active_iterators);
cci_credentials_list_new(&ccache->creds);
ccache->is_default = 0;
ccache->kdc_set = 0;
ccache->versions = cred_vers;
ccache->mycontext = NULL;
cci_ccache_set_principal(ccache, cred_vers, principal);
*outCCachepp = ccache;
return ccNoError;
}
cc_int32
cci_ccache_check_version( const cc_server_ccache_t *ccache,
const cc_credentials_union* creds,
cc_uint32* compat)
{
if (ccache == NULL)
return ccErrInvalidCCache;
if (creds == NULL || compat == NULL)
return ccErrBadParam;
if (ccache->versions == cc_credentials_v4_v5)
*compat = 1;
else if (ccache->versions == creds->version)
*compat = 1;
else
*compat = 0;
return ccNoError;
}
cc_int32
cci_ccache_check_principal( const cc_server_ccache_t *ccache,
const cc_credentials_union* creds,
cc_uint32* compat)
{
if (ccache == NULL)
return ccErrInvalidCCache;
if (creds == NULL || compat == NULL)
return ccErrBadParam;
if (creds->version == cc_credentials_v4) {
if (strcmp(creds->credentials.credentials_v4->principal, ccache->principal_v4) == 0)
*compat = 1;
else
*compat = 0;
} else if (creds->version == cc_credentials_v5) {
if (strcmp(creds->credentials.credentials_v5->client, ccache->principal_v5) == 0)
*compat = 1;
else
*compat = 0;
} else {
return ccErrBadCredentialsVersion;
}
return ccNoError;
}
cc_int32
cci_ccache_store_creds(cc_server_ccache_t *ccache, const cc_credentials_union* credentials)
{
cc_server_credentials_t* stored_cred=NULL;
cc_uint32 valid_version, valid_principal;
cc_int32 code;
if (ccache == NULL)
return ccErrInvalidCCache;
if (credentials == NULL)
return ccErrBadParam;
code = cci_ccache_check_version(ccache, credentials, &valid_version);
if (code != ccNoError) {
goto bad;
}
code = cci_ccache_check_principal(ccache, credentials, &valid_principal);
if (code != ccNoError) {
goto bad;
}
if (valid_version && valid_principal) {
stored_cred = (cc_server_credentials_t*)malloc(sizeof(cc_server_credentials_t));
if (stored_cred == NULL) {
code = ccErrNoMem;
goto bad;
}
memcpy(&stored_cred->creds, credentials, sizeof(cc_credentials_union));
if (credentials->version == cc_credentials_v4) {
stored_cred->creds.credentials.credentials_v4 = (cc_credentials_v4_t*)malloc(sizeof(cc_credentials_v4_t));
if (stored_cred->creds.credentials.credentials_v4 == NULL) {
code = ccErrNoMem;
goto bad;
}
memcpy(stored_cred->creds.credentials.credentials_v4, credentials->credentials.credentials_v4, sizeof(cc_credentials_v4_t));
} else if (credentials->version == cc_credentials_v5) {
stored_cred->creds.credentials.credentials_v5 = (cc_credentials_v5_t*)malloc(sizeof(cc_credentials_v5_t));
if (stored_cred->creds.credentials.credentials_v5 == NULL) {
code = ccErrNoMem;
goto bad;
}
memcpy(stored_cred->creds.credentials.credentials_v5, credentials->credentials.credentials_v5, sizeof(cc_credentials_v5_t));
} else {
code = ccErrBadCredentialsVersion;
goto bad;
}
code = cci_credentials_list_append(ccache->creds, stored_cred, NULL);
if ( code != ccNoError ) {
goto bad;
}
if (ccache->creds->head->data == (cc_uint8 *)stored_cred)
stored_cred->is_default = 1;
cci_ccache_changed(ccache);
return ccNoError;
} else {
#ifdef DEBUG
printf("vers: %d\tprincipal: %d\n",
valid_version, valid_principal);
#endif
code = ccErrInvalidCredentials;
goto bad;
}
bad:
if (stored_cred)
free(stored_cred);
return code;
}
void
cci_ccache_changed(cc_server_ccache_t* ccache)
{
ccache->changed = time(NULL);
if (ccache->mycontext != NULL)
ccache->mycontext->changed = time(NULL);
}
cc_int32
cci_ccache_rem_creds(cc_server_ccache_t *ccache, const cc_credentials_union* credentials)
{
cc_credentials_iterate_t* credentials_iterator=NULL, *active;
cc_generic_iterate_t* generic_iterator=NULL;
cc_credentials_list_node_t* credentials_node;
cc_generic_list_node_t* generic_node;
cc_server_credentials_t* stored_cred;
cc_int8 changed = 0;
cc_int32 code = 0;
if (ccache == NULL)
return ccErrInvalidCCache;
if (credentials == NULL)
return ccErrBadParam;
code = cci_credentials_list_iterator(ccache->creds, &credentials_iterator);
if (code != ccNoError) {
goto cleanup;
}
while (cci_credentials_iterate_has_next(credentials_iterator)) {
code = cci_credentials_iterate_next(credentials_iterator, &credentials_node);
stored_cred = (cc_server_credentials_t*)credentials_node->data;
if (memcmp(&stored_cred->creds,credentials,sizeof(cc_credentials_union)) == 0) {
free(credentials_node->data);
changed = 1;
code = cci_generic_list_iterator(ccache->active_iterators, &generic_iterator);
while (cci_generic_iterate_has_next(generic_iterator)) {
code = cci_generic_iterate_next(generic_iterator, &generic_node);
active = (cc_credentials_iterate_t*)generic_node->data;
if (active->next == credentials_node)
active->next = active->next->next;
}
code = cci_generic_free_iterator(generic_iterator);
generic_iterator = NULL;
if (credentials_node == ccache->creds->head) {
code = cci_credentials_list_remove_element(ccache->creds, credentials_node);
if (ccache->creds->head != NULL)
((cc_server_credentials_t*)ccache->creds->head->data)->is_default = 1;
} else {
code = cci_credentials_list_remove_element(ccache->creds, credentials_node);
}
break;
}
}
cleanup:
if (changed)
cci_ccache_changed(ccache);
if (credentials_iterator)
cci_credentials_free_iterator(credentials_iterator);
if (generic_iterator)
cci_generic_free_iterator(generic_iterator);
return code;
}
cc_int32
cci_ccache_move(cc_server_ccache_t *source, cc_server_ccache_t* destination)
{
cc_generic_list_node_t* node;
cc_generic_iterate_t* iterator;
cc_credentials_iterate_t* cur;
cc_int32 code;
if (source == NULL || destination == NULL)
return ccErrBadParam;
code = cci_credentials_list_destroy(destination->creds);
if ( code != ccNoError )
return code;
code = cci_credentials_list_copy(source->creds, &destination->creds);
if ( code != ccNoError )
return code;
destination->versions = source->versions;
destination->kdc_offset = source->kdc_offset;
destination->last_default = 0;
if (destination->active_iterators->head != NULL) {
code = cci_generic_list_iterator(destination->active_iterators, &iterator);
while (cci_generic_iterate_has_next(iterator)) {
code = cci_generic_iterate_next(iterator, &node);
cur = (cc_credentials_iterate_t*)node->data;
cur->next = destination->creds->head;
}
code = cci_generic_free_iterator(iterator);
}
cci_ccache_changed(destination);
return code;
}
cc_int32
cci_ccache_get_kdc_time_offset(cc_server_ccache_t* ccache, cc_time_t* offset)
{
if (ccache == NULL)
return ccErrInvalidCCache;
if (offset == NULL)
return ccErrBadParam;
if (!ccache->kdc_set)
return ccErrTimeOffsetNotSet;
*offset = ccache->kdc_offset;
return ccNoError;
}
cc_int32
cci_ccache_set_kdc_time_offset(cc_server_ccache_t* ccache, cc_time_t offset)
{
if (ccache == NULL)
return ccErrInvalidCCache;
ccache->kdc_offset = offset;
ccache->kdc_set = 1;
cci_ccache_changed(ccache);
return ccNoError;
}
cc_int32
cci_ccache_clear_kdc_time_offset(cc_server_ccache_t* ccache)
{
if (ccache == NULL)
return ccErrInvalidCCache;
ccache->kdc_offset = 0;
ccache->kdc_set = 0;
cci_ccache_changed(ccache);
return ccNoError;
}
cc_int32
cci_ccache_new_iterator(cc_server_ccache_t* ccache, cc_credentials_iterate_t** iterator)
{
cc_int32 code;
if (ccache == NULL)
return ccErrInvalidCCache;
if (iterator == NULL)
return ccErrBadParam;
code = cci_credentials_list_iterator(ccache->creds, iterator);
if (code != ccNoError)
return code;
code = cci_generic_list_prepend(ccache->active_iterators, *iterator, sizeof(cc_credentials_iterate_t), NULL);
if (code != ccNoError)
return code;
return ccNoError;
}
cc_int32
cci_ccache_get_principal(cc_server_ccache_t* ccache, cc_int32 version, char ** principal)
{
char *p = NULL;
switch ( version ) {
case cc_credentials_v4:
p = ccache->principal_v4;
break;
case cc_credentials_v5:
p = ccache->principal_v5;
break;
default:
return ccErrBadCredentialsVersion;
}
*principal = (char *)malloc(strlen(p)+1);
if ( *principal == NULL )
return ccErrNoMem;
strcpy(*principal, p);
return ccNoError;
}
cc_int32
cci_ccache_free_principal(char * principal)
{
if ( principal == NULL )
return ccErrBadParam;
free(principal);
return ccNoError;
}
cc_int32
cci_ccache_set_principal( cc_server_ccache_t* ccache, cc_int32 cred_version,
char* principal)
{
cc_generic_iterate_t* generic_iterator;
cc_generic_list_node_t* generic_node;
cc_ccache_iterate_t* ccache_iterator;
cc_int32 code = ccNoError;
if (ccache == NULL)
return ccErrInvalidCCache;
if (principal == NULL)
return ccErrInvalidString;
switch (cred_version) {
case cc_credentials_v4:
case cc_credentials_v4_v5:
ccache->principal_v4 = (char *)malloc(strlen(principal) + 1);
if (ccache->principal_v4 == NULL)
return ccErrNoMem;
strcpy(ccache->principal_v4, principal);
if (cred_version != cc_credentials_v4_v5)
break;
case cc_credentials_v5:
ccache->principal_v5 = (char *)malloc(strlen(principal) + 1);
if (ccache->principal_v5 == NULL) {
if (cred_version == cc_credentials_v4_v5) {
free(ccache->principal_v4);
ccache->principal_v4 = NULL;
}
return ccErrNoMem;
}
strcpy(ccache->principal_v5, principal);
break;
default:
return ccErrBadCredentialsVersion;
}
if (ccache->mycontext != NULL && ccache->mycontext->api_version == ccapi_version_2) {
cci_credentials_list_destroy(ccache->creds);
cci_credentials_list_new(&ccache->creds);
code = cci_generic_list_iterator(ccache->active_iterators, &generic_iterator);
if (code == ccNoError) {
while (cci_generic_iterate_has_next(generic_iterator)) {
code = cci_generic_iterate_next(generic_iterator, &generic_node);
ccache_iterator = (cc_ccache_iterate_t*)generic_node->data;
ccache_iterator->next = NULL;
}
}
}
cci_ccache_changed(ccache);
return code;
}
cc_int32
cci_ccache_destroy(cc_server_ccache_t* ccache)
{
cc_int32 code;
if ( ccache == NULL )
return ccErrInvalidCCache;
code = cci_generic_list_destroy(ccache->active_iterators);
code = cci_credentials_list_destroy(ccache->creds);
if (ccache->mycontext != NULL)
code = cci_context_rem_ccache(ccache->mycontext, ccache);
return code;
}
cc_int32
cci_ccache_compare(cc_server_ccache_t* ccache1, cc_server_ccache_t* ccache2, cc_uint32 *result)
{
if ( ccache1 == NULL || ccache2 == NULL )
return ccErrInvalidCCache;
if (ccache1 == ccache2)
*result = 1;
else
*result = 0;
return ccNoError;
}