Kerberos Login Principal Tranlation Plugin API

| # Macintosh Development

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

| KerberosLogin Principal Translation Plugin API

This documentation applies to Mac OS X 10.2 and later.

## Purpose of principal translation plugins

A principal translation plugin provides realm-specific principal translation. For example, if a realm allows the users to type their full names into the Kerberos Login dialog and looks up their Kerberos principals in an outside database (such as the Dartmouth Name Directory), then the administrators of that realm can provide a plugin to perform the translation.

Principal translation plugins are invoked by the Kerberos Login API whenever a string needs to be converted to a Kerberos principal. For example, the translation is applied to the name, instance, and realm entered by the user into the Kerberos Login dialog.

## Configuration of principal translation plugins

In order to activate a principal translation plugin for a realm, the realm stanza in the `edu.mit.Kerberos` file has to include a `principal_translation` line:

    REALM.NOWHERE.EDU = {
        ...
        principal_translation = "PluginName"
    }

On that line, `PluginName`, should be a unique string describing the plugin. The string must not be longer than 127 characters, and must end in "`.principalTranslator`".

The plugin file itself has to be located in the directory `/Library/Kerberos Plug-Ins/` (note space and hyphen) - you may have to create this directory if it doesn't already exist.

## Format of principal translation plugins

A principal translation plugin must be a Mach-O bundle with a name ending in "`.principalTranslator`".

The plugin must export three functions, which are detailed in the next section.

The plugin can contain any other code, data, or resources, but be mindful that it can be executed by arbitrary applications, and therefore should be careful not to affect the application's resources or resource handling.

## Functions exported by principal translation plugin

All three of these functions must be exported by every principal translation plugin. All functions use C linkage and standard Mach-O calling conventions.

The functions and related type declarations are specified in the `/System/Library/Frameworks/Kerberos.framework/Headers/KLPrincipalTranslation.h` header file.

### KerberosLoginPrincipalTranslation_InitializePlugin

    OSErr KerberosLoginPrincipalTranslation_InitializePlugin (
        KLPT_APIVersion          inAPIVersion);

This function is called by the Kerberos Login API when the plugin is loaded. The function must return `noErr` only if the plugin understands the API version passed in `inAPIVersion`; otherwise, it should return `paramErr`.

If this function returns anything but `noErr`, the other functions will not be called.

For example, a plugin which only understands the version 1 of the API (which is the current version), would do this:

    KLStatus KerberosLoginPrincipalTranslation_InitializePlugin (
        KLPT_APIVersion      inAPIVersion)
    {
        if (inAPIVersion == kKLPT_APIVersion1) {
            return noErr;
        } else {
            return paramErr;
        }
    }

### KerberosLoginPrincipalTranslation_TranslatePrincipal

    KLStatus KerberosLoginPrincipalTranslation_TranslatePrincipal (
    	const char*     inName,
    	const char*     inInstance,
    	const char*     inRealm,
    	const char**    outName,
    	const char**    outInstance,
    	const char**    outRealm,
    	KLBoolean*      outChanged);

This function performs principal translation. On input, `inName`, `inInstance`, and `inRealm` point to the components of the untranslated principal as C strings.

The function translates the principal components, and returns the translated components as newly allocated C strings in `*outName`, `*outInstance`, `*outRealm`. The memory for the translated components is allocated by this function.

The translation function must satisfy the following two constraints:

- The function must return a valid Kerberos principal triplet
- When called on a valid Kerberos principal, the function must return the principal unchanged

In other words, if the function is called to translate a principal, it must return a valid Kerberos principal. If it is called again, this time with the principal it returned, it must return it again, unchanged.

This property is also known as idempotency. When you are debugging your plugin, you should test it very carefully to make sure it behaves this way.

If the principal translation is successful, the function sets `*outChanged` to true, and returns `noErr`.

In case no translation is necessary, the function may return false in `*outChanged`, in which case the values returned in `*outName`, `*outInstance`, `*outRealm` will be ignored by the Kerberos Login library. The function is not obligated to take this shortcut -- it can also just copy the old components into new memory. It must not, however, just return pointers to the input components in the output components without allocating memory for them.

If the functions fails to perform the translation, it should return an appropriate error code and leave all outputs unchanged. For more information on error handling in principal translation plugins and reporting error messages to the user, see the error handling section below.

If an error occurs, the function should clean up after itself and leave all output components unchanged.

For example, a plugin which removes trailing letters 'x' from a principal would work like this:

    OSErr KerberosLoginPrincipalTranslation_TranslatePrincipal (
        const char*     inName,
        const char*     inInstance,
        const char*     inRealm,
        const char**    outName,
        const char**    outInstance,
        const char**    outRealm,
        KLBoolean*        outChanged)
    {
        *outChanged = false;

        OSErr err = noErr;

        UInt32  nameLength = strlen (inName);
        UInt32  instanceLength = strlen (inInstance);
        UInt32  realmLength = strlen (inRealm);

        char*   newName = NewPtr (nameLength + 1);
        char*   newInstance = NewPtr (instanceLength + 1);
        char*   newRealm = NewPtr (realmLength + 1);

        if ((newName == nil) || (newInstance == nil) || (newRealm == nil)) {
            err = memFullErr;
        }

        if (err == noErr) {
            strcpy (newName, inName);
            strcpy (newInstance, inInstance);
            strcpy (newRealm, inRealm);

            // Remove trailing 'x'
            for (UInt32 i = 0; i < nameLength; i++) {
            	if (newName [nameLength - i - 1] == 'x') {
            		newName [nameLength - i - 1] = '\0';
            	} else {
            		break;
            	}
            }

            *outName = newName;
            *outInstance = inInstance;
            *outRealm = inRealm;

            *outChanged = true;
        } else {
            if (newName != nil) {
                DisposePtr (newName);
            }

            if (newInstance != nil) {
                DisposePtr (newInstance);
            }

            if (newRealm != nil) {
                DisposePtr (newRealm);
            }
        }

        return err;
    }

### KerberosLoginPrincipalTranslation_ReleasePrincipal

    void KerberosLoginPrincipalTranslation_ReleasePrincipal (
    	const char*     inName,
    	const char*     inPrincipal,
    	const char*     inRealm);

This function is called by the Kerberos Login API to release the memory allocated by the principal translation function. It is only called if the principal translation function returned `noErr`.

For example, the plugin example above, which allocated all three components with `NewPtr()` would release them like this:

    void KerberosLoginPrincipalTranslation_ReleasePrincipal (
        char*   inName,
        char*   inInstance,
        char*   inRealm)
    {
        DisposePtr (inName);
        DisposePtr (inInstance);
        DisposePtr (inRealm);
    }

## Error handling in principal translation plugins

`KerberosLoginPrincipalTranslation_TranslatePrincipal()` is allowed to return private error codes. This error code will be propagated to the caller of the Kerberos Login API, which in turn calls `KLGetErrorString()` to translate the error into a message for the user. The private error codes must not conflict with any existing Mac OS error codes.

In order to allow the Kerberos Login API to translate the plugin's error codes into user messages, the plugin should register its errors with the KerberosErrors API. After that, errors returned by the plugin will be mapped to the strings in the plugin's error table.

Questions or comments? Send mail to macdev@mit.edu
Last updated on $Date: 2003/11/18 21:12:24 $
Last modified by $Author: smcguire $