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.
When returning an error constant other than ccNoError or ccIteratorEnd, API functions never modify any of the values passed in by reference.
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.
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.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.