# Credentials Cache API (CCAPI) Documentation

## Table of Contents

- Introduction
- Error Handling
- Synchronization and Atomicity
- Object Memory Management
- Opaque Types

- Constants
- Basic Types

- cc_context_t Overview
- cc_context_t Functions

- cc_ccache_t Overview
- cc_ccache_t Functions

- cc_credentials_t Overview
- cc_credentials_t Functions

- cc_ccache_iterator_t Overview
- cc_ccache_iterator_t Functions

- cc_credentials_iterator_t
- cc_credentials_iterator_t Functions

- cc_string_t Overview
- cc_string_t Functions

## Introduction

This is the specification for an API which provides Credentials Cache services for both Kerberos v5 and v4. The idea behind this API is that multiple Kerberos implementations can share a single collection of credentials caches, mediated by this API specification. On the Mac OS and Microsoft Windows platforms this will allow single-login, even when more than one Kerberos shared library is in use on a particular system.

Abstractly, a credentials cache collection contains one or more credentials caches, or ccaches. A ccache is uniquely identified by its name, which is a string internal to the API and not intended to be presented to users. The user presentable identifier of a ccache is its principal.

Unlike the previous versions of the API, version 3 of the API stores both Kerberos v4 and v5 credentials in the same ccache.

At any given time, one ccache is the "default" ccache. The exact meaning of a default ccache is OS-specific; refer to implementation requirements for details.

## Error Handling

All functions of the API return some of the error constants listed FIXME; the exact list of error constants returned by any API function is provided in the function descriptions below.

When returning an error constant other than ccNoError or ccIteratorEnd, API functions never modify any of the values passed in by reference.

## Synchronization and Atomicity

Every function in the API is atomic. In order to make a series of calls atomic, callers should lock the ccache or cache collection they are working with to advise other callers not to modify that container. Note that advisory locks are per container so even if you have a read lock on the cache collection other callers can obtain write locks on ccaches in that cache collection.

Note that iterators do not iterate over ccaches and credentials atomically because locking ccaches and the cache collection over every iteration would degrade performance considerably under high load. However, iterators do guarantee a consistent view of items they are iterating over. Iterators will never return duplicate entries or skip entries when items are removed or added to the container they are iterating over.

An application can always lock a ccache or the cache collection to guarantee that other callers participating in the advisory locking system do not modify the ccache or cache collection.

Implementations should not use copy-on-write techniques to implement locks because those techniques imply that same parts of the ccache collection remain visible to some callers even though they are not present in the collection, which is a potential security risk. For example, a copy-on-write technique might make a copy of the entire collection when a read lock is acquired, so as to allow the owner of the lock to access the collection in an apparently unmodified state, while also allowing others to make modifications to the collection. However, this would also enable the owner of the lock to indefinitely (until the expiration time) use credentials that have actually been deleted from the collection.

## Object Memory Management

The lifetime of an object returned by the API is until release() is called for it. Releasing one object has no effect on existence of any other object. For example, a ccache obtained within a context continue to exist when the context is released.

Every object returned by the API (cc_context_t, cc_ccache_t, cc_ccache_iterator_t, cc_credentials_t, cc_credentials_iterator_t, cc_string_t) is owned by the caller of the API, and it is the responsibility of the caller to call release() for every object to prevent memory leaks.

## Opaque Types

All of the opaque high-level types in CCache API are implemented as structures of function pointers and private data. To perform some operation on a type, the caller of the API has to first obtain an instance of that type, and then call the appropriate function pointer from that instance. For example, to call get_change_time() on a cc_context_t, one would call cc_initialize() which creates a new cc_context_t and then call its get_change_time(), like this:

     cc_context_t context;
     cc_int32 err = cc_initialize (&context, ccapi_version_3, nil, nil);
     if (err == ccNoError)
     time = context->functions->get_change_time (context)

All API functions also have convenience preprocessor macros, which make the API seem completely function-based. For example, cc_context_get_change_time (context, time) is equivalent to context->functions->get_change_time (context, time). The convenience macros follow the following naming convention:

The API function some_function()

     cc_type_t an_object;
     result = an_object->functions->some_function (opaque_pointer, args)

has an equivalent convenience macro of the form cc_type_some_function():

     cc_type_t an_object;
     result = cc_type_some_function (an_object, args)

The specifications below include the names for both the functions and the convenience macros, in that order. For clarity, it is recommended that clients using the API use the convenience macros, but that is merely a stylistic choice.

Implementing the API in this manner allows us to extend and change the interface in the future, while preserving compatibility with older clients.

For example, consider the case when the signature or the semantics of a cc_ccache_t function is changed. The API version number is incremented. The library implementation contains both a function with the old signature and semantics and a function with the new signature and semantics. When a context is created, the API version number used in that context is stored in the context, and therefore it can be used whenever a ccache is created in that context. When a ccache is created in a context with the old API version number, the function pointer structure for the ccache is filled with pointers to functions implementing the old semantics; when a ccache is created in a context with the new API version number, the function pointer structure for the ccache is filled with poitners to functions implementing the new semantics.

Similarly, if a function is added to the API, the version number in the context can be used to decide whether to include the implementation of the new function in the appropriate function pointer structure or not.