summaryrefslogtreecommitdiffstats
path: root/src/lib/ccapi/server
diff options
context:
space:
mode:
authorJeffrey Altman <jaltman@secure-endpoints.com>2004-10-27 20:48:07 +0000
committerJeffrey Altman <jaltman@secure-endpoints.com>2004-10-27 20:48:07 +0000
commit3c323c8486c538abcba3ec9bb4a6e8a4af20496c (patch)
tree1ea35c96ef0601dee44b625f86bd7601608a7bfc /src/lib/ccapi/server
parentb05d25d9b8be378287a86d57c12d4295e5949919 (diff)
downloadkrb5-3c323c8486c538abcba3ec9bb4a6e8a4af20496c.tar.gz
krb5-3c323c8486c538abcba3ec9bb4a6e8a4af20496c.tar.xz
krb5-3c323c8486c538abcba3ec9bb4a6e8a4af20496c.zip
* Initial commit of C CCAPI implementation
ticket: 2753 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@16840 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/ccapi/server')
-rw-r--r--src/lib/ccapi/server/ChangeLog4
-rw-r--r--src/lib/ccapi/server/NTMakefile30
-rw-r--r--src/lib/ccapi/server/ccache.c703
-rw-r--r--src/lib/ccapi/server/context.c325
-rw-r--r--src/lib/ccapi/server/datastore.h231
-rw-r--r--src/lib/ccapi/server/lists.c996
-rw-r--r--src/lib/ccapi/server/mac/ChangeLog4
-rw-r--r--src/lib/ccapi/server/rpc_auth.c63
-rw-r--r--src/lib/ccapi/server/rpc_auth.h71
-rw-r--r--src/lib/ccapi/server/serv_ops.c1500
-rw-r--r--src/lib/ccapi/server/serv_ops.h321
-rw-r--r--src/lib/ccapi/server/windows/ChangeLog4
12 files changed, 4252 insertions, 0 deletions
diff --git a/src/lib/ccapi/server/ChangeLog b/src/lib/ccapi/server/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/src/lib/ccapi/server/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27 Jeffrey Altman <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/src/lib/ccapi/server/NTMakefile b/src/lib/ccapi/server/NTMakefile
new file mode 100644
index 000000000..671b6905f
--- /dev/null
+++ b/src/lib/ccapi/server/NTMakefile
@@ -0,0 +1,30 @@
+# Makefile for the CCAPI Generic Server
+
+!INCLUDE <WIN32.MAK>
+
+CFLAGS = -I../include
+
+CCAPI_LIB = ../lib/ccapi.lib
+WINLIBS = user32.lib advapi32.lib
+CCSOBJS = context.obj ccache.obj lists.obj rpc_auth.obj serv_ops.obj
+
+all: t_lists.exe t_msg.exe t_ccache.exe t_context.exe ccapi_server.exe
+
+t_lists.exe: t_lists.obj $(CCSOBJS) $(CCAPI_LIB)
+ link -out:$@ t_lists.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS)
+
+t_msg.exe: t_msg.obj $(CCSOBJS) $(CCAPI_LIB)
+ link -out:$@ t_msg.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS)
+
+t_ccache.exe: t_ccache.obj $(CCSOBJS) $(CCAPI_LIB)
+ link -out:$@ t_ccache.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS)
+
+t_context.exe: t_context.obj $(CCSOBJS) $(CCAPI_LIB)
+ link -out:$@ t_context.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS)
+
+ccapi_server.exe: main.obj $(CCSOBJS) $(CCAPI_LIB)
+ link -out:$@ main.obj $(CCSOBJS) $(CCAPI_LIB) $(WINLIBS)
+
+clean:
+ del *.obj *.exe
+
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;
+}
+
diff --git a/src/lib/ccapi/server/context.c b/src/lib/ccapi/server/context.c
new file mode 100644
index 000000000..f405a4def
--- /dev/null
+++ b/src/lib/ccapi/server/context.c
@@ -0,0 +1,325 @@
+/* $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).
+ * $
+ */
+
+/*
+ * Functions to manipulate datastore layer contexts.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+
+#include "CredentialsCache.h"
+#include "datastore.h"
+
+int cc_myversion = 5;
+char cc_vendor[] = "MIT C lang CCache V5";
+char cc_default_ccache_name[] = "krb5cc";
+
+
+cc_int32
+cci_context_new( int api_version, cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info, cc_server_context_t** outContextpp )
+{
+ cc_server_context_t* ctx;
+
+ if ( outContextpp == NULL )
+ return ccErrBadParam;
+
+ ctx = (cc_server_context_t*)malloc(sizeof(cc_server_context_t));
+ if (ctx == NULL)
+ return ccErrNoMem;
+
+ cci_ccache_list_new(&ctx->ccaches);
+ cci_generic_list_new(&ctx->active_iterators);
+ ctx->api_version = api_version;
+ ctx->auth_info = auth_info;
+ ctx->session_info = session_info;
+ ctx->changed = time(NULL);
+
+ *outContextpp = ctx;
+ return ccNoError;
+}
+
+cc_int32
+cci_context_get_default_ccache_name(cc_server_context_t* ctx, char ** outNamepp)
+{
+ cc_server_ccache_t* default_ccache;
+
+ if (outNamepp == NULL)
+ return ccErrBadParam;
+
+ if (ctx == NULL)
+ return ccErrInvalidContext;
+
+ if (ctx->ccaches->head != NULL) {
+ default_ccache = (cc_server_ccache_t*)ctx->ccaches->head->data;
+ *outNamepp = default_ccache->name;
+ } else {
+ *outNamepp = cc_default_ccache_name;
+ }
+ return ccNoError;
+}
+
+
+cc_int32
+cci_context_find_ccache( cc_server_context_t* ctx, char *name,
+ cc_server_ccache_t** outCcachepp )
+{
+ cc_ccache_iterate_t* ccache_iterator;
+ cc_ccache_list_node_t* ccache_node;
+ cc_server_ccache_t* ccache;
+ cc_int32 code;
+
+ if (ctx == NULL)
+ return ccErrInvalidContext;
+
+ if (name == NULL)
+ return ccErrInvalidString;
+
+ if (outCcachepp == NULL)
+ return ccErrBadParam;
+
+ code = cci_ccache_list_iterator(ctx->ccaches, &ccache_iterator);
+ while (cci_ccache_iterate_has_next(ccache_iterator)) {
+ code = cci_ccache_iterate_next(ccache_iterator, &ccache_node);
+ ccache = (cc_server_ccache_t *)ccache_node->data;
+ if (strcmp(ccache->name, name) == 0) {
+ free(ccache_iterator);
+ *outCcachepp = ccache;
+ return ccNoError;
+ }
+ }
+ free(ccache_iterator);
+ return ccErrCCacheNotFound;
+}
+
+cc_int32
+cci_context_open_ccache( cc_server_context_t* ctx, char *name,
+ cc_server_ccache_t** outCcachepp )
+{
+ return cci_context_find_ccache(ctx, name, outCcachepp);
+}
+
+
+cc_int32
+cci_context_create_ccache( cc_server_context_t* ctx, char *name, int creds_version,
+ char *principal, cc_server_ccache_t** outCcachepp )
+{
+ cc_server_ccache_t* ccache;
+ cc_int32 code;
+
+ if (ctx == NULL)
+ return ccErrInvalidContext;
+
+ if (outCcachepp == NULL)
+ return ccErrBadParam;
+
+ if (name == NULL || principal == NULL)
+ return ccErrInvalidString;
+
+ if (creds_version != cc_credentials_v4 && creds_version != cc_credentials_v5 &&
+ creds_version != cc_credentials_v4_v5)
+ return ccErrBadCredentialsVersion;
+
+ code = cci_context_find_ccache(ctx, name, &ccache);
+ if (code == ccNoError) {
+ code = cci_ccache_set_principal(ccache, creds_version, principal);
+ } else {
+ code = cci_ccache_new(name, principal, creds_version, &ccache);
+ if (code != ccNoError)
+ return code; /*let caller deal with error*/
+
+ ccache->mycontext = ctx;
+ ctx->changed = time(NULL);
+ cci_ccache_list_append(ctx->ccaches, ccache, NULL);
+
+ if (ctx->ccaches->head->data == (cc_uint8 *)ccache) {
+ ccache->is_default = 1;
+ }
+ }
+ *outCcachepp = ccache;
+ return ccNoError;
+}
+
+cc_int32
+cci_context_create_default_ccache( cc_server_context_t* ctx, int creds_version,
+ char *principal, cc_server_ccache_t** outCcachepp )
+{
+ cc_server_ccache_t* ccache, *old_default;
+ cc_int32 code;
+
+ if (ctx == NULL)
+ return ccErrInvalidContext;
+
+ if (outCcachepp == NULL)
+ return ccErrBadParam;
+
+ if (principal == NULL)
+ return ccErrInvalidString;
+
+ if (creds_version != cc_credentials_v4 && creds_version != cc_credentials_v5 &&
+ creds_version != cc_credentials_v4_v5)
+ return ccErrBadCredentialsVersion;
+
+ code = cci_context_find_ccache(ctx, cc_default_ccache_name, &ccache);
+ if (code == ccNoError) {
+ cci_ccache_set_principal(ccache, creds_version, principal);
+ } else {
+ code = cci_ccache_new(cc_default_ccache_name, principal, creds_version, &ccache);
+ if (code != ccNoError)
+ return code; /*let caller deal with error*/
+
+ ccache->mycontext = ctx;
+ ccache->is_default = 1;
+ ctx->changed = time(NULL);
+
+ if (ctx->ccaches->head != NULL) {
+ old_default = (cc_server_ccache_t *)ctx->ccaches->head->data;
+ old_default->is_default = 0;
+ old_default->last_default = time(NULL);
+ }
+
+ cci_ccache_list_prepend(ctx->ccaches, ccache, NULL);
+ }
+ *outCcachepp = ccache;
+ return ccNoError;
+}
+
+cc_int32
+cci_context_ccache_iterator(cc_server_context_t* ctx, cc_ccache_iterate_t** iterpp)
+{
+ cc_ccache_iterate_t* ccache_iterator;
+ cc_int32 code;
+
+ if (ctx == NULL)
+ return ccErrInvalidContext;
+
+ if (iterpp == NULL)
+ return ccErrBadParam;
+
+ code = cci_ccache_list_iterator(ctx->ccaches, &ccache_iterator);
+ if (code != ccNoError)
+ return code;
+ cci_generic_list_prepend(ctx->active_iterators, ccache_iterator, sizeof(cc_ccache_iterate_t), NULL);
+
+ *iterpp = ccache_iterator;
+ return ccNoError;
+}
+
+cc_int32
+cci_context_compare(cc_server_context_t* a, cc_server_context_t* b)
+{
+ if (a == b)
+ return 1;
+ else
+ return 0;
+}
+
+cc_int32
+cci_context_destroy(cc_server_context_t* ctx)
+{
+ cc_ccache_iterate_t* ccache_iterator;
+ cc_ccache_list_node_t* ccache_node;
+ cc_server_ccache_t* ccache;
+ cc_int32 code;
+
+ if (ctx == NULL)
+ return ccErrInvalidContext;
+
+ cci_generic_list_destroy(ctx->active_iterators);
+
+ code = cci_ccache_list_iterator(ctx->ccaches, &ccache_iterator);
+ while (cci_ccache_iterate_has_next(ccache_iterator)) {
+ code = cci_ccache_iterate_next(ccache_iterator, &ccache_node);
+ ccache = (cc_server_ccache_t *)ccache_node->data;
+ ccache_node->data = NULL;
+ cci_ccache_destroy(ccache);
+ }
+ cci_ccache_list_destroy(ctx->ccaches);
+
+ return ccNoError;
+}
+
+cc_int32
+cci_context_rem_ccache(cc_server_context_t* ctx, cc_server_ccache_t* ccache)
+{
+ cc_ccache_iterate_t* ccache_iterator;
+ cc_ccache_iterate_t* active_ccache_iterator;
+ cc_ccache_list_node_t* ccache_node;
+ cc_server_ccache_t* list_ccache;
+ cc_generic_list_node_t* gen_node;
+ cc_generic_iterate_t* gen_iterator;
+ cc_int32 code;
+
+ if (ctx == NULL)
+ return ccErrInvalidContext;
+
+ if (ccache == NULL)
+ return ccErrInvalidCCache;
+
+ code = cci_ccache_list_iterator(ctx->ccaches, &ccache_iterator);
+ while (cci_ccache_iterate_has_next(ccache_iterator)) {
+ code = cci_ccache_iterate_next(ccache_iterator, &ccache_node);
+ list_ccache = (cc_server_ccache_t *)ccache_node->data;
+
+ if (list_ccache == ccache) {
+ code = cci_generic_list_iterator(ctx->active_iterators, &gen_iterator);
+ while (cci_generic_iterate_has_next(gen_iterator)) {
+ code = cci_generic_iterate_next(gen_iterator, &gen_node);
+ active_ccache_iterator = (cc_server_ccache_t *)gen_node->data;
+ if (active_ccache_iterator->next == ccache_node) {
+ active_ccache_iterator->next = active_ccache_iterator->next->next;
+ }
+ }
+ free(gen_iterator);
+ code = cci_ccache_list_remove_element(ctx->ccaches, ccache_node);
+ break;
+ }
+ }
+ free(ccache_iterator);
+ return ccNoError;
+}
+
diff --git a/src/lib/ccapi/server/datastore.h b/src/lib/ccapi/server/datastore.h
new file mode 100644
index 000000000..a92c60636
--- /dev/null
+++ b/src/lib/ccapi/server/datastore.h
@@ -0,0 +1,231 @@
+/* $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).
+ * $
+ */
+/*
+ * Prototypes and data structures for datastore.
+ *
+ */
+
+
+#ifndef __CCDATASTOREH__
+#define __CCDATASTOREH__
+
+#include "CredentialsCache.h"
+#include "rpc_auth.h"
+
+enum cc_list_type {
+ generic = 0,
+ context,
+ cache,
+ credentials
+};
+
+struct cc_generic_list_node_t {
+ cc_uint8* data;
+ cc_uint32 len;
+ struct cc_generic_list_node_t* next;
+ struct cc_generic_list_node_t* prev;
+};
+typedef struct cc_generic_list_node_t cc_generic_list_node_t;
+
+struct cc_generic_list_head_t {
+ enum cc_list_type type;
+ cc_generic_list_node_t* head;
+ cc_generic_list_node_t* tail;
+};
+typedef struct cc_generic_list_head_t cc_generic_list_head_t;
+
+
+struct cc_generic_iterate_t {
+ cc_generic_list_node_t* next;
+};
+typedef struct cc_generic_iterate_t cc_generic_iterate_t;
+
+typedef cc_generic_list_head_t cc_context_list_head_t;
+typedef cc_generic_list_node_t cc_context_list_node_t;
+
+typedef cc_generic_list_head_t cc_ccache_list_head_t;
+typedef cc_generic_list_node_t cc_ccache_list_node_t;
+
+typedef cc_generic_list_head_t cc_credentials_list_head_t;
+typedef cc_generic_list_node_t cc_credentials_list_node_t;
+
+struct cc_context_iterate_t {
+ cc_context_list_node_t* next;
+};
+typedef struct cc_context_iterate_t cc_context_iterate_t;
+
+struct cc_ccache_iterate_t {
+ cc_ccache_list_node_t* next;
+};
+typedef struct cc_ccache_iterate_t cc_ccache_iterate_t;
+
+struct cc_credentials_iterate_t {
+ cc_credentials_list_node_t* next;
+};
+typedef struct cc_credentials_iterate_t cc_credentials_iterate_t;
+
+struct cc_lock_t {
+ cc_uint32 read_locks; /* count of read locks (>= 0) */
+ cc_uint32 write_locks; /* count of write locks (0 or 1) */
+ void * platform_data; /* platform specific implementation data */
+};
+typedef struct cc_lock cc_lock_t;
+
+
+struct cc_server_context_t {
+ cc_ccache_list_head_t* ccaches; /*our ccaches*/
+ cc_generic_list_head_t* active_iterators; /*active ccache iterators*/
+ cc_int32 api_version; /*Version our client passed in on init (ccapi_version_X) */
+ cc_auth_info_t* auth_info; /*auth info passed in from RPC*/
+ cc_session_info_t* session_info; /*session info passed in from RPC*/
+ cc_time_t changed; /*date of last change to this context*/
+ cc_int32 error; /*last error code*/
+ cc_lock_t locks; /*are we locked?*/
+};
+typedef struct cc_server_context_t cc_server_context_t;
+
+struct cc_server_ccache_t {
+ char* name; /*name of this ccache*/
+ char* principal_v4; /*v4 principal associated with this cache*/
+ char* principal_v5; /*v5 principal associated with this cache*/
+ cc_uint32 versions; /*versions of creds supported (from cc_credentials enum in CredentialsCache.h)*/
+ cc_time_t changed; /*date of last change to ccache*/
+ cc_int32 kdc_set; /*is the KDC time offset initialized?*/
+ cc_time_t kdc_offset; /*offset of our clock relative kdc*/
+ cc_time_t last_default; /*the last date when we were default*/
+ cc_int32 is_default; /*is this the default cred on this ccache?*/
+ cc_generic_list_head_t* active_iterators; /*iterators which clients have opened on this cache*/
+ cc_credentials_list_head_t* creds; /*list of creds stored in this ccache*/
+ cc_server_context_t* mycontext; /*context to which I belong*/
+ cc_lock_t locks; /*are we locked?*/
+};
+typedef struct cc_server_ccache_t cc_server_ccache_t;
+
+struct cc_server_credentials_t {
+ cc_int32 is_default; /*Are we the default cred? (first in list)*/
+ cc_credentials_union creds;
+};
+typedef struct cc_server_credentials_t cc_server_credentials_t;
+
+
+/*Note: cci means Credential Cache Internal, to differentiate from exported API macros*/
+
+cc_int32 cci_generic_iterate_has_next(cc_generic_iterate_t *iterate);
+cc_int32 cci_generic_iterate_next(cc_generic_iterate_t *iterate, cc_generic_list_node_t**);
+
+cc_int32 cci_generic_list_new(cc_generic_list_head_t **);
+cc_int32 cci_generic_list_append(cc_generic_list_head_t *head, void *data, cc_uint32 len, cc_generic_list_node_t**);
+cc_int32 cci_generic_list_prepend(cc_generic_list_head_t *head, void *data, cc_uint32 len, cc_generic_list_node_t**);
+cc_int32 cci_generic_list_remove_element(cc_generic_list_head_t* head, cc_generic_list_node_t* rem);
+cc_int32 cci_generic_free_element(cc_generic_list_node_t* node);
+cc_int32 cci_generic_list_destroy(cc_generic_list_head_t* head);
+cc_int32 cci_generic_list_copy(cc_generic_list_head_t* head, cc_generic_list_head_t**);
+cc_int32 cci_generic_list_iterator(cc_generic_list_head_t *head, cc_generic_iterate_t**);
+cc_int32 cci_generic_free_iterator(cc_generic_iterate_t* iterator);
+
+cc_int32 cci_context_iterate_has_next(struct cc_context_iterate_t *iterate);
+cc_int32 cci_context_iterate_next(struct cc_context_iterate_t *iterate, cc_context_list_node_t**);
+
+cc_int32 cci_ccache_iterate_has_next(struct cc_ccache_iterate_t *iterate);
+cc_int32 cci_ccache_iterate_next(struct cc_ccache_iterate_t *iterate, cc_ccache_list_node_t**);
+
+cc_int32 cci_credentials_iterate_has_next(cc_credentials_iterate_t *iterate);
+cc_int32 cci_credentials_iterate_next(cc_credentials_iterate_t *iterate, cc_credentials_list_node_t **);
+
+cc_int32 cci_context_list_new(cc_context_list_head_t**);
+cc_int32 cci_context_list_append(cc_context_list_head_t *head, cc_server_context_t *data, cc_context_list_node_t**);
+cc_int32 cci_context_list_prepend(cc_context_list_head_t *head, cc_server_context_t *data, cc_context_list_node_t**);
+cc_int32 cci_context_list_remove_element(cc_context_list_head_t* head, cc_context_list_node_t* rem);
+cc_int32 cci_context_list_iterator(cc_context_list_head_t *head, struct cc_context_iterate_t**);
+cc_int32 cci_context_free_iterator(struct cc_context_iterate_t *iterator);
+cc_int32 cci_context_list_destroy(cc_context_list_head_t* head) ;
+cc_int32 cci_context_list_copy(cc_context_list_head_t* head, cc_context_list_head_t**);
+
+cc_int32 cci_ccache_list_new(cc_ccache_list_head_t**);
+cc_int32 cci_ccache_list_append(cc_ccache_list_head_t *head, cc_server_ccache_t *data, cc_ccache_list_node_t**);
+cc_int32 cci_ccache_list_prepend(cc_ccache_list_head_t *head, cc_server_ccache_t *data, cc_ccache_list_node_t**);
+cc_int32 cci_ccache_list_remove_element(cc_ccache_list_head_t* head, cc_ccache_list_node_t* rem);
+cc_int32 cci_ccache_list_iterator(cc_ccache_list_head_t *head, struct cc_ccache_iterate_t**);
+cc_int32 cci_ccache_free_iterator(struct cc_ccache_iterate_t *iterator);
+cc_int32 cci_ccache_list_destroy(cc_ccache_list_head_t* head) ;
+cc_int32 cci_ccache_list_copy(cc_ccache_list_head_t* head, cc_ccache_list_head_t**);
+
+
+cc_int32 cci_credentials_list_new(cc_credentials_list_head_t**);
+cc_int32 cci_credentials_list_append(cc_credentials_list_head_t *head, cc_server_credentials_t *data, cc_credentials_list_node_t**);
+cc_int32 cci_credentials_list_prepend(cc_credentials_list_head_t *head, cc_server_credentials_t *data, cc_credentials_list_node_t**);
+cc_int32 cci_credentials_list_remove_element(cc_credentials_list_head_t* head, cc_credentials_list_node_t* rem);
+cc_int32 cci_credentials_list_iterator(cc_credentials_list_head_t *head, cc_credentials_iterate_t**);
+cc_int32 cci_credentials_free_iterator(cc_credentials_iterate_t* iterator);
+cc_int32 cci_credentials_list_destroy(cc_credentials_list_head_t* head) ;
+cc_int32 cci_credentials_list_copy(cc_credentials_list_head_t* head, cc_credentials_list_head_t**) ;
+
+
+cc_int32 cci_context_new(int api_version, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_server_context_t** ) ;
+cc_int32 cci_context_get_default_ccache_name(cc_server_context_t* ctx, char **);
+cc_int32 cci_context_find_ccache(cc_server_context_t* ctx, char *name, cc_server_ccache_t**);
+cc_int32 cci_context_open_ccache(cc_server_context_t* ctx, char *name, cc_server_ccache_t** );
+cc_int32 cci_context_create_ccache(cc_server_context_t* ctx, char *name, int creds_version, char *principal, cc_server_ccache_t**);
+cc_int32 cci_context_create_default_ccache(cc_server_context_t* ctx, int creds_version, char *principal, cc_server_ccache_t**);
+cc_int32 cci_context_ccache_iterator(cc_server_context_t* ctx, cc_ccache_iterate_t**);
+cc_int32 cci_context_compare(cc_server_context_t* a, cc_server_context_t* b);
+cc_int32 cci_context_destroy(cc_server_context_t* ctx);
+cc_int32 cci_context_rem_ccache(cc_server_context_t* ctx, cc_server_ccache_t* ccache);
+
+cc_int32 cci_ccache_new(char *name, char *principal, int cred_vers, cc_server_ccache_t**);
+cc_int32 cci_ccache_check_version(const cc_server_ccache_t *ccache, const cc_credentials_union* creds, cc_uint32* compat);
+cc_int32 cci_ccache_check_principal(const cc_server_ccache_t *ccache, const cc_credentials_union* creds, cc_uint32* compat);
+cc_int32 cci_ccache_store_creds(cc_server_ccache_t *ccache, const cc_credentials_union* credentials);
+cc_int32 cci_ccache_rem_creds(cc_server_ccache_t *ccache, const cc_credentials_union* credentials);
+cc_int32 cci_ccache_move(cc_server_ccache_t *source, cc_server_ccache_t* destination);
+cc_int32 cci_ccache_get_kdc_time_offset(cc_server_ccache_t* ccache, cc_time_t* offset);
+cc_int32 cci_ccache_set_kdc_time_offset(cc_server_ccache_t* ccache, cc_time_t offset);
+cc_int32 cci_ccache_clear_kdc_time_offset(cc_server_ccache_t* ccache);
+cc_int32 cci_ccache_new_iterator(cc_server_ccache_t* ccache, cc_credentials_iterate_t** iterator);
+cc_int32 cci_ccache_get_principal(cc_server_ccache_t* ccache, cc_int32 version, char ** principal);
+cc_int32 cci_ccache_set_principal(cc_server_ccache_t* ccache, cc_int32 version, char * principal);
+cc_int32 cci_ccache_free_principal(char * principal);
+cc_int32 cci_ccache_destroy(cc_server_ccache_t* ccache);
+void cci_ccache_changed(cc_server_ccache_t* ccache);
+cc_int32 cci_ccache_compare(cc_server_ccache_t* ccache1, cc_server_ccache_t* ccache2, cc_uint32 *result);
+#endif /*__CCDATASTOREH__*/
diff --git a/src/lib/ccapi/server/lists.c b/src/lib/ccapi/server/lists.c
new file mode 100644
index 000000000..882ecb7a0
--- /dev/null
+++ b/src/lib/ccapi/server/lists.c
@@ -0,0 +1,996 @@
+/* $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).
+ * $
+ */
+
+
+/*
+ * Lists implementation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#include "CredentialsCache.h"
+#include "datastore.h"
+
+/**
+ * cci_generic_iterate_has_next()
+ *
+ * Purpose: Determine if an iterator has a next element
+ *
+ * Return: 1 if another element exists
+ * 0 if no additional elements exist
+ *
+ * Errors: None
+ *
+ */
+cc_int32
+cci_generic_iterate_has_next(cc_generic_iterate_t *iterate)
+{
+ return ((iterate == NULL || iterate->next == NULL) ? 0 : 1);
+}
+
+/**
+ * cci_generic_iterate_next()
+ *
+ * Purpose: Retrieve the next element from an iterator and advance
+ * the iterator
+ *
+ * Return: non-NULL, the next element in the iterator
+ * NULL, the iterator list is empty or iterator is invalid
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_generic_iterate_next(cc_generic_iterate_t *iterator, cc_generic_list_node_t** nodepp)
+{
+ cc_generic_list_node_t* ret;
+
+ if (iterator == NULL || nodepp == NULL)
+ return ccErrBadParam;
+
+ ret = iterator->next;
+ if (iterator->next != NULL)
+ iterator->next = iterator->next->next;
+
+ *nodepp = ret;
+ return ccNoError;
+}
+
+/**
+ * cci_context_iterate_has_next()
+ *
+ * Purpose: Determine if a context iterator has a next element
+ *
+ * Return: 1 if another element exists
+ * 0 if no additional elements exist
+ */
+cc_int32
+cci_context_iterate_has_next(cc_context_iterate_t *iterate)
+{
+ if ( iterate == NULL )
+ return 0;
+
+ return cci_generic_iterate_has_next((cc_generic_iterate_t*)iterate);
+}
+
+/**
+ * cci_context_iterate_next()
+ *
+ * Purpose: Retrieve the next element from a context iterator and advance
+ * the iterator
+ *
+ * Return: non-NULL, the next element in the iterator
+ * NULL, the iterator list is empty or iterator is invalid
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_context_iterate_next(cc_context_iterate_t *iterate, cc_context_list_node_t ** nodepp)
+{
+ if ( iterate == NULL || nodepp == NULL)
+ return ccErrBadParam;
+
+ return cci_generic_iterate_next((cc_generic_iterate_t*)iterate,(cc_context_list_node_t**)nodepp);
+}
+
+/**
+ * cci_ccache_iterate_has_next()
+ *
+ * Purpose: Determine if a cache iterator has a next element
+ *
+ * Return: 1 if another element exists
+ * 0 if no additional elements exist
+ * -1 if error
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_ccache_iterate_has_next(cc_ccache_iterate_t *iterate)
+{
+ if ( iterate == NULL )
+ return 0;
+ return cci_generic_iterate_has_next((cc_generic_iterate_t*)iterate);
+}
+
+/**
+ * cci_ccache_iterate_next()
+ *
+ * Purpose: Retrieve the next element from a ccache iterator and advance
+ * the iterator
+ *
+ * Return: non-NULL, the next element in the iterator
+ * NULL, the iterator list is empty or iterator is invalid
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_ccache_iterate_next(cc_ccache_iterate_t *iterate, cc_ccache_list_node_t ** nodepp)
+{
+ if ( iterate == NULL || nodepp == NULL)
+ return ccErrBadParam;
+
+ return cci_generic_iterate_next((cc_generic_iterate_t*)iterate, (cc_ccache_list_node_t**)nodepp);
+}
+
+/**
+ * cci_credentials_iterate_has_next()
+ *
+ * Purpose: Determine if a credentials iterator has a next element
+ *
+ * Return: 1 if another element exists
+ * 0 if no additional elements exist
+ * -1 if error
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_credentials_iterate_has_next(cc_credentials_iterate_t *iterate)
+{
+ if ( iterate == NULL )
+ return 0;
+
+ return cci_generic_iterate_has_next((cc_generic_iterate_t*)iterate);
+}
+
+/**
+ * cci_credentials_iterate_next()
+ *
+ * Purpose: Retrieve the next element from a credentials iterator and advance
+ * the iterator
+ *
+ * Return: non-NULL, the next element in the iterator
+ * NULL, the iterator list is empty or iterator is invalid
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_credentials_iterate_next(cc_credentials_iterate_t *iterate, cc_credentials_list_node_t** nodepp)
+{
+ if ( iterate == NULL || nodepp == NULL )
+ return ccErrBadParam;
+ return cci_generic_iterate_next((cc_generic_iterate_t*)iterate, (cc_credentials_list_node_t**)nodepp);
+}
+
+/**
+ * cci_generic_list_new()
+ *
+ * Purpose: Allocate new generic list
+ *
+ * Return: non-NULL, an empty list
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem
+ *
+ */
+cc_int32
+cci_generic_list_new(cc_generic_list_head_t ** listpp)
+{
+ cc_generic_list_head_t* ret = (cc_generic_list_head_t *)malloc(sizeof(cc_generic_list_head_t));
+ if (ret == NULL)
+ return ccErrNoMem;
+
+ ret->type = generic;
+ ret->head = ret->tail = NULL;
+ *listpp = ret;
+
+ return ccNoError;
+}
+
+/**
+ * cci_generic_list_append()
+ *
+ * Purpose: Appends a new node containing a copy of 'len' bytes of 'data'
+ *
+ * Return: non-NULL, a pointer to the newly allocated node
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_generic_list_append(cc_generic_list_head_t *head, void *data, cc_uint32 len, cc_generic_list_node_t** nodepp)
+{
+ cc_generic_list_node_t* new_node;
+
+ if ( data == NULL || len == 0 )
+ return ccErrBadParam;
+
+ new_node = (cc_generic_list_node_t *)malloc(sizeof(cc_generic_list_node_t));
+ if (new_node == NULL)
+ return ccErrNoMem;
+
+ new_node->data = malloc(len);
+ if ( new_node->data == NULL ) {
+ free(new_node);
+ return ccErrNoMem;
+ }
+
+ memcpy(new_node->data,data,len);
+ new_node->len = len;
+
+ if (head->head == NULL) { /*empty list*/
+ head->head = new_node;
+ head->tail = new_node;
+ new_node->next = new_node->prev = NULL;
+ } else {
+ new_node->prev = head->tail;
+ head->tail->next = new_node;
+ head->tail = new_node;
+ new_node->next = NULL;
+ }
+ if (nodepp != NULL)
+ *nodepp = new_node;
+ return ccNoError;
+}
+
+/**
+ * cci_generic_list_prepend()
+ *
+ * Purpose: Prepends a new node containing a copy of 'len' bytes of 'data'
+ *
+ * Return: non-NULL, a pointer to the newly allocated node
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem, ccErrBadParam
+ *
+ */
+cc_int32
+cci_generic_list_prepend(cc_generic_list_head_t *head, void *data, cc_uint32 len, cc_generic_list_node_t** nodepp)
+{
+ cc_generic_list_node_t* new_node;
+
+ if ( data == NULL || len == 0 )
+ return ccErrBadParam;
+
+ new_node = (cc_generic_list_node_t *)malloc(sizeof(cc_generic_list_node_t));
+ if (new_node == NULL)
+ return ccErrNoMem;
+
+ new_node->data = malloc(len);
+ if ( new_node->data == NULL ) {
+ free(new_node);
+ return ccErrNoMem;
+ }
+
+ memcpy(new_node->data,data,len);
+ new_node->len = len;
+
+ if (head->head == NULL) { /*empty list*/
+ head->head = new_node;
+ head->tail = new_node;
+ new_node->prev = new_node->next = NULL;
+ } else {
+ new_node->next = head->head;
+ head->head->prev = new_node;
+ new_node->prev = NULL;
+ head->head = new_node;
+ }
+
+ if (nodepp != NULL)
+ *nodepp = new_node;
+
+ return ccNoError;
+}
+
+/**
+ * cci_generic_list_remove_element()
+ *
+ * Purpose: Remove a node from the list
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_generic_list_remove_element(cc_generic_list_head_t* head, cc_generic_list_node_t* rem)
+{
+ if (head->head == NULL || rem == NULL)
+ return ccErrBadParam;
+
+ if (head->head == rem && head->tail == rem) { /*removing only element of list*/
+ head->head = head->tail = NULL;
+ } else if (head->head == rem) { /*removing head*/
+ head->head = head->head->next;
+ } else if (head->tail == rem) { /*removing tail*/
+ head->tail = head->tail->prev;
+ head->tail->next = NULL;
+ } else {
+ rem->prev->next = rem->next;
+ rem->next->prev = rem->prev;
+ }
+ free(rem);
+ return ccNoError;
+}
+
+/**
+ * cci_generic_free_element()
+ *
+ * Purpose: Free the memory associated with a node
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_generic_free_element(cc_generic_list_node_t* node)
+{
+ if ( node == NULL )
+ return ccErrBadParam;
+
+ if ( node->data ) {
+ free(node->data);
+ node->data = NULL;
+ }
+ node->len = 0;
+ node->next = node->prev = NULL;
+ free(node);
+ return ccNoError;
+}
+
+
+/**
+ * cci_generic_list_destroy()
+ *
+ * Purpose: Deallocate a list and all of its contents
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ */
+cc_int32
+cci_generic_list_destroy(cc_generic_list_head_t* head)
+{
+ cc_generic_list_node_t *cur, *next;
+ cc_int32 ret = ccNoError;
+
+ if ( head == NULL )
+ return ccErrBadParam;
+
+ for (cur = head->head; ret == ccNoError && cur != NULL; cur = next) {
+ next = cur->next;
+ ret = cci_generic_free_element(cur);
+ }
+ free(head);
+ return(ret);
+}
+
+/**
+ * cci_context_list_destroy()
+ *
+ * Purpose: Deallocate a list and all of its contents
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ */
+cc_int32
+cci_context_list_destroy(cc_context_list_head_t* head)
+{
+ return cci_generic_list_destroy((cc_generic_list_head_t*)head);
+}
+
+/**
+ * cci_ccache_list_destroy()
+ *
+ * Purpose: Deallocate a list and all of its contents
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ */
+cc_int32
+cci_ccache_list_destroy(cc_ccache_list_head_t* head)
+{
+ return cci_generic_list_destroy((cc_generic_list_head_t*)head);
+}
+
+/**
+ * cci_credentials_list_destroy()
+ *
+ * Purpose: Deallocate a list and all of its contents
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ */
+cc_int32
+cci_credentials_list_destroy(cc_credentials_list_head_t* head)
+{
+ return cci_generic_list_destroy((cc_generic_list_head_t*)head);
+}
+
+/**
+ * cci_generic_list_copy()
+ *
+ * Purpose: Copy a list
+ *
+ * Return: non-NULL, a new list
+ * NULL, failure
+ *
+ * Errors: ccErrBadParam, ccErrNoMem
+ *
+ */
+cc_int32
+cci_generic_list_copy(cc_generic_list_head_t* head, cc_generic_list_head_t** headpp)
+{
+ cc_generic_list_head_t* copy;
+ cc_generic_list_node_t *src_node, *dst_node;
+ cc_int32 code;
+
+ if (head == NULL || headpp == NULL)
+ return ccErrBadParam;
+
+ code = cci_generic_list_new(&copy);
+ if (code != ccNoError)
+ return code;
+
+ for (src_node = head->head; src_node != NULL; src_node = src_node->next) {
+ code = cci_generic_list_append(copy, src_node->data, src_node->len, &dst_node);
+ if (code != ccNoError) {
+ cci_generic_list_destroy(copy);
+ return code;
+ }
+ }
+ *headpp = copy;
+ return ccNoError;
+}
+
+/**
+ * cci_context_list_copy()
+ *
+ * Purpose: Copy a list
+ *
+ * Return: non-NULL, a new list
+ * NULL, failure
+ *
+ * Errors: ccErrBadParam, ccErrNoMem
+ *
+ */
+cc_int32
+cci_context_list_copy(cc_context_list_head_t* head, cc_context_list_head_t** headpp )
+{
+ return cci_generic_list_copy((cc_generic_list_head_t*)head, (cc_context_list_head_t **)headpp);
+}
+
+/**
+ * cci_ccache_list_copy()
+ *
+ * Purpose: Copy a list
+ *
+ * Return: non-NULL, a new list
+ * NULL, failure
+ *
+ * Errors: ccErrBadParam, ccErrNoMem
+ */
+cc_int32
+cci_ccache_list_copy(cc_ccache_list_head_t* head, cc_ccache_list_head_t** headpp)
+{
+ return cci_generic_list_copy((cc_generic_list_head_t*)head, (cc_ccache_list_head_t **)headpp);
+}
+
+/**
+ * cci_credentials_list_copy()
+ *
+ * Purpose: Copy a list
+ *
+ * Return: non-NULL, a new list
+ * NULL, failure
+ *
+ * Errors: ccErrBadParam, ccErrNoMem
+ *
+ */
+cc_int32
+cci_credentials_list_copy(cc_credentials_list_head_t* head, cc_credentials_list_head_t** headpp)
+{
+ return cci_generic_list_copy((cc_generic_list_head_t*)head, (cc_credentials_list_head_t **)headpp);
+}
+
+
+/**
+ * cci_generic_list_iterator()
+ *
+ * Purpose: Allocate an iterator for the specified list
+ *
+ * Return: non-NULL, an iterator
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem
+ *
+ */
+cc_int32
+cci_generic_list_iterator(cc_generic_list_head_t *head, cc_generic_iterate_t** headpp)
+{
+ cc_generic_iterate_t* iterator;
+
+ if ( head == NULL || headpp == NULL )
+ return ccErrBadParam;
+
+ iterator = (cc_generic_iterate_t*)malloc(sizeof(cc_generic_iterate_t));
+ if (iterator == NULL)
+ return ccErrNoMem;
+
+ iterator->next = head->head;
+ *headpp = iterator;
+ return ccNoError;
+}
+
+/**
+ * cci_generic_free_iterator()
+ *
+ * Purpose: Deallocate memory associated with an iterator
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_generic_free_iterator(cc_generic_iterate_t* iterator)
+{
+ if ( iterator == NULL )
+ return ccErrBadParam;
+
+ iterator->next = NULL;
+ free(iterator);
+ return ccNoError;
+}
+
+
+/**
+ * cci_context_list_new()
+ *
+ * Purpose: Allocate a new context list
+ *
+ * Return: non-NULL, a new list
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem
+ *
+ */
+cc_int32
+cci_context_list_new(cc_context_list_head_t ** headpp)
+{
+ cc_context_list_head_t *ret;
+
+ if ( headpp == NULL )
+ return ccErrBadParam;
+
+ ret = (cc_context_list_head_t *)malloc(sizeof(cc_context_list_head_t));
+ if (ret == NULL)
+ return ccErrNoMem;
+ ret->head = ret->tail = NULL;
+ *headpp = ret;
+ return ccNoError;
+}
+
+/**
+ * cci_context_list_append()
+ *
+ * Purpose: Appends a new node containing a copy of 'len' bytes of 'data'
+ *
+ * Return: non-NULL, a pointer to the newly allocated node
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_context_list_append(cc_context_list_head_t *head, cc_server_context_t *data, cc_context_list_node_t** nodepp)
+{
+ return cci_generic_list_append((cc_generic_list_head_t *)head, (void *)data, sizeof(cc_server_context_t), (cc_context_list_node_t**)nodepp);
+}
+
+/**
+ * cci_context_list_prepend()
+ *
+ * Purpose: Prepends a new node containing a copy of 'len' bytes of 'data'
+ *
+ * Return: non-NULL, a pointer to the newly allocated node
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_context_list_prepend(cc_context_list_head_t *head, cc_server_context_t *data, cc_context_list_node_t** nodepp )
+{
+ return cci_generic_list_prepend((cc_generic_list_head_t *)head, (void *)data, sizeof(cc_server_context_t), (cc_context_list_node_t**)nodepp);
+}
+
+/**
+ * cci_context_list_remove_element
+ *
+ * Purpose: Remove a node from the list
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ */
+cc_int32
+cci_context_list_remove_element(cc_context_list_head_t* head, cc_context_list_node_t* rem)
+{
+ return cci_generic_list_remove_element((cc_generic_list_head_t*)head, (cc_generic_list_node_t*)rem);
+}
+
+/**
+ * cci_context_list_iterator()
+ *
+ * Purpose: Allocate an iterator for the specified list
+ *
+ * Return: non-NULL, an iterator
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem
+ *
+ */
+cc_int32
+cci_context_list_iterator(cc_context_list_head_t *head, cc_context_iterate_t** iterpp)
+{
+ cc_context_iterate_t* iterator;
+
+ if ( head == NULL || iterpp == NULL )
+ return ccErrBadParam;
+
+ iterator = (cc_context_iterate_t*)malloc(sizeof(cc_context_iterate_t));
+ if (iterator == NULL)
+ return ccErrNoMem;
+
+ iterator->next = head->head;
+ *iterpp = iterator;
+ return ccNoError;
+}
+
+/**
+ * cci_context_free_iterator()
+ *
+ * Purpose: Deallocate memory associated with an iterator
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_context_free_iterator(cc_context_iterate_t* iterator)
+{
+ if ( iterator == NULL )
+ return ccErrBadParam;
+
+ iterator->next = NULL;
+ free(iterator);
+ return ccNoError;
+}
+
+/**
+ * cci_ccache_list_new()
+ *
+ * Purpose: Allocate a new ccache list
+ *
+ * Return: non-NULL, a new list
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem
+ */
+cc_int32
+cci_ccache_list_new(cc_ccache_list_head_t ** listpp)
+{
+ cc_ccache_list_head_t *ret;
+
+ if ( listpp == NULL )
+ return ccErrBadParam;
+
+ ret = (cc_ccache_list_head_t *)malloc(sizeof(cc_ccache_list_head_t));
+ if (ret == NULL)
+ return ccErrNoMem;
+
+ ret->head = ret->tail = NULL;
+ *listpp = ret;
+ return ccNoError;
+}
+
+/**
+ * cci_ccache_list_append()
+ *
+ * Purpose: Appends a new node containing a copy of 'len' bytes of 'data'
+ *
+ * Return: non-NULL, a pointer to the newly allocated node
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_ccache_list_append(cc_ccache_list_head_t *head, cc_server_ccache_t *data, cc_ccache_list_node_t** nodepp)
+{
+ return cci_generic_list_append((cc_generic_list_head_t *)head, (void *)data, sizeof(cc_server_ccache_t), (cc_ccache_list_node_t**)nodepp);
+}
+
+/**
+ * cci_ccache_list_prepend()
+ *
+ * Purpose: Prepends a new node containing a copy of 'len' bytes of 'data'
+ *
+ * Return: non-NULL, a pointer to the newly allocated node
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_ccache_list_prepend(cc_ccache_list_head_t *head, cc_server_ccache_t *data, cc_ccache_list_node_t** nodepp)
+{
+ return cci_generic_list_prepend((cc_generic_list_head_t *)head, (void *)data, sizeof(cc_server_ccache_t), (cc_ccache_list_node_t**)nodepp);
+}
+
+/**
+ * cci_ccache_list_remove_element()
+ *
+ * Purpose: Remove a node from the list
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_ccache_list_remove_element(cc_ccache_list_head_t* head, cc_ccache_list_node_t* rem)
+{
+ return cci_generic_list_remove_element((cc_generic_list_head_t*)head, (cc_generic_list_node_t*)rem);
+}
+
+/**
+ * cci_ccache_list_iterator()
+ *
+ * Purpose: Allocate an iterator for the specified list
+ *
+ * Return: non-NULL, an iterator
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem
+ *
+ */
+cc_int32
+cci_ccache_list_iterator(cc_ccache_list_head_t *head, cc_ccache_iterate_t** iterpp)
+{
+ cc_ccache_iterate_t* iterator;
+
+ if ( head == NULL || iterpp == NULL )
+ return ccErrBadParam;
+
+ iterator = (cc_ccache_iterate_t*)malloc(sizeof(cc_ccache_iterate_t));
+ if (iterator == NULL)
+ return ccErrNoMem;
+
+ iterator->next = head->head;
+ *iterpp = iterator;
+ return ccNoError;
+}
+
+/**
+ * cci_ccache_free_iterator()
+ *
+ * Purpose: Deallocate memory associated with an iterator
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_ccache_free_iterator(cc_ccache_iterate_t* iterator)
+{
+ if ( iterator == NULL )
+ return ccErrBadParam;
+
+ iterator->next = NULL;
+ free(iterator);
+ return ccNoError;
+}
+
+/**
+ * cci_credentials_list_new()
+ *
+ * Purpose: Allocate a new ccache list
+ *
+ * Return: non-NULL, a new list
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem
+ *
+ */
+cc_int32
+cci_credentials_list_new(cc_credentials_list_head_t ** list)
+{
+ if ( list == NULL )
+ return ccErrBadParam;
+
+ *list = (cc_credentials_list_head_t *)malloc(sizeof(cc_credentials_list_head_t));
+ if (*list == NULL)
+ return ccErrNoMem;
+
+ (*list)->head = (*list)->tail = NULL;
+ return ccNoError;
+}
+
+/**
+ * cci_credentials_list_append()
+ *
+ * Purpose: Appends a new node containing a copy of 'len' bytes of 'data'
+ *
+ * Return: non-NULL, a pointer to the newly allocated node
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_credentials_list_append(cc_credentials_list_head_t *head, cc_server_credentials_t *data, cc_credentials_list_node_t** nodepp )
+{
+ return cci_generic_list_append((cc_generic_list_head_t *)head, (void *)data, sizeof(cc_server_credentials_t), (cc_credentials_list_node_t**)nodepp);
+}
+
+/**
+ * cci_credentials_list_prepend()
+ *
+ * Purpose: Prepends a new node containing a copy of 'len' bytes of 'data'
+ *
+ * Return: non-NULL, a pointer to the newly allocated node
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem,ccErrBadParam
+ *
+ */
+cc_int32
+cci_credentials_list_prepend(cc_credentials_list_head_t *head, cc_server_credentials_t *data, cc_credentials_list_node_t** nodepp)
+{
+ return cci_generic_list_prepend((cc_generic_list_head_t *)head, (void *)data, sizeof(cc_server_credentials_t), (cc_credentials_list_node_t**)nodepp);
+}
+
+/**
+ * cci_credentials_list_remove_element()
+ *
+ * Purpose: Remove a node from the list
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_credentials_list_remove_element(cc_credentials_list_head_t* head, cc_credentials_list_node_t* rem)
+{
+ return cci_generic_list_remove_element((cc_generic_list_head_t*)head, (cc_generic_list_node_t*)rem);
+}
+
+/**
+ * cci_credentials_list_iterator()
+ *
+ * Purpose: Allocate an iterator for the specified list
+ *
+ * Return: non-NULL, an iterator
+ * NULL, failure
+ *
+ * Errors: ccErrNoMem
+ *
+ */
+cc_int32
+cci_credentials_list_iterator(cc_credentials_list_head_t *head, cc_credentials_iterate_t** iterpp)
+{
+ cc_credentials_iterate_t* iterator;
+
+ if ( head == NULL || iterpp == NULL )
+ return ccErrBadParam;
+
+ iterator = (cc_credentials_iterate_t*)malloc(sizeof(cc_credentials_iterate_t));
+ if (iterator == NULL)
+ return ccErrNoMem;
+
+ iterator->next = head->head;
+ *iterpp = iterator;
+ return ccNoError;
+}
+
+/**
+ * cci_credentials_free_iterator()
+ *
+ * Purpose: Deallocate memory associated with an iterator
+ *
+ * Return: 0, success
+ * -1, failure
+ *
+ * Errors: ccErrBadParam
+ *
+ */
+cc_int32
+cci_credentials_free_iterator(cc_credentials_iterate_t* iterator)
+{
+ if ( iterator == NULL )
+ return ccErrBadParam;
+
+ iterator->next = NULL;
+ free(iterator);
+ return ccNoError;
+}
+
diff --git a/src/lib/ccapi/server/mac/ChangeLog b/src/lib/ccapi/server/mac/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/src/lib/ccapi/server/mac/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27 Jeffrey Altman <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+
diff --git a/src/lib/ccapi/server/rpc_auth.c b/src/lib/ccapi/server/rpc_auth.c
new file mode 100644
index 000000000..dd338e010
--- /dev/null
+++ b/src/lib/ccapi/server/rpc_auth.c
@@ -0,0 +1,63 @@
+/* $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).
+ * $
+ */
+
+/*
+ * Stubs for rpc_auth.
+ */
+
+#include "CredentialsCache.h"
+#include "rpc_auth.h"
+
+cc_int32
+cci_rpc_is_authorized( cc_auth_info_t* msg_auth, cc_session_info_t* msg_session, cc_auth_info_t* stored_auth,
+ cc_session_info_t* stored_session, cc_uint32 * authorizedp)
+{
+ if (msg_auth == stored_auth && msg_session == stored_session)
+ *authorizedp = 1;
+ else
+ *authorizedp = 0;
+
+ return ccNoError;
+}
+
+
diff --git a/src/lib/ccapi/server/rpc_auth.h b/src/lib/ccapi/server/rpc_auth.h
new file mode 100644
index 000000000..21d7db501
--- /dev/null
+++ b/src/lib/ccapi/server/rpc_auth.h
@@ -0,0 +1,71 @@
+/* $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).
+ * $
+ */
+
+
+/*
+ * Types for RPC auth + session info
+ *
+ */
+
+#ifndef __RPC_AUTH_H__
+#define __RPC_AUTH_H__
+
+#include "CredentialsCache.h"
+
+/*preliminary*/
+struct cc_auth_info_t {
+ cc_uint8 *info;
+ cc_uint32 len;
+};
+typedef struct cc_auth_info_t cc_auth_info_t;
+
+/*preliminary*/
+struct cc_session_info_t {
+ cc_uint8 *info;
+ cc_uint32 len;
+};
+typedef struct cc_session_info_t cc_session_info_t;
+
+cc_int32 cci_rpc_is_authorized(cc_auth_info_t* msg_auth, cc_session_info_t* msg_session, cc_auth_info_t* stored_auth, cc_session_info_t* stored_session, cc_uint32 *authorizedp);
+
+#endif /*__RPC_AUTH_H__*/
diff --git a/src/lib/ccapi/server/serv_ops.c b/src/lib/ccapi/server/serv_ops.c
new file mode 100644
index 000000000..30a108a34
--- /dev/null
+++ b/src/lib/ccapi/server/serv_ops.c
@@ -0,0 +1,1500 @@
+/* $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).
+ * $
+ */
+
+/*
+ * Server side implementation of each API function.
+ */
+
+#include "CredentialsCache.h"
+#include "serv_ops.h"
+#include "datastore.h"
+#include "rpc_auth.h"
+#include "msg_headers.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+cc_context_list_head_t* AllContexts = NULL;
+type_to_op_mapping_t* TypeToOpMapping = NULL;
+
+extern int cc_err_code;
+extern int cc_myversion;
+extern char cc_vendor[];
+
+cc_int32
+cci_serv_initialize(void)
+{
+ cc_int32 code;
+
+ code = cci_context_list_new(&AllContexts);
+ if ( code != ccNoError )
+ return code;
+ TypeToOpMapping = (type_to_op_mapping_t*)malloc(sizeof(type_to_op_mapping_t));
+ if (TypeToOpMapping == NULL) {
+ cci_context_list_destroy(AllContexts);
+ return ccErrNoMem;
+ }
+
+ TypeToOpMapping->operations[ccmsg_INIT] = ccop_INIT;
+ TypeToOpMapping->operations[ccmsg_CTX_RELEASE] = ccop_CTX_RELEASE;
+ TypeToOpMapping->operations[ccmsg_CTX_GET_CHANGE_TIME] = ccop_CTX_GET_CHANGE_TIME;
+ TypeToOpMapping->operations[ccmsg_CTX_GET_DEFAULT_CCACHE_NAME] = ccop_CTX_GET_DEFAULT_CCACHE_NAME;
+ TypeToOpMapping->operations[ccmsg_CTX_COMPARE] = ccop_CTX_COMPARE;
+ TypeToOpMapping->operations[ccmsg_CTX_NEW_CCACHE_ITERATOR] = ccop_CTX_NEW_CCACHE_ITERATOR;
+ TypeToOpMapping->operations[ccmsg_CTX_LOCK] = ccop_CTX_LOCK;
+ TypeToOpMapping->operations[ccmsg_CTX_UNLOCK] = ccop_CTX_UNLOCK;
+ TypeToOpMapping->operations[ccmsg_CTX_CLONE] = ccop_CTX_CLONE;
+ TypeToOpMapping->operations[ccmsg_CCACHE_OPEN] = ccop_CCACHE_OPEN;
+ TypeToOpMapping->operations[ccmsg_CCACHE_OPEN_DEFAULT] = ccop_CCACHE_OPEN_DEFAULT;
+ TypeToOpMapping->operations[ccmsg_CCACHE_CREATE] = ccop_CCACHE_CREATE;
+ TypeToOpMapping->operations[ccmsg_CCACHE_CREATE_DEFAULT] = ccop_CCACHE_CREATE_DEFAULT;
+ TypeToOpMapping->operations[ccmsg_CCACHE_CREATE_UNIQUE] = ccop_CCACHE_CREATE_UNIQUE;
+ TypeToOpMapping->operations[ccmsg_CCACHE_RELEASE] = ccop_CCACHE_RELEASE;
+ TypeToOpMapping->operations[ccmsg_CCACHE_DESTROY] = ccop_CCACHE_DESTROY;
+ TypeToOpMapping->operations[ccmsg_CCACHE_SET_DEFAULT] = ccop_CCACHE_SET_DEFAULT;
+ TypeToOpMapping->operations[ccmsg_CCACHE_GET_CREDS_VERSION] = ccop_CCACHE_GET_CREDS_VERSION;
+ TypeToOpMapping->operations[ccmsg_CCACHE_GET_NAME] = ccop_CCACHE_GET_NAME;
+ TypeToOpMapping->operations[ccmsg_CCACHE_GET_PRINCIPAL] = ccop_CCACHE_GET_PRINCIPAL;
+ TypeToOpMapping->operations[ccmsg_CCACHE_SET_PRINCIPAL] = ccop_CCACHE_SET_PRINCIPAL;
+ TypeToOpMapping->operations[ccmsg_CCACHE_CREDS_ITERATOR] = ccop_CCACHE_CREDS_ITERATOR;
+ TypeToOpMapping->operations[ccmsg_CCACHE_STORE_CREDS] = ccop_CCACHE_STORE_CREDS;
+ TypeToOpMapping->operations[ccmsg_CCACHE_REM_CREDS] = ccop_CCACHE_REM_CREDS;
+ TypeToOpMapping->operations[ccmsg_CCACHE_GET_LAST_DEFAULT_TIME] = ccop_CCACHE_GET_LAST_DEFAULT_TIME;
+ TypeToOpMapping->operations[ccmsg_CCACHE_GET_CHANGE_TIME] = ccop_CCACHE_GET_CHANGE_TIME;
+ TypeToOpMapping->operations[ccmsg_CCACHE_COMPARE] = ccop_CCACHE_COMPARE;
+ TypeToOpMapping->operations[ccmsg_CCACHE_GET_KDC_TIME_OFFSET] = ccop_CCACHE_GET_KDC_TIME_OFFSET;
+ TypeToOpMapping->operations[ccmsg_CCACHE_SET_KDC_TIME_OFFSET] = ccop_CCACHE_SET_KDC_TIME_OFFSET;
+ TypeToOpMapping->operations[ccmsg_CCACHE_CLEAR_KDC_TIME_OFFSET] = ccop_CCACHE_CLEAR_KDC_TIME_OFFSET;
+ TypeToOpMapping->operations[ccmsg_CCACHE_ITERATOR_RELEASE] = ccop_CCACHE_ITERATOR_RELEASE;
+ TypeToOpMapping->operations[ccmsg_CCACHE_ITERATOR_NEXT] = ccop_CCACHE_ITERATOR_NEXT;
+ TypeToOpMapping->operations[ccmsg_CREDS_ITERATOR_RELEASE] = ccop_CREDS_ITERATOR_RELEASE;
+ TypeToOpMapping->operations[ccmsg_CREDS_ITERATOR_NEXT] = ccop_CREDS_ITERATOR_NEXT;
+ TypeToOpMapping->operations[ccmsg_CREDS_RELEASE] = ccop_CREDS_RELEASE;
+
+ return ccNoError;
+};
+
+cc_int32
+cci_serv_process_msg(cc_msg_t * msg, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_msg_t** resp_msg)
+{
+ cc_server_context_t* ctx;
+ ccmsg_ctx_only_t* header = (ccmsg_ctx_only_t *)msg->header;
+ cc_int32 code;
+
+ if (msg == NULL || msg->header == NULL || auth_info == NULL || session_info == NULL)
+ return ccErrBadParam;
+
+ if (AllContexts == NULL) {
+ code = cci_serv_initialize();
+ if ( code != ccNoError )
+ return code;
+ }
+
+ if (msg->type == ccmsg_INIT) {
+ return TypeToOpMapping->operations[msg->type] (NULL, auth_info, session_info, msg, resp_msg);
+ } else {
+ if (msg->header_len < sizeof(ccmsg_ctx_only_t)) {
+ return ccErrBadParam;
+ }
+
+ code = cci_serv_find_ctx_by_handle(header->ctx, auth_info, session_info, &ctx);
+ if (code != ccNoError) {
+ cci_serv_make_nack(ccErrContextNotFound, auth_info, session_info, resp_msg);
+ return code;
+ }
+ return TypeToOpMapping->operations[msg->type] (ctx, auth_info, session_info, msg, resp_msg);
+ }
+}
+
+/*deprecated*/
+cc_int32
+cci_serv_find_ctx(cc_auth_info_t* auth_info, cc_session_info_t* session_info,
+ cc_server_context_t** ctxpp)
+{
+ cc_context_iterate_t* ctx_iterator;
+ cc_context_list_node_t* ctx_node;
+ cc_server_context_t* ctx;
+ cc_int32 code;
+ cc_uint32 authorized;
+
+ code = cci_context_list_iterator(AllContexts, &ctx_iterator);
+ if (code != ccNoError)
+ return code;
+
+ while (cci_context_iterate_has_next(ctx_iterator)) {
+ code = cci_context_iterate_next(ctx_iterator, &ctx_node);
+ if (code != ccNoError) {
+ cci_context_free_iterator(ctx_iterator);
+ return code;
+ }
+ ctx = (cc_server_context_t *)ctx_node->data;
+ code = cci_rpc_is_authorized(auth_info, session_info, ctx->auth_info, ctx->session_info, &authorized);
+ if (code != ccNoError) {
+ cci_context_free_iterator(ctx_iterator);
+ return code;
+ }
+
+ if (authorized) {
+ cci_context_free_iterator(ctx_iterator);
+ *ctxpp = ctx;
+ return ccNoError;
+ }
+ }
+ cci_context_free_iterator(ctx_iterator);
+ return ccIteratorEnd;
+}
+
+cc_int32
+cci_serv_find_ctx_by_handle(cc_handle ctx_num, cc_auth_info_t* auth, cc_session_info_t* session, cc_server_context_t** ctxpp)
+{
+ cc_server_context_t* input_ctx = (cc_server_context_t*)ctx_num;
+ cc_context_iterate_t* ctx_iterator;
+ cc_context_list_node_t* ctx_node;
+ cc_server_context_t* ctx;
+ cc_uint32 authorized;
+ cc_int32 code;
+
+ code = cci_context_list_iterator(AllContexts, &ctx_iterator);
+ if (code != ccNoError)
+ return code;
+
+ while (cci_context_iterate_has_next(ctx_iterator)) {
+ code = cci_context_iterate_next(ctx_iterator, &ctx_node);
+ ctx = (cc_server_context_t *)ctx_node->data;
+ if (code != ccNoError) {
+ cci_context_free_iterator(ctx_iterator);
+ return code;
+ }
+
+ code = cci_rpc_is_authorized(auth, session, ctx->auth_info, ctx->session_info, &authorized);
+ if (code != ccNoError) {
+ cci_context_free_iterator(ctx_iterator);
+ return code;
+ }
+
+ if (ctx == input_ctx && authorized) {
+ cci_context_free_iterator(ctx_iterator);
+ *ctxpp = ctx;
+ return ccNoError;
+ }
+ }
+ cci_context_free_iterator(ctx_iterator);
+ return ccIteratorEnd;
+}
+
+cc_int32
+cci_serv_find_ccache_by_handle(cc_server_context_t* ctx, cc_handle ccache, cc_server_ccache_t** ccachepp )
+{
+ cc_ccache_iterate_t* ccache_iterator;
+ cc_ccache_list_node_t* ccache_node;
+ cc_server_ccache_t* stored_ccache;
+ cc_server_ccache_t* target_ccache = (cc_server_ccache_t*)ccache;
+ cc_int32 code;
+
+ code = cci_ccache_list_iterator(ctx->ccaches, &ccache_iterator);
+ if (code != ccNoError)
+ return code;
+
+ while (cci_ccache_iterate_has_next(ccache_iterator)) {
+ code = cci_ccache_iterate_next(ccache_iterator, &ccache_node);
+ if (code != ccNoError) {
+ cci_ccache_free_iterator(ccache_iterator);
+ return code;
+ }
+
+ stored_ccache = (cc_server_ccache_t *)ccache_node->data;
+
+ if (stored_ccache == target_ccache) {
+ cci_ccache_free_iterator(ccache_iterator);
+ *ccachepp = stored_ccache;
+ return ccNoError;
+ }
+ }
+ cci_ccache_free_iterator(ccache_iterator);
+ return ccIteratorEnd;
+}
+
+cc_int32
+cci_serv_find_ccache_iterator_by_handle(cc_server_context_t* ctx, cc_handle iterator, cc_generic_list_node_t** nodepp )
+{
+ cc_generic_iterate_t* gen_iterator;
+ cc_generic_list_node_t* gen_node;
+ cc_ccache_iterate_t* stored_iterator;
+ cc_ccache_iterate_t* target_iterator = (cc_ccache_iterate_t*)iterator;
+ cc_int32 code;
+
+ code = cci_generic_list_iterator(ctx->active_iterators, &gen_iterator);
+ if (code != ccNoError)
+ return code;
+
+ while (cci_generic_iterate_has_next(gen_iterator)) {
+ code = cci_generic_iterate_next(gen_iterator, &gen_node);
+ if (code != ccNoError) {
+ cci_generic_free_iterator(gen_iterator);
+ return code;
+ }
+
+ stored_iterator = (cc_ccache_iterate_t *)gen_node->data;
+ if (stored_iterator == target_iterator) {
+ cci_generic_free_iterator(gen_iterator);
+ *nodepp = gen_node;
+ return ccNoError;
+ }
+ }
+ cci_generic_free_iterator(gen_iterator);
+ return ccIteratorEnd;
+}
+
+cc_int32
+cci_serv_find_creds_iterator_by_handle(cc_server_ccache_t* ccache, cc_handle iterator, cc_generic_list_node_t** nodepp)
+{
+ cc_generic_iterate_t* gen_iterator;
+ cc_generic_list_node_t* gen_node;
+ cc_ccache_iterate_t* stored_iterator;
+ cc_ccache_iterate_t* target_iterator = (cc_ccache_iterate_t*)iterator;
+ cc_int32 code;
+
+ code = cci_generic_list_iterator(ccache->active_iterators, &gen_iterator);
+ if (code != ccNoError)
+ return code;
+
+ while (cci_generic_iterate_has_next(gen_iterator)) {
+ code = cci_generic_iterate_next(gen_iterator, &gen_node);
+ if (code != ccNoError) {
+ cci_generic_free_iterator(gen_iterator);
+ return code;
+ }
+
+ stored_iterator = (cc_ccache_iterate_t *)gen_node->data;
+ if (stored_iterator == target_iterator) {
+ cci_generic_free_iterator(gen_iterator);
+ *nodepp = gen_node;
+ return ccNoError;
+ }
+ }
+ cci_generic_free_iterator(gen_iterator);
+ return ccIteratorEnd;
+}
+
+cc_int32
+cci_serv_make_nack(cc_int32 err_code, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_msg_t** resp_msg)
+{
+ ccmsg_nack_t* nack_header;
+ cc_int32 code;
+
+ code = cci_msg_new(ccmsg_NACK, resp_msg);
+ if (code != ccNoError)
+ return code;
+
+ nack_header = (ccmsg_nack_t*)malloc(sizeof(ccmsg_nack_t));
+ if (nack_header == NULL) {
+ cci_msg_destroy(*resp_msg);
+ *resp_msg = 0;
+ return ccErrNoMem;
+ }
+
+ nack_header->err_code = err_code;;
+ code = cci_msg_add_header(*resp_msg, nack_header, sizeof(ccmsg_nack_t));
+ if (code != ccNoError) {
+ cci_msg_destroy(*resp_msg);
+ *resp_msg = 0;
+ return code;
+ }
+
+ return ccNoError;
+}
+
+cc_int32
+cci_serv_make_ack(void * header, cc_int32 header_len, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_msg_t** resp_msg)
+{
+ cc_int32 code;
+
+ code = cci_msg_new(ccmsg_ACK, resp_msg);
+ if (code != ccNoError)
+ return code;
+
+ if (header != NULL) {
+ code = cci_msg_add_header(*resp_msg, header, header_len);
+ if (code != ccNoError) {
+ cci_msg_destroy(*resp_msg);
+ resp_msg = 0;
+ return code;
+ }
+ }
+ return ccNoError;
+}
+
+cc_int32
+ccop_INIT( cc_server_context_t* ctx, /* not used */
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ cc_uint32 blob_pos;
+ cc_server_context_t *new_ctx;
+ ccmsg_init_resp_t *resp_header;
+ ccmsg_init_t *header = (ccmsg_init_t *)msg->header;
+ cc_context_list_node_t* ctx_node;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_init_t)) {
+ return ccErrBadParam;
+ }
+
+ code = cci_context_new(header->in_version, auth_info, session_info, &new_ctx);
+ if (code != ccNoError) {
+ return code;
+ }
+
+ code = cci_context_list_append(AllContexts, ctx, &ctx_node);
+ if (code != ccNoError) {
+ cci_context_destroy(new_ctx);
+ return code;
+ }
+
+ resp_header = (ccmsg_init_resp_t*)malloc(sizeof(ccmsg_init_resp_t));
+ if (resp_header == NULL) {
+ cci_context_destroy(new_ctx);
+ return ccErrNoMem;
+ }
+
+ code = cci_msg_new(ccmsg_ACK, resp_msg);
+ if (code != ccNoError) {
+ free(resp_header);
+ cci_context_destroy(new_ctx);
+ return code;
+ }
+ code = cci_msg_add_data_blob(*resp_msg, cc_vendor, strlen(cc_vendor) + 1, &blob_pos);
+ if (code != ccNoError) {
+ free(resp_header);
+ cci_context_destroy(new_ctx);
+ cci_msg_destroy(*resp_msg);
+ *resp_msg = 0;
+ return code;
+ }
+
+ resp_header->out_ctx = new_ctx;
+ resp_header->out_version = cc_myversion;
+ resp_header->vendor_offset = blob_pos;
+ resp_header->vendor_length = strlen(cc_vendor) + 1;
+ code = cci_msg_add_header(*resp_msg, resp_header, sizeof(ccmsg_init_resp_t));
+ if (code != ccNoError) {
+ free(resp_header);
+ cci_context_destroy(new_ctx);
+ cci_msg_destroy(*resp_msg);
+ *resp_msg = 0;
+ return code;
+ }
+
+ return ccNoError;
+}
+
+cc_int32
+ccop_CTX_RELEASE( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ctx_release_t* header = (ccmsg_ctx_release_t *)msg->header;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ctx_release_t)) {
+ return ccErrBadParam;
+ }
+
+ code = cci_context_destroy(header->ctx);
+ return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CTX_GET_CHANGE_TIME( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ctx_get_change_time_resp_t* resp_header;
+ ccmsg_ctx_get_change_time_t *header = (ccmsg_ctx_get_change_time_t *)msg->header;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ctx_get_change_time_t)) {
+ return ccErrBadParam;
+ }
+
+ resp_header = (ccmsg_ctx_get_change_time_resp_t*)malloc(sizeof(ccmsg_ctx_get_change_time_resp_t));
+ if (resp_header == NULL) {
+ return ccErrNoMem;
+ }
+
+ resp_header->time = ctx->changed;
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ctx_get_change_time_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CTX_GET_DEFAULT_CCACHE_NAME( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ char * name;
+ ccmsg_ctx_get_default_ccache_name_resp_t* resp_header;
+ ccmsg_ctx_get_default_ccache_name_t* header = (ccmsg_ctx_get_default_ccache_name_t *)msg->header;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ctx_get_default_ccache_name_t)) {
+ return ccErrBadParam;
+ }
+
+ code = cci_context_get_default_ccache_name(ctx, &name);
+ if (code != ccNoError)
+ return code;
+
+ code = cci_msg_new(ccmsg_ACK, resp_msg);
+ if (code != ccNoError)
+ return code;
+
+ resp_header = (ccmsg_ctx_get_default_ccache_name_resp_t*)malloc(sizeof(ccmsg_ctx_get_default_ccache_name_resp_t));
+ if (resp_header == NULL) {
+ cci_msg_destroy(*resp_msg);
+ *resp_msg = 0;
+ return ccErrNoMem;
+ }
+
+ code = cci_msg_add_data_blob(*resp_msg, name, strlen(name) + 1, &resp_header->name_offset);
+ resp_header->name_len = strlen(name) + 1;
+ return ccNoError;
+}
+
+cc_int32
+ccop_CTX_COMPARE(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ cc_server_context_t *ctx2;
+ ccmsg_ctx_compare_resp_t* resp_header;
+ ccmsg_ctx_compare_t* header = (ccmsg_ctx_compare_t *)msg->header;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ctx_compare_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ctx_by_handle(header->ctx2, auth_info, session_info, &ctx2);
+
+ resp_header = (ccmsg_ctx_compare_resp_t*)malloc(sizeof(ccmsg_ctx_compare_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ resp_header->is_equal = cci_context_compare(ctx, ctx2);
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ctx_compare_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CTX_NEW_CCACHE_ITERATOR(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ cc_ccache_iterate_t* ccache_iterator;
+ ccmsg_ctx_new_ccache_iterator_resp_t* resp_header;
+ ccmsg_ctx_new_ccache_iterator_t* header = (ccmsg_ctx_new_ccache_iterator_t*)msg->header;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ctx_new_ccache_iterator_t))
+ return ccErrBadParam;
+
+ code = cci_context_ccache_iterator(ctx,&ccache_iterator);
+
+ resp_header = (ccmsg_ctx_new_ccache_iterator_resp_t*)malloc(sizeof(ccmsg_ctx_new_ccache_iterator_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ resp_header->iterator = ccache_iterator;
+
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ctx_new_ccache_iterator_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CTX_LOCK( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ // TODO
+ return cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CTX_UNLOCK( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ // TODO
+ return cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CTX_CLONE( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ // TODO
+ return cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_OPEN(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ char *name;
+ cc_server_ccache_t* ccache;
+ ccmsg_ccache_open_resp_t* resp_header;
+ ccmsg_ccache_open_t* header = (ccmsg_ccache_open_t*)msg->header;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_open_t))
+ return ccErrBadParam;
+
+ code = cci_msg_retrieve_blob(msg, header->name_offset, header->name_len, &name);
+ code = cci_context_find_ccache(ctx, name, &ccache);
+
+ free(name);
+
+ if (ccache == NULL)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ resp_header = (ccmsg_ccache_open_resp_t*)malloc(sizeof(ccmsg_ccache_open_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ resp_header->ccache = ccache;
+ cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_open_resp_t), auth_info, session_info, resp_msg);
+ return ccNoError;
+}
+
+cc_int32
+ccop_CCACHE_OPEN_DEFAULT(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_open_default_t* header = (ccmsg_ccache_open_default_t*)msg->header;
+ ccmsg_ccache_open_resp_t* resp_header;
+ cc_server_ccache_t* ccache;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_open_default_t))
+ return ccErrBadParam;
+
+ if (ctx->ccaches->head->data == NULL)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ ccache = (cc_server_ccache_t*) ctx->ccaches->head->data;
+
+ resp_header = (ccmsg_ccache_open_resp_t*)malloc(sizeof(ccmsg_ccache_open_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ resp_header->ccache = ccache;
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_open_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_CREATE(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_create_resp_t* resp_header;
+ ccmsg_ccache_create_t* header = (ccmsg_ccache_create_t*)msg->header;
+ cc_server_ccache_t* ccache;
+ char* principal;
+ char* name;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_create_t))
+ return ccErrBadParam;
+
+ code = cci_msg_retrieve_blob(msg, header->principal_offset, header->principal_len, &principal);
+ if (code != ccNoError)
+ return code;
+ principal[header->principal_len] = '\0'; /*Ensure null termination*/
+
+ code = cci_msg_retrieve_blob(msg, header->name_offset, header->name_len, &name);
+ if (code != ccNoError)
+ return code;
+ name[header->name_len] = '\0'; /*Ensure null termination*/
+
+ code = cci_context_create_ccache(ctx, name, header->version, principal, &ccache);
+ if (code != ccNoError)
+ return code;
+
+ resp_header = (ccmsg_ccache_create_resp_t*)malloc(sizeof(ccmsg_ccache_create_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ resp_header->ccache = ccache;
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_create_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_CREATE_DEFAULT( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_create_resp_t* resp_header;
+ ccmsg_ccache_create_t* header = (ccmsg_ccache_create_t*)msg->header;
+ cc_server_ccache_t* ccache;
+ char* principal;
+ char* name;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_create_t))
+ return ccErrBadParam;
+
+ code = cci_msg_retrieve_blob(msg, header->principal_offset, header->principal_len, &principal);
+ if (code != ccNoError)
+ return code;
+ principal[header->principal_len] = '\0'; /*Ensure null termination*/
+
+ code = cci_context_get_default_ccache_name(ctx, &name);
+ if (code != ccNoError)
+ return code;
+
+ code = cci_context_create_ccache(ctx, name, header->version, principal, &ccache);
+ if (code != ccNoError)
+ return code;
+
+ resp_header = (ccmsg_ccache_create_resp_t*)malloc(sizeof(ccmsg_ccache_create_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ resp_header->ccache = ccache;
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_create_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_CREATE_UNIQUE( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_create_resp_t* resp_header;
+ ccmsg_ccache_create_t* header = (ccmsg_ccache_create_t*)msg->header;
+ cc_server_ccache_t* ccache;
+ char* principal;
+ char* name;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_create_t))
+ return ccErrBadParam;
+
+ code = cci_msg_retrieve_blob(msg, header->principal_offset, header->principal_len, &principal);
+ if (code != ccNoError)
+ return code;
+ principal[header->principal_len] = '\0'; /*Ensure null termination*/
+
+ // TODO: Generate a unique ccache name
+
+ code = cci_context_create_ccache(ctx, name, header->version, principal, &ccache);
+ if (code != ccNoError)
+ return code;
+
+ resp_header = (ccmsg_ccache_create_resp_t*)malloc(sizeof(ccmsg_ccache_create_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ resp_header->ccache = ccache;
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_create_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_RELEASE( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ // TODO: This is probably wrong.
+ return ccop_CCACHE_DESTROY(ctx, auth_info, session_info, msg, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_DESTROY( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_release_t* header = (ccmsg_ccache_release_t*)msg->header;
+ cc_server_ccache_t* ccache;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_release_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ cci_ccache_destroy(ccache);
+
+ return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_SET_DEFAULT(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ cc_server_ccache_t* ccache, *stored_ccache, *old_default;
+ ccmsg_ccache_set_default_t* header = (ccmsg_ccache_set_default_t*)msg->header;
+ cc_ccache_iterate_t* ccache_iterator;
+ cc_ccache_list_node_t* ccache_node;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_set_default_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ if (ccache == (cc_server_ccache_t*)ctx->ccaches->head->data) /*already default*/
+ return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+
+ old_default = (cc_server_ccache_t*)ctx->ccaches->head->data;
+ old_default->last_default = time(NULL);
+
+ code = cci_ccache_list_iterator(ctx->ccaches, &ccache_iterator);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ while (cci_ccache_iterate_has_next(ccache_iterator)) {
+ code = cci_ccache_iterate_next(ccache_iterator,&ccache_node);
+ stored_ccache = (cc_server_ccache_t*)ccache_node->data;
+
+ if (stored_ccache == ccache) {
+ ccache_node->data = NULL; /*don't want list removal code free()ing ccache*/
+ cci_ccache_list_remove_element(ctx->ccaches, ccache_node);
+ cci_ccache_list_prepend(ctx->ccaches, ccache, NULL);
+ break;
+ }
+ }
+ return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_GET_CREDS_VERSION(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_get_creds_version_t* header = (ccmsg_ccache_get_creds_version_t*)msg->header;
+ ccmsg_ccache_get_creds_version_resp_t* resp_header;
+ cc_server_ccache_t* ccache;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_get_creds_version_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ resp_header = (ccmsg_ccache_get_creds_version_resp_t*)malloc(sizeof(ccmsg_ccache_get_creds_version_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ resp_header->version = ccache->versions;
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_get_creds_version_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_GET_NAME(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_get_name_t* header = (ccmsg_ccache_get_name_t*)msg->header;
+ ccmsg_ccache_get_name_resp_t* resp_header;
+ cc_server_ccache_t* ccache;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_get_name_resp_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (ccache == NULL)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ resp_header = (ccmsg_ccache_get_name_resp_t*)malloc(sizeof(ccmsg_ccache_get_name_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ code = cci_msg_new(ccmsg_ACK, resp_msg);
+ if (code != ccNoError)
+ return code;
+
+ code = cci_msg_add_data_blob(*resp_msg, ccache->name, strlen(ccache->name) + 1, &resp_header->name_offset);
+ resp_header->name_len = strlen(ccache->name) + 1;
+ cci_msg_add_header(*resp_msg, resp_header, sizeof(ccmsg_ccache_get_name_resp_t));
+
+ return ccNoError;
+}
+
+cc_int32
+ccop_CCACHE_GET_PRINCIPAL(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_get_principal_t* header = (ccmsg_ccache_get_principal_t*)msg->header;
+ ccmsg_ccache_get_principal_resp_t* resp_header;
+ cc_server_ccache_t* ccache;
+ char * principal;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_get_principal_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ code = cci_ccache_get_principal(ccache, header->version, &principal);
+ if (code != ccNoError)
+ return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+ code = cci_msg_new(ccmsg_ACK, resp_msg);
+ if (code != ccNoError)
+ return code;
+
+ resp_header = (ccmsg_ccache_get_principal_resp_t*)malloc(sizeof(ccmsg_ccache_get_principal_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ code = cci_msg_add_data_blob(*resp_msg, principal, strlen(principal) + 1, &resp_header->principal_offset);
+ cci_msg_add_header(*resp_msg, resp_header, sizeof(ccmsg_ccache_get_principal_resp_t));
+
+ return ccNoError;
+}
+
+cc_int32
+ccop_CCACHE_SET_PRINCIPAL(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_set_principal_t* header = (ccmsg_ccache_set_principal_t*)msg->header;
+ cc_server_ccache_t* ccache;
+ char *principal;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_set_principal_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ code = cci_msg_retrieve_blob(msg, header->principal_offset, header->principal_len, &principal);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrBadParam, auth_info, session_info, resp_msg);
+
+ code = cci_ccache_set_principal(ccache, header->version, principal);
+ if (code != ccNoError)
+ return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+ return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_CREDS_ITERATOR(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ cc_server_ccache_t* ccache;
+ cc_credentials_iterate_t* creds_iterator;
+ ccmsg_ccache_creds_iterator_t* header = (ccmsg_ccache_creds_iterator_t*)msg->header;
+ ccmsg_ccache_creds_iterator_resp_t* resp_header;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_creds_iterator_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ code = cci_ccache_new_iterator(ccache, &creds_iterator);
+ if (code != ccNoError)
+ return code;
+
+ resp_header = (ccmsg_ccache_creds_iterator_resp_t*)malloc(sizeof(ccmsg_ccache_creds_iterator_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ resp_header->iterator = creds_iterator;
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_creds_iterator_resp_t), auth_info, session_info, resp_msg);
+}
+
+
+static cc_int32
+cci_credentials_union_release( cc_credentials_union * creds )
+{
+ int i;
+
+ switch (creds->version) {
+ case cc_credentials_v4:
+ free(creds->credentials.credentials_v4);
+ break;
+ case cc_credentials_v5:
+ if ( creds->credentials.credentials_v5->client )
+ free(creds->credentials.credentials_v5->client);
+ if ( creds->credentials.credentials_v5->server )
+ free(creds->credentials.credentials_v5->server );
+ if ( creds->credentials.credentials_v5->keyblock.data )
+ free(creds->credentials.credentials_v5->keyblock.data);
+ if ( creds->credentials.credentials_v5->ticket.data )
+ free(creds->credentials.credentials_v5->ticket.data);
+ if ( creds->credentials.credentials_v5->second_ticket.data )
+ free(creds->credentials.credentials_v5->second_ticket.data);
+ if ( creds->credentials.credentials_v5->addresses ) {
+ for ( i=0; creds->credentials.credentials_v5->addresses[i]; i++) {
+ if (creds->credentials.credentials_v5->addresses[i]->data)
+ free(creds->credentials.credentials_v5->addresses[i]->data);
+ }
+ free(creds->credentials.credentials_v5->addresses);
+ }
+ if ( creds->credentials.credentials_v5->authdata ) {
+ for ( i=0; creds->credentials.credentials_v5->authdata[i]; i++) {
+ if ( creds->credentials.credentials_v5->authdata[i]->data )
+ free(creds->credentials.credentials_v5->authdata[i]->data);
+ }
+ free(creds->credentials.credentials_v5->authdata);
+ }
+ break;
+ default:
+ return ccErrBadCredentialsVersion;
+ }
+ return ccNoError;
+}
+
+cc_int32
+ccop_CCACHE_STORE_CREDS(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_store_creds_t* header = (ccmsg_ccache_store_creds_t*)msg->header;
+ cc_server_ccache_t* ccache;
+ char *flat_creds;
+ cc_credentials_union *creds;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_store_creds_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ // TODO: This code is too simplistic. cc_credential_unions are not flat
+ // structures and must be flattened. That means that although we can
+ // store a flat blob in the message we will need to decode the blob
+ // into the actual object.
+ code = cci_msg_retrieve_blob(msg, header->creds_offset, header->creds_len, &flat_creds);
+ if (code != ccNoError)
+ return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+ creds = (cc_credentials_union *)malloc(sizeof(cc_credentials_union));
+ if ( creds == NULL )
+ return ccErrNoMem;
+
+ switch ( creds->version ) {
+ case cc_credentials_v4:
+ code = cci_creds_v4_unmarshall(flat_creds, header->creds_len, creds);
+ break;
+ case cc_credentials_v5:
+ code = cci_creds_v5_unmarshall(flat_creds, header->creds_len, creds);
+ break;
+ default:
+ return cci_serv_make_nack(ccErrBadCredentialsVersion, auth_info, session_info, resp_msg);
+ }
+ if (code != ccNoError)
+ return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+ code = cci_ccache_store_creds(ccache, creds);
+ cci_credentials_union_release(creds);
+ if (code != ccNoError) {
+ return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+ }
+
+ return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_REM_CREDS(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_rem_creds_t* header = (ccmsg_ccache_rem_creds_t*)msg->header;
+ cc_server_ccache_t* ccache;
+ cc_credentials_union *creds;
+ cc_int32 code;
+
+ *resp_msg = 0;
+ if (msg->header_len != sizeof(ccmsg_ccache_rem_creds_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ code = cci_ccache_rem_creds(ccache, header->creds);
+ if (code != ccNoError)
+ return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+ return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_LOCK( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ // TODO
+ return cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_UNLOCK( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ // TODO
+ return cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_MOVE( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ // TODO
+ return cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+}
+
+
+cc_int32
+ccop_CCACHE_GET_LAST_DEFAULT_TIME(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_get_last_default_time_t* header = (ccmsg_ccache_get_last_default_time_t*)msg->header;
+ ccmsg_ccache_get_last_default_time_resp_t* resp_header;
+ cc_server_ccache_t* ccache;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_get_last_default_time_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ resp_header = (ccmsg_ccache_get_last_default_time_resp_t*)malloc(sizeof(ccmsg_ccache_get_last_default_time_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ resp_header->last_default_time = ccache->last_default;
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_get_last_default_time_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_GET_CHANGE_TIME( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_get_change_time_resp_t* resp_header;
+ ccmsg_ccache_get_change_time_t *header = (ccmsg_ccache_get_change_time_t *)msg->header;
+ cc_server_ccache_t* ccache = (cc_server_ccache_t *)header->ccache;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_get_change_time_t)) {
+ return ccErrBadParam;
+ }
+
+ resp_header = (ccmsg_ccache_get_change_time_resp_t*)malloc(sizeof(ccmsg_ccache_get_change_time_resp_t));
+ if (resp_header == NULL) {
+ return ccErrNoMem;
+ }
+
+ resp_header->time = ccache->changed;
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_get_change_time_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_COMPARE(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_compare_t* header = (ccmsg_ccache_compare_t*)msg->header;
+ ccmsg_ccache_compare_resp_t* resp_header;
+ cc_server_ccache_t* ccache1, *ccache2;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_compare_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache1, &ccache1);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache2, &ccache2);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ resp_header = (ccmsg_ccache_compare_resp_t*)malloc(sizeof(ccmsg_ccache_compare_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ cci_ccache_compare(ccache1, ccache2, &resp_header->is_equal);
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_compare_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_GET_KDC_TIME_OFFSET(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_get_kdc_time_offset_t* header = (ccmsg_ccache_get_kdc_time_offset_t*)msg->header;
+ ccmsg_ccache_get_kdc_time_offset_resp_t* resp_header;
+ cc_server_ccache_t* ccache;
+ cc_time_t offset;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_get_kdc_time_offset_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ // TODO How is the header->creds_version supposed to be used?
+
+ code = cci_ccache_get_kdc_time_offset(ccache, &offset);
+ if (code != ccNoError)
+ return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+ resp_header = (ccmsg_ccache_get_kdc_time_offset_resp_t*)malloc(sizeof(ccmsg_ccache_get_kdc_time_offset_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ resp_header->offset = offset;
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_get_kdc_time_offset_resp_t), auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_SET_KDC_TIME_OFFSET(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_set_kdc_time_offset_t* header = (ccmsg_ccache_set_kdc_time_offset_t*)msg->header;
+ cc_server_ccache_t* ccache;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_set_kdc_time_offset_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ // TODO How is the header->creds_version supposed to be used?
+
+ cci_ccache_set_kdc_time_offset(ccache, header->offset);
+ return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_CLEAR_KDC_TIME_OFFSET(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_clear_kdc_time_offset_t* header = (ccmsg_ccache_clear_kdc_time_offset_t*)msg->header;
+ cc_server_ccache_t* ccache;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_clear_kdc_time_offset_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ // TODO How is the header->creds_version supposed to be used?
+
+ cci_ccache_clear_kdc_time_offset(ccache);
+ return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_ITERATOR_RELEASE(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ cc_generic_list_node_t* gen_node;
+ ccmsg_ccache_iterator_release_t* header = (ccmsg_ccache_iterator_release_t*)msg->header;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_iterator_release_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_iterator_by_handle(ctx, header->iterator, &gen_node);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrBadParam, auth_info, session_info, resp_msg);
+
+ code = cci_generic_list_remove_element(ctx->active_iterators, gen_node);
+ if (code != ccNoError)
+ return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+ return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CCACHE_ITERATOR_NEXT(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_ccache_iterator_release_t* header = (ccmsg_ccache_iterator_release_t*)msg->header;
+ ccmsg_ccache_iterator_next_resp_t* resp_header;
+ cc_generic_list_node_t* gen_node;
+ cc_ccache_iterate_t* ccache_iterator;
+ cc_ccache_list_node_t *ccache_node;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_ccache_iterator_next_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_iterator_by_handle(ctx, header->iterator, &gen_node);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrBadParam, auth_info, session_info, resp_msg);
+
+ ccache_iterator = (cc_ccache_iterate_t*)gen_node->data;
+ if (cci_ccache_iterate_has_next(ccache_iterator)) {
+ resp_header = (ccmsg_ccache_iterator_next_resp_t*)malloc(sizeof(ccmsg_ccache_iterator_next_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ code = cci_ccache_iterate_next(ccache_iterator, &ccache_node);
+ if (code != ccNoError)
+ return cci_serv_make_nack(code, auth_info, session_info, resp_msg);
+
+ resp_header->ccache = ccache_node;
+ return cci_serv_make_ack(resp_header, sizeof(ccmsg_ccache_iterator_next_resp_t), auth_info, session_info, resp_msg);
+ } else {
+ return cci_serv_make_nack(ccIteratorEnd, auth_info, session_info, resp_msg);
+ }
+}
+
+cc_int32
+ccop_CREDS_ITERATOR_RELEASE(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ cc_generic_list_node_t* gen_node;
+ cc_server_ccache_t* ccache;
+ ccmsg_creds_iterator_release_t* header = (ccmsg_creds_iterator_release_t*)msg->header;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_creds_iterator_release_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ code = cci_serv_find_creds_iterator_by_handle(ccache, header->iterator, &gen_node);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrBadParam, auth_info, session_info, resp_msg);
+
+ code = cci_generic_list_remove_element(ccache->active_iterators, gen_node);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrBadParam, auth_info, session_info, resp_msg);
+
+ return cci_serv_make_ack(NULL, 0, auth_info, session_info, resp_msg);
+}
+
+cc_int32
+ccop_CREDS_ITERATOR_NEXT(cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+ ccmsg_creds_iterator_next_t* header = (ccmsg_creds_iterator_next_t*)msg->header;
+ ccmsg_creds_iterator_next_resp_t* resp_header;
+ cc_credentials_iterate_t* creds_iterator;
+ cc_generic_list_node_t* gen_node;
+ cc_credentials_list_node_t* creds_node;
+ cc_server_ccache_t* ccache;
+ cc_server_credentials_t* stored_creds;
+ cc_credentials_union *creds_union;
+ cc_int32 code;
+
+ *resp_msg = 0;
+
+ if (msg->header_len != sizeof(ccmsg_creds_iterator_next_t))
+ return ccErrBadParam;
+
+ code = cci_serv_find_ccache_by_handle(ctx, header->ccache, &ccache);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrCCacheNotFound, auth_info, session_info, resp_msg);
+
+ code = cci_serv_find_creds_iterator_by_handle(ccache, header->iterator, &gen_node);
+ if (code != ccNoError)
+ return cci_serv_make_nack(ccErrBadParam, auth_info, session_info, resp_msg);
+
+ creds_iterator = (cc_credentials_iterate_t*)gen_node->data;
+ if (cci_credentials_iterate_has_next(creds_iterator)) {
+ code = cci_msg_new(ccmsg_ACK, resp_msg);
+ if (code != ccNoError)
+ return code;
+
+ resp_header = (ccmsg_creds_iterator_next_resp_t*)malloc(sizeof(ccmsg_creds_iterator_next_resp_t));
+ if (resp_header == NULL)
+ return ccErrNoMem;
+
+ code = cci_credentials_iterate_next(creds_iterator, &creds_node);
+ stored_creds = (cc_server_credentials_t*)creds_node->data;
+ creds_union = &stored_creds->creds;
+
+ code = cci_msg_add_data_blob(*resp_msg, creds_union, sizeof(cc_credentials_union), &resp_header->creds_offset);
+ code = cci_msg_add_header(*resp_msg, resp_header, sizeof(ccmsg_creds_iterator_next_resp_t));
+ } else {
+ cci_serv_make_nack(ccIteratorEnd, auth_info, session_info, resp_msg);
+ }
+ return ccNoError;
+}
+
+cc_int32
+ccop_CREDS_RELEASE( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg, cc_msg_t **resp_msg)
+{
+
+ cci_serv_make_nack(ccErrNotImplemented, auth_info, session_info, resp_msg);
+ return ccNoError;
+}
diff --git a/src/lib/ccapi/server/serv_ops.h b/src/lib/ccapi/server/serv_ops.h
new file mode 100644
index 000000000..f43956685
--- /dev/null
+++ b/src/lib/ccapi/server/serv_ops.h
@@ -0,0 +1,321 @@
+/* $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).
+ * $
+ */
+
+/*
+ * Prototypes for serv_ops.c
+ */
+
+#ifndef __SERV_OPS_H__
+#define __SERV_OPS_H__
+
+#include "CredentialsCache.h"
+#include "rpc_auth.h"
+#include "msg.h"
+#include "datastore.h"
+
+struct type_to_op_mapping_t {
+ cc_int32 (*operations[CC_MSG_MAX_TYPE]) (
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+};
+typedef struct type_to_op_mapping_t type_to_op_mapping_t;
+
+cc_int32 cci_serv_initialize(void);
+cc_int32 cci_serv_process_msg(cc_msg_t * msg, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_msg_t** resp_msg);
+cc_int32 cci_serv_find_ctx(cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_server_context_t** contextp);
+cc_int32 cci_serv_find_ctx_by_handle(cc_handle ctx_handle, cc_auth_info_t *auth, cc_session_info_t* session, cc_server_context_t** contextp);
+cc_int32 cci_serv_find_ccache_by_handle(cc_server_context_t* ctx, cc_handle ccache_handle, cc_server_ccache_t** ccachep) ;
+cc_int32 cci_serv_find_ccache_iterator_by_handle(cc_server_context_t* ctx, cc_handle iterator, cc_generic_list_node_t** nodep);
+cc_int32 cci_serv_find_creds_iterator_by_handle(cc_server_ccache_t* ccache, cc_handle iterator, cc_generic_list_node_t** nodep);
+cc_int32 cci_serv_make_nack(cc_int32 err_code, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_msg_t** msgp);
+cc_int32 cci_serv_make_ack(void * header, cc_int32 header_len, cc_auth_info_t* auth_info, cc_session_info_t* session_info, cc_msg_t** msgp);
+
+cc_int32 ccop_INIT(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CTX_RELEASE(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CTX_GET_CHANGE_TIME(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CTX_GET_DEFAULT_CCACHE_NAME(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CTX_COMPARE(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CTX_NEW_CCACHE_ITERATOR(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32
+ccop_CTX_LOCK( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32
+ccop_CTX_UNLOCK( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32
+ccop_CTX_CLONE( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_OPEN(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_OPEN_DEFAULT(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_CREATE(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32
+ccop_CCACHE_CREATE_DEFAULT( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32
+ccop_CCACHE_CREATE_UNIQUE( cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_RELEASE(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_DESTROY(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_SET_DEFAULT(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_GET_CREDS_VERSION(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_GET_NAME(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_GET_PRINCIPAL(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_SET_PRINCIPAL(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_CREDS_ITERATOR(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_STORE_CREDS(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_REM_CREDS(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_GET_LAST_DEFAULT_TIME(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32
+ccop_CCACHE_GET_CHANGE_TIME(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg) ;
+
+cc_int32 ccop_CCACHE_COMPARE(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_GET_KDC_TIME_OFFSET(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_SET_KDC_TIME_OFFSET(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_CLEAR_KDC_TIME_OFFSET(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_ITERATOR_RELEASE(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CCACHE_ITERATOR_NEXT(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CREDS_ITERATOR_RELEASE(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CREDS_ITERATOR_NEXT(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+
+cc_int32 ccop_CREDS_RELEASE(
+ cc_server_context_t* ctx,
+ cc_auth_info_t* auth_info,
+ cc_session_info_t* session_info,
+ cc_msg_t *msg,
+ cc_msg_t **resp_msg);
+#endif /*__SERV_OPS_H__*/
diff --git a/src/lib/ccapi/server/windows/ChangeLog b/src/lib/ccapi/server/windows/ChangeLog
new file mode 100644
index 000000000..aaa59da72
--- /dev/null
+++ b/src/lib/ccapi/server/windows/ChangeLog
@@ -0,0 +1,4 @@
+2004-10-27 Jeffrey Altman <jaltman@mit.edu>
+
+ * Initial commit of C CCAPI implementation
+