MIT Information Systems

Macintosh Development

[Home] [About Us] [People] [Information Systems]
[Kerberos for Macintosh] [Applications] [Miscellaneous Documentation]


Credentials Cache API v3 Specification


Abstract

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.


New in revision 7 (API Version 3 second draft)

March 11, 2000, by meeroh

New in revision 6 (API Version 3 draft)

October 11, 1999, by meeroh

Also see the revision history for previous versions


Constants

CCache API version constants

// enums for API versions used in cc_initialize()
enum {
   ccapi_version_2 = 2,
   ccapi_version_3 = 3
};

These constants are passed into cc_initialize() to indicate the version of the API the caller wants to use.

CCache API v1 and v2 are incompatible, and therefore the v1 version number has been removed. Clients shouldn't be using the v1 API.

Credentials versions constants

enum {  
    cc_credentials_v4 = 1,             // Kerberos v4 credentials
    cc_credentials_v5 = 2,             // Kerberos v5 credentials
    cc_credentials_v4_v5 = cc_credentials_v4 | cc_credentials_v5
                                       // Kerberos v4 and v5 credentials
};

These constants are used in several places in the API to discern between Kerberos v4 and Kerberos v5. Not all values are valid inputs and outputs for all functions; function specifications below detail the allowed values.

Kerberos version constants will always be a bit-field, and can be tested as such; for example:

if ((ccacheVersion & cc_credentials_v5) != 0) /* ccache has v5 credentials */

Lock types

enum cc_lock_type {
    cc_lock_read = 0,
    cc_lock_write = 1,
    cc_lock_block = 2,
    cc_lock_noblock = 3,
};

These constants are used in locking functions to describe the type of lock requested. Read locks, when granted, give the owner of the lock the ability to inspect the locked object. Write locks, when granted, give the owner of the lock the ability to modify the locked object. Attempting to acquire a lock with a non-blocking call will result in an error if the lock cannot be acquired; otherwise, the call will block until the lock can be acquired.

Error constants

ccNoError Successful return
201  ccIteratorEnd Iterator is done iterating
202 ccErrBadParam Bad parameter (NULL or invalid pointer where valid pointer expected)
203 ccErrNoMem Not enough memory to complete the operation
204 ccErrInvalidContext Context is invalid (e.g., it was released)
205 ccErrInvalidCCache CCache is invalid (e.g., it was released or destroyed)
206 ccErrInvalidString String is invalid (e.g., it was released)
207 ccErrInvalidCredentials Credentials are invalid (e.g., they were released), or they have a bad version
208 ccErrInvalidCCacheIterator CCache iterator is invalid (e.g., it was released)
209 ccErrInvalidCredentialsIterator Credentials iterator is invalid (e.g., it was released)
210 ccErrInvalidLock Lock is invalid (e.g., it was released)
211 ccErrBadName Bad credential cache name format
212 ccErrBadCredentialsVersion Credentials version is invalid
213 ccErrBadAPIVersion Unsupported API version
214 ccErrContextLocked Context is already locked
215 ccErrContextUnlocked Context is not locked by the caller
216 ccErrCCacheLocked CCache is already locked
217 ccErrCCacheUnlocked CCache is not locked by the caller
218 ccErrBadLockType Bad lock type
219 ccErrNeverDefault CCache was never default
220 ccErrCredentialsNotFound Matching credentials not found in the ccache
221 ccErrCCacheNotFound Matching ccache not found in the collection (either a name was supplied to a function, and no ccache with that name exists, or a cc_ccache_t was supplied and the corresponding ccache has been destroyed).

API behavior

Error handling

All functions of the API return some of the error constants listed above; 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. Every function acquires a lock before accessing any ccache or the collection, and releases the lock before returning; the scope of the lock is the smallest possible i.e. only as few individual ccaches as needed are locked; otherwise, the entire collection is locked. The restrictions of the lock are the narrowest possible, i.e. the lock is a read lock unless the ccache or the collection need to be modified.

Iterators, in addition to every function being atomic, iterate over ccacches or credentials atomically. That means that the caller is guaranteed that the set of ccaches or credentials that is iterated over will not change during the lifetime of the iterator (except as noted below). The lock is acquired when the iterator is created. The lock is released when the iterator is released. The lock is a reader lock, which means that if you intend to make modifications to the iteration set while iterating, you need to upgrade to a writer lock first.

The only case when the iteration set will be modified while the iterator is active is when the owner of the iterator makes modifications. The only guarantee made in this case is that deleting an element on the iteration set has no effect on which elements will be subsequently returned by the iterator (note that their order can be affected, however). This allows one to iterate over an iteration set and delete all its elements.

Locking implementation 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 lifetimes and 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.

Platform-specific behaviors and requirements

Mac OS

It is an error to hold any lock across a call to WaitNextEvent() under Mac OS, whether the lock is explicit (acquired by calling lock()) or implicit (acquired by an iterator or other API functions). If you do that, all your locks might be automatically unlocked, to allow other processes to access the cache. (In other words, blocking locks can't be used on Mac OS for inter-process synchronization.)

Under Mac OS 7, 8, and 9, the default cache is maintained on a system-wide basis, since all the processes running on the machine have the same privileges anyway (the privileges of the currently logged in user).

For Mac OS X Server, see the UNIX section below.

MS Windows

DLLs should be named KrbCC16.dll and KrbCC32.dll.

The semantics of default ccaches under MS Windows are unspecified so far (will be fixed before final version of the API specification).

UNIX

The semantics of default ccaches on various variant of UNIX are unspecified so far (will be fixed before final version of the API specification).

Types and functions

Basic types

The cc_int32 and cc_uint32 are the signed and unsigned 32-bit integer types. cc_uint32 is unsigned int on platforms where 4 <= sizeof (unsigned int) < sizeof (unsigned long) and long on all other platforms. cc_int32 is int on platforms where 4 <= sizeof (int) < sizeof (long) and long on all other platforms.

typedef cc_int32 cc_time_t;

The cc_time_t type is used to represent a time in seconds. The time must be stored as the number of seconds since midnight GMT on January 1, 1970.

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 function call

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

can be written using a convenience macro as:

cc_type_t opaque_pointer;
result = cc_type_somefunction (opaque_pointer, 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.


cc_context_t

typedef struct {
    cc_int32    (*release) (
                                cc_context_t context);
    cc_int32    (*get_version) (
                                cc_context_t context,
                                cc_int32* version);
    cc_int32    (*get_change_time) (
                                cc_context_t context,
                                cc_time_t* time);
    cc_int32    (*get_default_ccache_name) (
                                cc_context_t context,
                                cc_string_t* name);
    cc_int32    (*open_ccache) (
                                cc_context_t context,
                                const char* name,
                                cc_ccache_t* ccache);
    cc_int32    (*open_default_ccache) (
                                cc_context_t context,
                                cc_ccache_t* ccache);
    cc_int32    (*create_ccache) (
                                cc_context_t context,
                                const char* name,
                                cc_int_32 cred_vers,
                                const char* principal, 
                                cc_ccache_t* ccache);
    cc_int32    (*create_default_ccache) (
                                cc_context_t context,
                                cc_int_32 cred_vers,
                                const char* principal, 
                                cc_ccache_t* ccache);
    cc_int32    (*create_new_ccache) (
                                cc_context_t context,
                                cc_int_32 cred_vers,
                                const char* principal, 
                                cc_ccache_t* ccache);
    cc_int32    (*new_ccache_iterator) (
                                cc_context_t context,
                                cc_ccache_iterator_t* iterator);
    cc_uint32   (*lock) (
                                cc_context_t context,
                                cc_uint32 lock_type,
                                cc_uint32 block);
    cc_uint32   (*unlock) (
                                cc_context_t context);
} cc_context_f;

typedef struct {
    const cc_context_f* functions;
}* cc_context_t;

The cc_context_t type gives the caller access to a ccache collection. Before being able to call any functions in the CCache API, the caller needs to acquire an instance of cc_context_t by calling cc_initialize or cc_context_clone. The cc_context_t type has the following functions:

cc_initialize

cc_int32 cc_initialize (
    cc_context_t*         cc_context,
    cc_int32              api_version,
    cc_int32*             api_supported,
    char**                vendor)

This function performs any initialization required by the API. It must be called before any other function in the API is called.

The application must pass in the maximum version number of the API it supports in the api_version parameter.

If api_supported is non-NULL, then cc_initialize will store the maximum API version number supported by the library implementing the API there.

If the version requested by api_version is not equal to a version supported by the library, ccErrBadAPIVersion will be returned as the error code (along with the version the library does support in api_supported) and cc_initialize() will not allocate any memory.

If vendor is non-NULL, then cc_initialize() will store in *vendor a pointer to a read-only C string which contains a string describing the vendor which implemented the credentials cache API.

Possible return values: ccNoError, ccErrNoMem, ccErrBadAPIVersion, ccErrBadParam

cc_context_get_version

cc_int32 get_version (
    cc_context_t          cc_context,
    cc_int32*             api_version)
cc_int32 cc_context_get_version (
    cc_context_t          cc_context,
    cc_int32*             api_version)

This function returns the API version with which a context was initialized.

This is useful for cases where a context is passed between different pieces of code (an application and a library, for example), and the recipient of a context wants to ascertain that the context was initialized with the appropriate version of the API.

Possible return values: ccNoError, ccErrInvalidContext, ccErrBadParam

cc_context_release

cc_int32 release (
    cc_context_t          cc_context)
cc_int32 cc_context_release (
    cc_context_t          cc_context)

This function releases the context and performs any cleanup required by the API.

Possible return values: ccNoError, ccErrInvalidContext

cc_context_get_change_time

cc_int32 get_change_time (
    cc_context_t          cc_context,
    cc_time_t*            time)
cc_int32 cc_context_get_change_time (
    cc_context_t          cc_context,
    cc_time_t*            time)

This function returns the time of the most recent change for the entire ccache collection. By maintaining a local copy the caller can deduce whether the ccache collection has been modified since the previous call to cc_context_get_change_time() or not.

The time returned by cc_context_get_changed_time() increases whenever:

Possible return values: ccNoError, ccErrInvalidContext, ccBadParam

cc_context_get_default_ccache_name

cc_int32 get_default_ccache_name (
    cc_context_t          cc_context,
    cc_string_t*          name)
cc_int32 cc_context_get_default_ccache_name (
    cc_context_t          cc_context,
    cc_string_t*          name)

This function returns the name of the default ccache. When the default ccache exists, its name is returned. If there are no ccaches in the collection, and thus there is no default ccache, the name that the default ccache should have is returned. The ccache with that name will be used as the default ccache by all processes which initialized Kerberos libraries before the ccache was created.

If there is no default ccache, and the client is creating a new ccache, it should be created with the default name. If there already is a default ccache, and the client wants to create a new ccache (as opposed to reusing an existing ccache), it should be created with any unique name; cc_context_create_new_ccache() can be used to accomplish that more easily.

If the first ccache is created with a name other than the default name, then the processes already running will not notice the credentials stored in the new ccache, which is normally undesirable.

Possible return values: ccNoError, ccErrInvalidContext, ccBadParam, ccErrNoMem

cc_context_open_ccache

cc_int32 open_ccache (
    cc_context_t          cc_context,
    const char*           name,
    cc_ccache_t*          ccache)
cc_int32 cc_context_open_ccache (
    cc_context_t          cc_context,
    const char*           name,
    cc_ccache_t*          ccache)

Opens an already existing ccache identified by its name. It returns a reference to the ccache in *ccache.

The list of all ccache names, principals, and credentials versions may be retrieved by calling cc_context_new_cache_iterator(), cc_ccache_get_name(), cc_ccache_get_principal(), and cc_ccache_get_cred_version().

Possible error codes: ccNoError, ccErrBadName, ccErrInvalidContext, ccErrNoMem, ccErrCCacheNotFound, ccErrBadParam

cc_context_open_default_ccache

cc_int32 open_default_ccache (
    cc_context_t          cc_context,
    cc_ccache_t*          ccache)
cc_int32 cc_context_open_default_ccache (
    cc_context_t          cc_context,
    cc_ccache_t*          ccache)

Opens the default ccache. It returns a reference to the ccache in *ccache.

This function performs the same function as calling cc_context_get_default_ccache_name followed by cc_context_open_ccache, but it performs it atomically.

Possible error codes: ccNoError, ccErrInvalidContext, ccErrNoMem, ccErrCCacheNotFound, ccErrBadParam

cc_context_create_ccache

cc_int32 create_ccache (
    cc_context_t          cc_context,
    const char*           name,
    cc_int32              cred_vers, 
    const char*           principal,
    cc_ccache_t*          ccache)
cc_int32 cc_context_create_ccache (
    cc_context_t          cc_context,
    const char*           name,
    cc_int32              cred_vers, 
    const char*           principal,
    cc_ccache_t*          ccache)

Create a new credentials cache. The ccache is uniquely identified by its name. The principal given is also associated with the ccache and the credentials version specified. A NULL name is not allowed (and ccErrBadName is returned if one is passed in). Only cc_credentials_v4 and cc_credentials_v5 are valid input values for cred_vers. If you want to create a new ccache that will hold both versions of credentials, call cc_context_create_ccache() with one version, and then cc_ccache_set_principal() with the other version.

If you want to create a new ccache (with a unique name), you should use cc_context_create_new_ccache() instead. If you want to create or reinitialize the default cache, you should use cc_context_create_default_ccache().

If name is non-NULL and there is already a ccache named name:

If no ccache named name already exists:

For a new ccache, the name should be any unique string. The name is not intended to be presented to users.

If the created ccache is the first ccache in the collection, it is made the default ccache. Note that normally it is undesirable to create the first ccache with a name different from the default ccache name (as returned by cc_context_get_default_ccache_name()); see the description of cc_context_get_default_ccache_name() for details.

The principal should be a C string containing an unparsed Kerberos principal in the format of the appropriate Kerberos version, i.e. foo.bar@BAZ for Kerberos v4 and foo/bar@BAZ for Kerberos v5.

Possible error codes: ccNoError, ccErrorBadName, ccErrBadParam, ccErrInvalidContext, ccErrNoMem, ccErrBadCredentialsVersion

cc_context_create_default_ccache

cc_int32 create_default_ccache (
    cc_context_t          cc_context,
    cc_int32              cred_vers, 
    const char*           principal,
    cc_ccache_t*          ccache)
cc_int32 cc_context_create_default_ccache (
    cc_context_t          cc_context,
    cc_int32              cred_vers, 
    const char*           principal,
    cc_ccache_t*          ccache)

Create the default credentials cache. The behavior of this function is similar to that of cc_create_ccache(). If there is a default ccache (which is always the case except when there are no ccaches at all in the collection), it is initialized with the specified credentials version and principal, as per cc_create_ccache(); otherwise, a new ccache is created, and its name is the name returned by cc_context_get_default_ccache_name().

Possible error codes: ccNoError, ccErrBadName, ccErrBadParam, ccErrInvalidContext, ccErrNoMem, ccErrBadCredentialsVersion

cc_context_create_new_ccache

cc_int32 create_new_ccache (
    cc_context_t          cc_context,
    cc_int32              cred_vers, 
    const char*           principal,
    cc_ccache_t*          ccache)
cc_int32 cc_context_create_new_ccache (
    cc_context_t          cc_context,
    cc_int32              cred_vers, 
    const char*           principal,
    cc_ccache_t*          ccache)

Create a new unique credentials cache. The behavior of this function is similar to that of cc_create_ccache(). If there are no ccaches, and therefore no default ccache, the new ccache is created with the default ccache name as would be returned by get_default_ccache_name(). If there are some ccaches, and therefore there is a default ccache, the new ccache is created with a new unique name. Clearly, this function never reinitializes a ccache, since it always uses a unique name.

Possible error codes: ccNoError, ccErrBadName, ccErrBadParam, ccErrInvalidContext, ccErrNoMem, ccErrBadCredentialsVersion

cc_context_new_ccache_iterator

cc_int32 new_ccache_iterator (
    cc_context_t          cc_context,
    cc_ccache_iterator_t* iterator)
cc_int32 cc_context_new_ccache_iterator (
    cc_context_t          cc_context,
    cc_ccache_iterator_t* iterator)

Used to allocate memory and initialize iterator. Successive calls to iterator's next() function will return ccaches in the collection.

If changes are made to the collection while an iterator is being used on it, the iterator must return at least the intersection, and at most the union, of the set of ccaches that were present when the iteration began and the set of ccaches that are present when it ends.

Possible error codes: ccNoError, ccBadParam, ccErrNoMem, ccErrInvalidContext

cc_context_lock

cc_int32 lock (
    cc_context_t          context,
    cc_int32              lock_type,
    cc_int32              block)
cc_int32 cc_context_lock (
    cc_context_t          context,
    cc_int32              lock_type,
    cc_int32              block)

Attempts to acquire a lock for the ccache collection. Allowed values for lock_type are:

If block is cc_lock_block, lock() will not return until the lock is acquired. If block is cc_lock_noblock, lock() will return immediately, either acquiring the lock and returning ccNoError, or failing to acquire the lock and returning ccErrContextLocked.

Attempting to acquire a write lock on a context that is already read-locked is allowed; if successful, the context acquires two different locks (a read and a write lock), which is the same as having just a write lock. To release them, cc_lock_release() should be called twice. If unsuccessful, the context still has one read lock.

To avoid having to deal with differences between thread semantics on different platforms, locks are granted per context, rather than per thread or per process. That means that different threads of execution have to acquire separate contexts in order to be able to synchronize with each other.

The lock should be unlocked by using cc_context_unlock().

Possible error codes: ccNoError, ccErrContextLocked, ccErrBadLockType, ccErrInvalidContext, ccErrNoMem

cc_context_unlock

cc_int32 unlock (
    cc_context_t          context);
cc_int32 cc_context_lock (
    cc_context_t          context);

Attempts to release a lock for the ccache collection.

The lock released is the last lock acquired on the context.

Possible error codes: ccNoError, ccErrContextUnlocked, ccErrInvalidContext, ccErrNoMem


cc_ccache_t

typedef struct {
    cc_int32    (*release) (
                                 cc_ccache_t ccache);
    cc_int32    (*destroy) (
                                 cc_ccache_t ccache);
    cc_int32    (*set_default) (
                                 cc_ccache_t ccache);
    cc_int32    (*get_credentials_version) (
                                 cc_ccache_t ccache,
                                 cc_int32* credentials_version);
    cc_int32    (*get_name) (
                                 cc_ccache_t ccache,
                                 cc_string_t* name);
    cc_int32    (*get_principal) (
                                 cc_ccache_t ccache,
                                 cc_int32 credentials_version,
                                 cc_string_t* principal);
    cc_int32    (*set_principal) (
                                 cc_ccache_t ccache,
                                 cc_int32 credentials_version,
                                 const char* principal);
    cc_int32    (*store_credentials) (
                                 cc_ccache_t ccache,
                                 const cc_credentials_union* credentials);
    cc_int32    (*remove_credentials) (
                                 cc_ccache_t ccache,
                                 cc_credentials_t credentials);
    cc_int32    (*new_credentials_iterator) (
                                 cc_ccache_t ccache,
                                 cc_credentials_iterator_t* iterator);
    cc_int32    (*lock) (
                                 cc_ccache_t ccache,
                                 cc_uint32 lock_type,
                                 cc_uint32 block);
    cc_uint32   (*unlock) (
                                 cc_ccache_t context);
    cc_int_32   (*get_last_default_time) (
                                 cc_ccache_t ccache,
                                 cc_time_t* time);
    cc_int_32   (*get_change_time) (
                                 cc_ccache_t ccache,
                                 cc_time_t* time);
    cc_int_32   (*move) (
                                 cc_ccache_t source,
                                 cc_ccache_t destination);
} cc_ccache_f;

typedef struct {
    const cc_ccache_f* functions;
}* cc_ccache_t;

The cc_ccache_t type represents a reference to a ccache. Callers can access a ccache and the credentials stored in it via a cc_ccache_t. A cc_ccache_t can be acquired via cc_context_open_ccache(), cc_context_open_default_ccache(), or cc_ccache_iterator_next(). The functions in a cc_ccache_t are:

cc_ccache_release

cc_int32 release (
    cc_ccache_t           ccache)
cc_int32 cc_ccache_release (
    cc_ccache_t           ccache)

Close the ccache reference. Memory associated with the ccache reference is deallocated; the ccache itself remains unchanged. The reference is invalid after being released.

Possible return values: ccNoError, ccErrInvalidCCache

cc_ccache_destroy

cc_int32 destroy (
    cc_ccache_t           ccache)
cc_int32 cc_ccache_destroy (
    cc_ccache_t           ccache)

Destroy the ccache referenced by the ccache reference. All credentials in the ccache are removed. The associated memory is deallocated. The reference itself is released at the same time, and is therefore invalid after the call to cc_ccache_destroy().

If the default ccache is destroyed, the ccache that was most recently default before it is made the default ccache, unless the default ccache was the only ccache in the collection; in that case, no ccache is made default, as there are no ccaches left.

Possible return values: ccNoError, ccErrInvalidCCache, ccErrCCacheNotFound

cc_ccache_set_default_ccache

cc_int32 set_default (
    cc_ccache_t           ccache)
cc_int32 cc_ccache_set_default (
    cc_ccache_t           ccache)

Makes the ccache referenced the default ccache.

Possible return values: ccNoError, ccErrInvalidCCache, ccErrCCacheNotFound

cc_cache_get_credentials_version

cc_int32 get_credentials_version (
    cc_ccache_t           ccache,
    cc_int32*             credentials_version)
cc_int32 cc_ccache_get_credentials_version (
    cc_ccache_t           ccache,
    cc_int32*             credentials_version)

cc_get_credentials_version() returns one value of the enumerated type cc_credentials_vers. The possible return values are cc_credentials_v4 (if ccache's v4 principal has been set), cc_credentials_v5 (if ccache's v5 principal has been set), or cc_credentials_v4_v5 (if both ccache's v4 and v5 principals have been set). A ccache's principal is set with one of cc_context_create_ccache(), cc_context_create_new_ccache(), cc_create_default_ccache(), or cc_ccache_set_principal().

Possible return values: ccNoError, ccErrInvalidCCache, ccErrBadParam, ccErrCCacheNotFound

cc_ccache_get_name

cc_int32 get_name (
    cc_ccache_t           ccache,
    cc_string_t*          name)
cc_int32 cc_ccache_get_name (
    cc_ccache_t           ccache,
    cc_string_t*          name)

get_name() returns the name of the ccache. The name can be used in cc_context_open_ccache() or cc_context_create_ccache(). The name uniquely identifies a ccache. The returned name should be freed via the cc_string_release() function.

Possible error codes: ccNoError, ccErrNoMem, ccErrBadParam, ccErrInvalidCCache, ccErrCCacheNotFound

cc_ccache_get_principal

cc_int32 get_principal (
    cc_ccache_t           ccache,
    cc_int32              cred_vers,
    cc_string_t*          principal)
cc_int32 cc_ccache_get_principal (
    cc_ccache_t           ccache,
    cc_int32              cred_vers,
    cc_string_t*          principal)

Return the principal for the ccache that was set via cc_context_create_ccache(), cc_context_create_default_ccache(), cc_context_create_new_ccache(), or cc_ccache_set_principal(). The returned principal should be freed via the cc_string_release() function. Principals for v4 and v5 are separate, but should be kept synchronized for each ccache; they can be retrieved by passing cc_credentials_v4 or cc_credentials_v5 in cred_vers. Passing cc_credentials_v4_v5 is an error (ccErrBadCredentialsVersion).

Possible error codes: ccNoError, ccErrNoMem, ccErrBadCredentialsVersion, ccErrBadParam, ccErrInvalidCCache, ccErrCCacheNotFound

cc_ccache_set_principal

cc_int32 set_principal (
    cc_ccache_t           ccache,
    cc_int32              cred_vers,
    const char*           principal)
cc_int32 cc_ccache_set_principal (
    cc_ccache_t           ccache,
    cc_int32              cred_vers,
    const char*           principal)

Set the a principal for ccache. The v4 and v5 principals can be set independently, but they should always be kept equal, up to differences in string representation between v4 and v5. Passing cc_credentials_v4_v5 in cred_vers is an error (ccErrBadCredentialsVersion).

principal points to a nul-terminated string that will be copied into the ccache. This new principal will be returned if you call cc_ccache_get_principal() for this ccache.

Possible error codes: ccNoError, ccErrNoMem, ccErrInvalidCCache, ccErrBadCredentialsVersion, ccErrBadParam, ccErrCCacheNotFound

cc_ccache_store_credentials

cc_int32 store_credentials (
    cc_ccache_t                   ccache,
    const cc_credentials_union*   credentials)
cc_int32 cc_ccache_store_credentials (
    cc_ccache_t                   ccache,
    const cc_credentials_union*   credentials)

Store a copy of credentials in the ccache.

See the description of the credentials types for the meaning of cc_credentials_union fields.

Before credentials of a specific credential type can be stored in a ccache, the corresponding principal version has to be set. I.e., before you can store Kerberos v4 credentials in a ccache, the Kerberos v4 principal has to be set either by cc_context_create_ccache(), cc_context_create_default_ ccache(), cc_context_create_new_ccache(), or cc_set_principal(); likewise for Kerberos v5. Otherwise, ccErrBadCredentialsVersion is returned.

Possible error codes: ccNoError, ccErrInvalidCCache, ccErrInvalidCredentials, ccErrBadCredentialsVersion, ccErrCCacheNotFound

cc_ccache_remove_credentials

cc_int32 remove_credentials (
    cc_ccache_t                   ccache,
    cc_credentials_t              credentials)
cc_int32 cc_ccache_remove_credentials (
    cc_ccache_t                   ccache,
    cc_credentials_t              credentials)

Removes credentials from a ccache. Note that credentials must be previously acquired from the CCache API; only exactly matching credentials will be removed. (This places the burden of determining exactly which credentials to remove on the caller, but ensures there is no ambigity about which credentials will be removed.)

If found, the credentials are removed from the ccache. The credentials parameter is not modified and should be freed by the caller. It is legitimate to call this function while an iterator is traversing the ccache, and the deletion of a credential already returned by cc_credentials_iterator_next() will not disturb sequence of credentials returned by cc_credentials_iterator_next().

Possible error codes: ccNoError, ccErrInvalidCCache, ccErrInvalidCredentials, ccErrCredentialsNotFound, ccErrCCacheNotFound

cc_ccache_new_credentials_iterator

cc_int32 new_credentials_iterator (
    cc_ccache_t           ccache,
    cc_creds_iterator_t*  iterator)
cc_int32 cc_cccache_new_credentials_iterator (
    cc_ccache_t           ccache,
    cc_creds_iterator_t*  iterator)

Allocates memory for iterator and initializes it. Successive calls to cc_credentials_iterator_next() will return credentials from the ccache.

If changes are made to the ccache while an iterator is being used on it, the iterator must return at least the intersection, and at most the union, of the set of credentials that were in the ccache when the iteration began and the set of credentials that are in the ccache when it ends.

Possible error codes: ccNoError, ccErrBadParam, ccErrNoMem, ccErrCCacheNotFound

cc_ccache_lock

cc_int32 lock (
    cc_ccache_t           ccache,
    cc_int32              lock_type,
    cc_uint32             block)
cc_int32 cc_ccache_lock (
    cc_ccache_t           ccache,
    cc_int32              lock_type,
    cc_uint32             block)

Attempts to acquire a lock for the ccache. Allowed values for lock_type are:

If block is cc_lock_block, lock() will not return until the lock is acquired. If block is cc_lock_noblock, lock() will return immediately, either acquiring the lock and returning ccNoError, or failing to acquire the lock and returning ccErrCCacheLocked.

Attempting to acquire a write lock on a ccache that is already read-locked is allowed; if successful, the context acquires two different locks (a read and a write lock), which is the same as having just a write lock. To release them, cc_lock_release() should be called twice. If unsuccessful, the context still has one read lock.

To avoid having to deal with differences between thread semantics on different platforms, locks are granted per context, rather than per thread or per process. That means that different threads of execution have to acquire separate contexts in order to be able to synchronize with each other.

The lock object is returned in the lock parameter, and should be unlocked by using cc_lock_release().

Possible error codes: ccNoError, ccErrCCacheLocked, ccErrBadLockType, ccErrNoMem, ccErrCCacheNotFound

cc_ccache_unlock

cc_int32 unlock (
    cc_ccache_t          ccache);
cc_int32 cc_ccache_lock (
    cc_ccache_t          ccache);

Attempts to release a lock for the ccache.

The lock released is the last lock acquired on the ccache.

Possible error codes: ccNoError, ccErrCCacheUnlocked, ccErrInvalidCCache, ccErrNoMem

cc_ccache_get_change_time

cc_int32 get_change_time (
    cc_ccache_t           ccache,
    cc_time_t*            time)
cc_int32 cc_ccache_get_change_time (
    cc_ccache_t           ccache,
    cc_time_t*            time)

This function returns the time of the most recent change for the ccache. By maintaining a local copy the caller can deduce whether the ccache has been modified since the previous call to cc_ccache_get_change_time() or not.

The time returned by cc_ccache_get_changed_time() increases whenever:

Possible return values: ccNoError, ccErrInvalidCCache, ccBadParam, ccErrCCacheNotFound

cc_ccache_get_last_default_time

cc_int32 get_last_default_time (
    cc_ccache_t           ccache,
    cc_time_t*            time)
cc_int32 cc_ccache_get_last_default_time (
    cc_ccache_t           ccache,
    cc_time_t*            time)

This function returns the last time when the ccache was made the default ccache. This allows clients to sort the ccaches by how recently they were default, which is useful for user listing of ccaches. If the ccache was never default, ccErrNeverDefault is returned.

Possible return values: ccNoError, ccErrInvalidCCache, ccBadParam, ccErrNeverDefault, ccErrCCacheNotFound

cc_ccache_move

cc_int32 move (
    cc_ccache_t           source,
    cc_ccache_t           destination)
cc_int32 cc_ccache_move (
    cc_ccache_t           source,
    cc_ccache_t           destination)

This function takes one ccache (the source) and moves all of its credentials and all of its principals to a different ccache (the destination). All the credentials in the destination are destroyed; both principals of the destination are reset to the corresponding principals of the source ccache.

Assuming that the ccaches are valid, the function cannot fail. This makes it extremely useful for callers that want to atomically and safely replace all the credentials in a ccache -- for example, to renew user's credentials. The new credentials can be placed in a new ccache, and when they are all available, atomically placed into the destination ccache.

All ccache handles for the source ccache, including the one passed to cc_ccache_move(), become invalid, just as cc_ccache_destroy had been called.

Any locks held on the source ccache are transferred to the destination ccache; this is okay because those locks must be held by the caller.

Possible return values: ccNoError, ccErrInvalidCCache, ccErrCCacheNotFound


cc_ccache_iterator_t

typedef struct {
    cc_int32    (*release) (
                                 cc_ccache_iterator_t iter);
    cc_int32    (*clone) (
                                 cc_ccache_iterator_t iter,
                                 cc_ccache_iterator_t* new_iter);
    cc_int32    (*next) (
                                 cc_ccache_iterator_t iter,
                                 cc_ccache_t* ccache);
} cc_ccache_iterator_f;

typedef struct {
    const cc_ccache_iterator_f* functions;
}* cc_ccache_iterator_t;

The cc_ccache_iterator_t type represents an iterator that iterates over a set of ccaches and returns them in all in some order. A new instance of this type can be obtained by calling cc_context_new_ccache_iterator(). The type has the following functions:

cc_ccache_iterator_release

cc_int32 release (
    cc_ccache_iterator_t  iterator)
cc_int32 cc_ccache_iterator_release (
    cc_ccache_iterator_t  iterator)

Deallocates the memory used by a ccache iterator.

Possible error codes: ccNoError, ccErrInvalidCCacheIterator

cc_ccache_iterator_clone

cc_int32 clone (
    cc_ccache_iterator_t  iter,
    cc_ccache_iterator_t* new_iter)
cc_int32 cc_ccache_iterator_clone (
    cc_ccache_iterator_t  iter,
    cc_ccache_iterator_t* new_iter)

Creates a new iterator by cloning an existing one.

Since the original iterator acquires a lock on the entire collection when it's created, the newly created iterator will always iterate over exactly the same set of ccaches. The newly created iterator will not return the ccaches that the original iterator had already returned, unless cc_ccache_iterator_reset() is called on the new iterator.

Possible error codes: ccNoError, ccErrNoMem, ccErrInvalidCCacheIterator

cc_ccache_iterator_next

cc_int32 next (
    cc_ccache_iterator_t  iterator,
    cc_ccache_t*          ccache)
cc_int32 cc_ccache_iterator_next (
    cc_ccache_iterator_t  iterator,
    cc_ccache_t*          ccache)

Used to sequentially open every ccache in the iteration set.

ccache must be a pointer to a cc_ccache_t. The ccache returned may be used to get information about the ccache by calling cc_ccache_get_name(), cc_ccache_get_cred_version(), and cc_ccache_get_principal(). CCaches returned must be released between or after calls to cc_ccache_iterator_next().

When the last ccache in the sequence is returned, the return code from next() will be ccIteratorEnd.

Possible error codes: ccNoError, ccIteratorEnd, ccErrBadParam, ccErrNoMem, ccErrInvalidCCacheIterator, ccErrCCacheNotFound


cc_credentials_iterator_t

typedef struct {
    void        (*release) (
                                 cc_credentials_iterator_t iterator);
    cc_int32    (*clone) (
                                 cc_credentials_iterator_t iter,
                                 cc_credentials_iterator_t* new_iter);
    cc_int32    (*next) (
                                 cc_credentials_iterator_t iterator,
                                 cc_credentials_t* ccache);
} cc_credentials_iterator_f;

typedef struct {
    const cc_credentials_iterator_f* functions;
}* cc_credentials_iterator_t;

The cc_credentials_iterator_t type represents an iterator that iterates over a set of credentials. A new instance of this type can be obtained by calling cc_ccache_new_credentials_iterator(). The type has the following functions:

cc_ccache_credentials_iterator_release

cc_int32 release (
    cc_credentials_iterator_t  iterator)
cc_int32 cc_ccache_iterator_release (
    cc_credentials_iterator_t  iterator)

Deallocates memory used by a credentials iterator.

Possible error codes: ccNoErr, ccErrInvalidCredentialsIterator

cc_credentials_iterator_clone

cc_int32 clone (
    cc_credentials_iterator_t  iter,
    cc_credentials_iterator_t* new_iter)
cc_int32 cc_credentials_iterator_clone (
    cc_credentials_iterator_t  iter,
    cc_credentials_iterator_t* new_iter)

Creates a new iterator by cloning an existing one.

Since the original iterator acquires a lock on the entire ccache when it's created, the newly created iterator will always iterate over exactly the same set of credentials. The newly created iterator will not return the credentials that the original iterator had already returned, unless cc_credentials_iterator_reset() is called on the new iterator.

Possible error codes: ccNoError, ccErrNoMem, ccErrInvalidCredentialsIterator

cc_credentials_iterator_next

cc_int32 next (
    cc_credentials_iterator_t  iterator,
    cc_credentials_t*     credentials)
cc_int32 cc_credentials_iterator_next (
    cc_credentials_iterator_t  iterator,
    cc_credentials_t*     credentials)

cc_ccache_creds_iterator_t -> next() is used to sequentially access a set of credentials. Both Kerberos v4 and v5 credentials are returned by the iterator; callers interested in only one kind need to check the version of the returned credentials and ignore the ones they don't care about.

The credentials are returned in a cc_credentials_t pointed to by credentials.

When the last credential in the sequence is returned, the return code from next() will be ccIteratorEnd.

Possible error codes: ccNoErr, ccIteratorEnd, ccErrBadParam, ccErrNoMem, ccErrInvalidCredentialsIterator


cc_credentials_t

typedef struct {
    cc_int32                  version;
    union {
        cc_credentials_v4_t*  credentials_v4;
        cc_credentials_v5_t*  credentials_v5;
    } credentials;
} cc_credentials_union;

typedef struct {
    cc_int32                  (*release) (
                                 cc_credentials_t credentials);
} cc_credentials_f;

typedef struct {
    const cc_credentials_union* data;
    const cc_credentials_f* functions;
}* cc_credentials_t;

The cc_credentials_t type is used to store a single set of credentials for either Kerberos v4 or Kerberos v5. In addition to its only function, release(), it contains a pointer to a cc_credentials_union structure. A cc_credentials_union structure contains an integer of the enumerator type cc_credentials_version, which is either cc_credentials_v4 or cc_credentials_v5, and a pointer union, which contains either a cc_credentials_v4_t pointer or a cc_credentials_v5_t pointer, depending on the value in version.

Variables of the type cc_credentials_t are allocated by the CCache implementation, and should be released with their release() function. API functions which receive credentials structures from the caller always accept cc_credentials_union, which is allocated by the caller, and accordingly disposed by the caller.

If a cc_credentials_t variable is used to store Kerberos v4 credentials, then credentials.credentials_v4 points to a v4 credentials structure:

enum {
  cc_v4_ticket_size = 1250
  cc_v4_name_size = 40,
  cc_v4_instance_size = 40,
  cc_v4_realm_size = 40,
  cc_v4_key_size = 8
};

enum cc_string_to_key_type {
   cc_v4_stk_unknown = 0,
   cc_v4_stk_afs = 1,
   cc_v4_stk_des = 2,
   cc_v4_stk_columbia_special = 3
};
 
typedef struct {
    unsigned char              version;
    char                       principal[cc_v4_name_size];
    char                       principal_instance[cc_v4_instance_size];
    char                       service[cc_v4_name_size];
    char                       service_instance[cc_v4_instance_size];
    char                       realm[cc_v4_realm_size];
    unsigned char              session_key[cc_v4_key_size];
    cc_int32                   kvno;
    cc_int32                   string_to_key;
    cc_time_t                  issue_date;
    cc_int32                   lifetime;
    cc_uint32                  address;
    cc_int32                   ticket_size;
    unsigned char              ticket[cc_v4_ticket_size];
} cc_cred_v4;

The realm, principal, principal_instance, service, and service_instance fields should contain (properly quoted) string representation of the realm, the principal, and the instance of the ticket and the service it was issued for. The session_key field should contain the session key for the ticket. The kvno field should contain the key version number of the ticket. The string_to_key field should contain a value of the enumerated type cc_string_to_key_type. The issue_date field should contain the issue time of the ticket. The lifetime field should contain the lifetime of the ticket in units of 5 minutes. The address field should contain the IP address that the ticket was issued for as an unsigned 32-bit integer. The ticket field should contain the ticket itself, and its size should be in the ticket_size field.

Otherwise, cc_credentials_t is used to store Kerberos v5 credentials, and then credentials.credentials_v5 points to a a v5 credentials structure. In a v5 credentials structure, cc_data structures are used to store tagged variable-length binary data. Specifically, for cc_credentials_v5.ticket and cc_credentials_v5.second_ticket, the cc_data.type field must be zero. For the cc_credentials_v5.addresses, cc_credentials_v5.authdata, and cc_credentials_v5.keyblock, the cc_data.type field should be the address type, authorization data type, and encryption type, as defined by the Kerberos v5 protocol definition.

typedef struct {
    cc_uint32            type;
    cc_uint32            length;
    unsigned char*      data;
} cc_data;
 
typedef struct {
    char*       client;
    char*       server;
    cc_data     keyblock;
    cc_time_t   authtime;
    cc_time_t   starttime;
    cc_time_t   endtime;
    cc_time_t   renew_till;
    cc_uint32   is_skey;
    cc_uint32   ticket_flags;
    cc_data**   addresses;
    cc_data     ticket;
    cc_data     second_ticket;
    cc_data**   authdata;
} cc_cred_v5;

The client and the server field should contain the client's and the server's principal identifier, respectively, in properly quoted string representation. The keyblock fiels should contain the session encryption key info. The authtime field should contain the time when the ticket was issued. The starttime and the endtime fields should contain the beginning and the end of the time period during which the credentials are valid. The renew_till field should contain the maximal time until which the credentials can be renewed. The is_skey field should be set to 1 if the ticket is encrypted in another ticket's key, or 0 otherwise. The ticket_flags field should contain the ticket flags of the ticket, as presented by the Kerberos v5 API. The addresses field should contain the list of network addresses of hosts that are allowed to authenticate using this ticket. The ticket field should contain the ticket data, and the second_ticket field should contain the data for the second ticket, if there is one (for example, if the ticket is encrypted in second ticket's key). The authdata field should contain the autorization data.

cc_credentials_release

cc_int32 release (
    cc_credentials_t  credentials)
cc_int32 cc_credentials_release (
    cc_credentials_t  credentials)

This function frees all storage associated with a variable of cc_credentials_t.

Possible error codes: ccNoError, ccErrInvalidCredentials


cc_string_t

typedef struct {
    cc_int32                  (*release) (
                                 cc_string_t string);
} cc_string_f;

typedef struct {
    const char* data;
    const cc_string_f* functions;
}* cc_string_t;

The cc_string_t represents a C string returned by the API. It has a pointer to the string data and a release() function. This type is used for both principal names and ccache names returned by the API. Principal names may contain UTF-8 encoded strings for internationalization purposes.

cc_string_release

cc_int32 release (
    cc_string_t  string)
cc_int32 cc_string_release (
    cc_string_t  string)

This function frees the string returned by an API function.

Possible error codes: ccNoError, ccErrInvalidString


Revision History and Notes

Original version (Draft Version 1)

1/27/96 by Theodore Ts'o

Revision 2 (Draft Version 1)

970628 by Steve Rothwell for the V4Cache Team (Paul Hill, Jenny Khuon, Jean Luker, Dave Detlefs, Allan Bjorklund, & Steve Rothwell)

Revision 3 (Draft Version 1)

970725 by Steve Rothwell after initial implementation and alpha release. The term "credentials cache" was previously used to mean both "the main cache" and individual "named cache"s within the main cache. I have started using the term "NC" for "named cache" to make the distinction clearer and to reduce the overloading of the word "cache".

Changes made for revision 3 of this API:

Revision 4 (Draft Version 1)

970908 by Steve Rothwell to incorporate changes initiated by Ted Tso. Further changes are expected in the comments for cc_create() and cc_get_change_time().

Revision 4a (Final Version 1)

980603 by Scott McGuire to correct typographical errors, HTML errors, and minor clarifications. Final API Version 1 spec.

Revision 5 (Draft Version 2)

990201 by Scott McGuire.

Revision 5a (Final Version 2)

990723 by Scott McGuire.


Questions or comments? Send mail to macdev@mit.edu
Last updated on $Date: 2003/11/19 20:42:28 $
Last modified by $Author: smcguire $