summaryrefslogtreecommitdiffstats
path: root/src/lib/ccapi/server/ccache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/ccapi/server/ccache.c')
-rw-r--r--src/lib/ccapi/server/ccache.c703
1 files changed, 703 insertions, 0 deletions
diff --git a/src/lib/ccapi/server/ccache.c b/src/lib/ccapi/server/ccache.c
new file mode 100644
index 000000000..2c3a745af
--- /dev/null
+++ b/src/lib/ccapi/server/ccache.c
@@ -0,0 +1,703 @@
+/* $Copyright:
+ *
+ * Copyright 2004 by the Massachusetts Institute of Technology.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require a
+ * specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute
+ * this software and its documentation for any purpose and without fee is
+ * hereby granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of M.I.T. not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. Furthermore if you
+ * modify this software you must label your software as modified software
+ * and not distribute it in such a fashion that it might be confused with
+ * the original MIT software. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Individual source code files are copyright MIT, Cygnus Support,
+ * OpenVision, Oracle, Sun Soft, FundsXpress, and others.
+ *
+ * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+ * and Zephyr are trademarks of the Massachusetts Institute of Technology
+ * (MIT). No commercial use of these trademarks may be made without prior
+ * written permission of MIT.
+ *
+ * "Commercial use" means use of a name in a product or other for-profit
+ * manner. It does NOT prevent a commercial firm from referring to the MIT
+ * trademarks in order to convey information (although in doing so,
+ * recognition of their trademark status should be given).
+ * $
+ */
+
+/*
+ * Manages ccache objects.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "CredentialsCache.h"
+#include "datastore.h"
+
+/**
+ * ccache_new()
+ *
+ * Purpose: Allocate and initialize new credentials cache for the specified principal
+ * and version
+ *
+ * Return: ccNoError - success
+ * ccErrInvalidString - name or principal is NULL
+ * ccErrBadCredentialsVersion - unsupported creds type
+ * ccErrBadParam - outCcachepp is NULL
+ * ccErrNoMem - malloc failed
+ */
+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;
+}
+
+/**
+ * cci_ccache_check_version()
+ *
+ * Purpose: Check to see if the ccache and the creds have compatible versions.
+ *
+ * Return: ccNoError and compat = 1 if they are compatible
+ * ccNoError and compat = 0 if they are not compatible
+ *
+ * Errors: ccErrInvalidCCache - ccache is NULL
+ * ccErrBadParam - either creds or compat are NULL
+ */
+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;
+}
+
+/**
+cci_ccache_check_principal()
+
+Check to see if the client principal from the credentials matches
+the principal associated with the cache.
+
+* Return: ccNoError and compat = 1 if they are compatible
+* ccNoError and compat = 0 if they are not compatible
+*
+* Errors: ccErrInvalidCCache - ccache is NULL
+* ccErrBadParam - either creds or compat are NULL
+* ccErrBadCredentialVersion - unsupported credential type
+*/
+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;
+}
+
+
+/**
+ * cci_ccache_store_creds()
+ *
+ * Purpose: Stores the provided credentials into the provided cache. Validates the
+ * ability of the cache to store credentials of the given version and client
+ * principal.
+ *
+ * Return: 0 on success
+ * -1 on error
+ *
+ * Errors: ccErrNoMem
+ * ccErrBadCredentialsVersion
+ * ccErrBadInvalidCredentials
+ * ccErrInvalidCache
+ * ccErrBadParam
+ */
+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) {
+ /* pass error on to caller */
+ goto bad;
+ }
+ code = cci_ccache_check_principal(ccache, credentials, &valid_principal);
+ if (code != ccNoError) {
+ /* pass error on to caller */
+ 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 ) {
+ /* pass error on to caller */
+ goto bad;
+ }
+ if (ccache->creds->head->data == (cc_uint8 *)stored_cred)
+ stored_cred->is_default = 1; /*we're first on the list, so we're default*/
+
+ cci_ccache_changed(ccache);
+ return ccNoError;
+ } else {
+#ifdef DEBUG
+ printf("vers: %d\tprincipal: %d\n",
+ valid_version, valid_principal);
+#endif /* DEBUG */
+ code = ccErrInvalidCredentials;
+ goto bad;
+ }
+
+ bad:
+ if (stored_cred)
+ free(stored_cred);
+ return code; /* error */
+}
+
+/**
+ * cci_ccache_changed()
+ *
+ * Purpose: Updates the last update time for the ccache and its associated context.
+ * Provides a location from which interested parties should be notified
+ * of cache updates.
+ *
+ * Return: none
+ *
+ * Errors: none
+ */
+void
+cci_ccache_changed(cc_server_ccache_t* ccache)
+{
+ ccache->changed = time(NULL);
+ if (ccache->mycontext != NULL)
+ ccache->mycontext->changed = time(NULL);
+
+ /* XXX - notify registered listeners when implemented */
+}
+
+/**
+ * cci_ccache_rem_creds()
+ *
+ * Purpose: Removes the specified credential object from the specified cache if
+ * it exists
+ *
+ * Return: 0 on success (credential is not in the cache)
+ * -1 on error
+ *
+ * Errors: ccErrBadParam, ccErrNoMem (from cc_credentials_list_iterator)
+ *
+ * Verify: does the memory associated with stored_cred->creds need to be freed?
+ *
+ */
+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) {
+ /* pass error to caller */
+ 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) {
+ /* XXX - do we need to free(stored_cred->creds) ? */
+ free(credentials_node->data);
+ changed = 1;
+
+ /*If any iterator's next points to the deleted node, make it point to the next node*/
+ 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) { /*removing the default, must make next cred default*/
+ 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;
+}
+
+/**
+ * cci_ccache_move()
+ *
+ * Purpose: Destroys the existing contents of the destination and copies
+ * all credentials from the source to the destination
+ *
+ * Return: 0 on success
+ * -1 on error
+ *
+ * Errors: ccBadNoMem
+ *
+ */
+
+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;
+
+ /*reset all active iterators to point to the head of the new creds list*/
+ 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;
+}
+
+/**
+ * cci_ccache_get_kdc_time_offset()
+ *
+ * Purpose: Retrieves the kdc_time_offset from the ccache if set
+ *
+ * Return: 0 on success
+ * -1 on error
+ *
+ * Errors: ccErrBadParam, ccErrTimeOffsetNotSet
+ *
+ */
+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;
+}
+
+/**
+ * cci_ccache_set_kdc_time_offset()
+ *
+ * Purpose: Sets the kdc time offset in the designated ccache
+ *
+ * Return: 0 on success
+ * -1 on error
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+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;
+}
+
+/**
+ * cci_ccache_clear_kdc_time_offset()
+ *
+ * Purpose: Clear the kdc time offset in the designated ccache
+ *
+ * Return: 0 on success
+ * -1 on error
+ *
+ * Errors: ccErrBadParam
+ */
+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;
+}
+
+/**
+ * cci_ccache_new_iterator()
+ *
+ * Purpose: Retrieve an iterator for the designated cache
+ *
+ * Return: 0 on success
+ * -1 on error
+ *
+ * Errors: ccErrBadParam, ccBadNoMem
+ */
+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;
+}
+
+/**
+ * cci_ccache_get_principal()
+ *
+ * Purpose: Retrieves the client principal associated with the designated cache.
+ * The value is returned
+ * Return:
+ *
+ * Errors:
+ */
+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;
+}
+
+/**
+ * Purpose: Releases the memory associated with a ccache principal
+ *
+ * Return:
+ *
+ * Errors:
+ *
+ */
+cc_int32
+cci_ccache_free_principal(char * principal)
+{
+ if ( principal == NULL )
+ return ccErrBadParam;
+
+ free(principal);
+ return ccNoError;
+}
+
+/**
+ * ccache_set_principal()
+ *
+ * Purpose: Assigns a principal to the designated ccache and credential version.
+ * If the api version is 2, the cache is cleared of all existing
+ * credentials.
+ *
+ * Return: 0 on success
+ * -1 on error
+ *
+ * Errors: ccErrNoMem, ccErrBadCredentialsVersion
+ */
+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;
+ /* fall-through if we are v4_v5 */
+ 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;
+ }
+
+ /*For API version 2 clients set_principal implies a flush of all creds*/
+ if (ccache->mycontext != NULL && ccache->mycontext->api_version == ccapi_version_2) {
+ cci_credentials_list_destroy(ccache->creds);
+ cci_credentials_list_new(&ccache->creds);
+
+ /*clean up active_iterators*/
+ 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;
+}
+
+/**
+ * cci_ccache_destroy()
+ *
+ * Purpose: Destroys an existing ccache
+ *
+ * Return: 0 on success
+ * -1 on errors
+ *
+ * Errors: ccErrBadParam
+ */
+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;
+}
+
+/**
+ * cci_ccache_compare()
+ *
+ * Purpose: Returns a boolean value indicating if two caches are identical
+ * Implemented as pointer equivalence.
+ *
+ * Return: 1 if TRUE
+ * 0 if FALSE
+ *
+ * Errors: No errors
+ */
+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;
+}
+