From 0e5252ec1778d3421122f2ee95c88e8b1b77e383 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Thu, 8 Mar 2012 22:38:58 +0000 Subject: [PATCH] Add pluggable interface RST documentation Create a new top-level section for plugin module developers. Document the general conventions for pluggable interfaces and an overview of each existing interface (except for GSSAPI mechanisms). Since we're not currently generating doxygen markup for plugin interface headers, refer to header files for detail-level documentation for now. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25759 dc483132-0cff-0310-8789-dd5450dbe970 --- doc/rst_source/index.rst | 1 + doc/rst_source/krb_plugindev/ccselect.rst | 26 ++++++ doc/rst_source/krb_plugindev/clpreauth.rst | 53 +++++++++++ doc/rst_source/krb_plugindev/general.rst | 98 +++++++++++++++++++++ doc/rst_source/krb_plugindev/index.rst | 32 +++++++ doc/rst_source/krb_plugindev/internal.rst | 32 +++++++ doc/rst_source/krb_plugindev/kadm5_hook.rst | 24 +++++ doc/rst_source/krb_plugindev/kdcpreauth.rst | 61 +++++++++++++ doc/rst_source/krb_plugindev/locate.rst | 32 +++++++ doc/rst_source/krb_plugindev/profile.rst | 86 ++++++++++++++++++ doc/rst_source/krb_plugindev/pwqual.rst | 23 +++++ 11 files changed, 468 insertions(+) create mode 100644 doc/rst_source/krb_plugindev/ccselect.rst create mode 100644 doc/rst_source/krb_plugindev/clpreauth.rst create mode 100644 doc/rst_source/krb_plugindev/general.rst create mode 100644 doc/rst_source/krb_plugindev/index.rst create mode 100644 doc/rst_source/krb_plugindev/internal.rst create mode 100644 doc/rst_source/krb_plugindev/kadm5_hook.rst create mode 100644 doc/rst_source/krb_plugindev/kdcpreauth.rst create mode 100644 doc/rst_source/krb_plugindev/locate.rst create mode 100644 doc/rst_source/krb_plugindev/profile.rst create mode 100644 doc/rst_source/krb_plugindev/pwqual.rst diff --git a/doc/rst_source/index.rst b/doc/rst_source/index.rst index 9956b2ce0..4b07b1ff2 100644 --- a/doc/rst_source/index.rst +++ b/doc/rst_source/index.rst @@ -11,6 +11,7 @@ Contents krb_appldev/index.rst krb_admins/index.rst krb_users/index.rst + krb_plugindev/index.rst krb_build/index.rst .. toctree:: diff --git a/doc/rst_source/krb_plugindev/ccselect.rst b/doc/rst_source/krb_plugindev/ccselect.rst new file mode 100644 index 000000000..00133d944 --- /dev/null +++ b/doc/rst_source/krb_plugindev/ccselect.rst @@ -0,0 +1,26 @@ +Credential cache selection interface (ccselect) +=============================================== + +The ccselect interface allows modules to control how credential caches +are chosen when a GSSAPI client contacts a service. For a detailed +description of the ccselect interface, see the header file +````. + +The primary ccselect method is **choose**, which accepts a server +principal as input and returns a ccache and/or principal name as +output. A module can use the krb5_cccol APIs to iterate over the +cache collection in order to find an appropriate ccache to use. + +.. TODO: add reference to the admin guide for ccaches and cache + collections when we have appropriate sections. + +A module can create and destroy per-library-context state objects by +implementing the **init** and **fini** methods. State objects have +the type krb5_ccselect_moddata, which is an abstract pointer type. A +module should typically cast this to an internal type for the state +object. + +A module can have one of two priorities, "authoritative" or +"heuristic". Results from authoritative modules, if any are +available, will take priority over results from heuristic modules. A +module communicates its priority as a result of the **init** method. diff --git a/doc/rst_source/krb_plugindev/clpreauth.rst b/doc/rst_source/krb_plugindev/clpreauth.rst new file mode 100644 index 000000000..68e56aa5f --- /dev/null +++ b/doc/rst_source/krb_plugindev/clpreauth.rst @@ -0,0 +1,53 @@ +Client preauthentication interface (clpreauth) +============================================== + +During an initial ticket request, a KDC may ask a client to prove its +knowledge of the password before issuing an encrypted ticket, or to +use credentials other than a password. This process is called +preauthentication, and is described in :rfc:`4120` and :rfc:`6113`. +The clpreauth interface allows the addition of client support for +preauthentication mechanisms beyond those included in the core MIT +krb5 code base. For a detailed description of the clpreauth +interface, see the header file ````. + +A clpreauth module is generally responsible for: + +* Supplying a list of preauth type numbers used by the module in the + **pa_type_list** field of the vtable structure. + +* Indicating what kind of preauthentication mechanism it implements, + with the **flags** method. In the most common case, this method + just returns ``PA_REAL``, indicating that it implements a normal + preauthentication type. + +* Examining the padata information included in the preauth_required + error and producing padata values for the next AS request. This is + done with the **process** method. + +* Examining the padata information included in a successful ticket + reply, possibly verifying the KDC identity and computing a reply + key. This is also done with the **process** method. + +* For preauthentication types which support it, recovering from errors + by examining the error data from the KDC and producing a padata + value for another AS request. This is done with the **tryagain** + method. + +* Receiving option information (supplied by ``kinit -X`` or by an + application), with the **gic_opts** method. + +A clpreauth module can create and destroy per-library-context and +per-request state objects by implementing the **init**, **fini**, +**request_init**, and **request_fini** methods. Per-context state +objects have the type krb5_clpreauth_moddata, and per-request state +objects have the type krb5_clpreauth_modreq. These are abstract +pointer types; a module should typically cast these to internal +types for the state objects. + +The **process** and **tryagain** methods have access to a callback +function and handle (called a "rock") which can be used to get +additional information about the current request, including the +expected enctype of the AS reply, the FAST armor key, and the client +long-term key (prompting for the user password if necessary). A +callback can also be used to replace the AS reply key if the +preauthentication mechanism computes one. diff --git a/doc/rst_source/krb_plugindev/general.rst b/doc/rst_source/krb_plugindev/general.rst new file mode 100644 index 000000000..dff680762 --- /dev/null +++ b/doc/rst_source/krb_plugindev/general.rst @@ -0,0 +1,98 @@ +General plugin concepts +======================= + +A krb5 dynamic plugin module is a Unix shared object or Windows DLL. +Typically, the source code for a dynamic plugin module should live in +its own project with a build system using automake_ and libtool_, or +tools with similar functionality. + +A plugin module must define a specific symbol name, which depends on +the pluggable interface and module name. For most pluggable +interfaces, the exported symbol is a function named +``INTERFACE_MODULE_initvt``, where *INTERFACE* is the name of the +pluggable interface and *MODULE* is the name of the module. For these +interfaces, it is possible for one shared object or DLL to implement +multiple plugin modules, either for the same pluggable interface or +for different ones. For example, a shared object could implement both +KDC and client preauthentication mechanisms, by exporting functions +named ``kdcpreauth_mymech_initvt`` and ``clpreauth_mymech_initvt``. + +.. note: The profile, locate, and GSSAPI mechglue pluggable interfaces + follow different conventions. See the documentation for + those interfaces for details. The remainder of this section + applies to pluggable interfaces which use the standard + conventions. + +A plugin module implementation should include the header file +````, where *INTERFACE* is the name of the +pluggable interface. For instance, a ccselect plugin module +implementation should use ``#include ``. + +.. note: clpreauth and kdcpreauth module implementations should + include . + +initvt functions have the following prototype:: + + krb5_error_code interface_modname_initvt(krb5_context context, + int maj_ver, int min_ver, + krb5_plugin_vtable vtable); + +and should do the following: + +1. Check that the supplied maj_ver argument is supported by the + module. If it is not supported, the function should return + KRB5_PLUGIN_VER_NOTSUPP. + +2. Cast the supplied vtable pointer to the structure type + corresponding to the major version, as documented in the pluggable + interface header file. + +3. Fill in the structure fields with pointers to method functions and + static data, stopping at the field indicated by the supplied minor + version. Fields for unimplemented optional methods can be left + alone; it is not necessary to initialize them to NULL. + +In most cases, the context argument will not be used. The initvt +function should not allocate memory; think of it as a glorified +structure initializer. Each pluggable interface defines methods for +allocating and freeing module state if doing so is necessary for the +interface. + +Pluggable interfaces typically include a **name** field in the vtable +structure, which should be filled in with a pointer to a string +literal containing the module name. + +Here is an example of what an initvt function might look like for a +fictional pluggable interface named fences, for a module named +"wicker":: + + krb5_error_code + fences_wicker_initvt(krb5_context context, int maj_ver, + int min_ver, krb5_plugin_vtable vtable) + { + krb5_ccselect_vtable vt; + + if (maj_ver == 1) { + krb5_fences_vtable vt = (krb5_fences_vtable)vtable; + vt->name = "wicker"; + vt->slats = wicker_slats; + vt->braces = wicker_braces; + } else if (maj_ver == 2) { + krb5_fences_vtable_v2 vt = (krb5_fences_vtable_v2)vtable; + vt->name = "wicker"; + vt->material = wicker_material; + vt->construction = wicker_construction; + if (min_ver < 2) + return 0; + vt->footing = wicker_footing; + if (min_ver < 3) + return 0; + vt->appearance = wicker_appearance; + } else { + return KRB5_PLUGIN_VER_NOTSUPP; + } + return 0; + } + +.. _automake: http://www.gnu.org/software/automake/ +.. _libtool: http://www.gnu.org/software/libtool/ diff --git a/doc/rst_source/krb_plugindev/index.rst b/doc/rst_source/krb_plugindev/index.rst new file mode 100644 index 000000000..640b67522 --- /dev/null +++ b/doc/rst_source/krb_plugindev/index.rst @@ -0,0 +1,32 @@ +For plugin module developers +============================ + +Kerberos plugin modules allow increased control over MIT krb5 library +and server behavior. This guide describes how to create dynamic +plugin modules and the currently available pluggable interfaces. + +See :ref:`plugins` for information on how to register dynamic plugin +modules and how to enable and disable plugin modules via +:ref:`krb5.conf(5)`. + +.. TODO: update the above reference when we have a free-form section + in the admin guide about plugin configuration + + +Contents +-------- + +.. toctree:: + :maxdepth: 2 + + general.rst + clpreauth.rst + kdcpreauth.rst + ccselect.rst + pwqual.rst + kadm5_hook.rst + locate.rst + profile.rst + internal.rst + +.. TODO: GSSAPI mechanism plugins diff --git a/doc/rst_source/krb_plugindev/internal.rst b/doc/rst_source/krb_plugindev/internal.rst new file mode 100644 index 000000000..99e30bb79 --- /dev/null +++ b/doc/rst_source/krb_plugindev/internal.rst @@ -0,0 +1,32 @@ +Internal pluggable interfaces +============================= + +Following are brief discussions of pluggable interfaces which have not +yet been made public. These interfaces are functional, but the +interfaces are likely to change in incompatible ways from release to +release. In some cases, it may be necessary to copy header files from +the krb5 source tree to use an internal interface. Use these with +care, and expect to need to update your modules for each new release +of MIT krb5. + + +Kerberos database interface (KDB) +--------------------------------- + +A KDB module implements a database back end for KDC principal and +policy information, and can also control many aspects of KDC behavior. +For a full description of the interface, see the header file +````. + +The KDB pluggable interface is often referred to as the DAL (Database +Access Layer). + + +Authorization data interface (authdata) +--------------------------------------- + +The authdata interface allows a module to provide (from the KDC) or +consume (in application servers) authorization data of types beyond +those handled by the core MIT krb5 code base. The interface is +defined in the header file ````, which is not +installed by the build. diff --git a/doc/rst_source/krb_plugindev/kadm5_hook.rst b/doc/rst_source/krb_plugindev/kadm5_hook.rst new file mode 100644 index 000000000..067eae639 --- /dev/null +++ b/doc/rst_source/krb_plugindev/kadm5_hook.rst @@ -0,0 +1,24 @@ +KADM5 hook interface (kadm5_hook) +================================= + +The kadm5_hook interface allows modules to perform actions when +changes are made to the Kerberos database through :ref:`kadmin(8)`. +For a detailed description of the kadm5_hook interface, see the header +file ````. + +The kadm5_hook interface has four primary methods: **chpass**, +**create**, **modify**, and **remove**. Each of these methods is +called twice when the corresponding administrative action takes place, +once before the action is committed and once afterwards. A module can +prevent the action from taking place by returning an error code during +the pre-commit stage. + +A module can create and destroy per-process state objects by +implementing the **init** and **fini** methods. State objects have +the type kadm5_hook_modinfo, which is an abstract pointer type. A +module should typically cast this to an internal type for the state +object. + +Because the kadm5_hook interface is tied closely to the kadmin +interface (which is explicitly unstable), it may not remain as stable +across versions as other public pluggable interfaces. diff --git a/doc/rst_source/krb_plugindev/kdcpreauth.rst b/doc/rst_source/krb_plugindev/kdcpreauth.rst new file mode 100644 index 000000000..e6ba9e531 --- /dev/null +++ b/doc/rst_source/krb_plugindev/kdcpreauth.rst @@ -0,0 +1,61 @@ +KDC preauthentication interface (kdcpreauth) +============================================ + +The kdcpreauth interface allows the addition of KDC support for +preauthentication mechanisms beyond those included in the core MIT +krb5 code base. For a detailed description of the kdcpreauth +interface, see the header file ````. + +A kdcpreauth module is generally responsible for: + +* Supplying a list of preauth type numbers used by the module in the + **pa_type_list** field of the vtable structure. + +* Indicating what kind of preauthentication mechanism it implements, + with the **flags** method. If the mechanism computes a new reply + key, it must specify the ``PA_REPLACES_KEY`` flag. If the mechanism + is generally only used with hardware tokens, the ``PA_HARDWARE`` + flag allows the mechanism to work with principals which have the + **requires_hwauth** flag set. + +* Producing a padata value to be sent with a preauth_required error, + with the **edata** method. + +* Examining a padata value sent by a client and verifying that it + proves knowledge of the appropriate client credential information. + This is done with the **verify** method. + +* Producing a padata response value for the client, and possibly + computing a reply key. This is done with the **return_padata** + method. + +A module can create and destroy per-KDC state objects by implementing +the **init** and **fini** methods. Per-KDC state objects have the +type krb5_kdcpreauth_moddata, which is an abstract pointer types. A +module should typically cast this to an internal type for the state +object. + +A module can create a per-request state object by returning one in the +**verify** method, receiving it in the **return_padata** method, and +destroying it in the **free_modreq** method. Note that these state +objects only apply to the processing of a single AS request packet, +not to an entire authentication exchange (since an authentication +exchange may remain unfinished by the client or may involve multiple +different KDC hosts). Per-request state objects have the type +krb5_kdcpreauth_modreq, which is an abstract pointer type. + +The **edata**, **verify**, and **return_padata** methods have access +to a callback function and handle (called a "rock") which can be used +to get additional information about the current request, including the +maximum allowable clock skew, the client's long-term keys, the +DER-encoded request body, the FAST armor key, string attributes on the +client's database entry, and the client's database entry itself. + +The **edata** and **verify** methods can be implemented +asynchronously. Because of this, they do not return values directly +to the caller, but must instead invoke responder functions with their +results. A synchronous implementation can invoke the responder +function immediately. An asynchronous implementation can use the +callback to get an event context for use with the libverto_ API. + +.. _libverto: https://fedorahosted.org/libverto/ diff --git a/doc/rst_source/krb_plugindev/locate.rst b/doc/rst_source/krb_plugindev/locate.rst new file mode 100644 index 000000000..3e8357af0 --- /dev/null +++ b/doc/rst_source/krb_plugindev/locate.rst @@ -0,0 +1,32 @@ +Server location interface (locate) +================================== + +The locate interface allows modules to control how KDCs and similar +services are located by clients. For a detailed description of the +ccselect interface, see the header file ````. + +.. note: The locate interface does not follow the normal conventions + for MIT krb5 pluggable interfaces, because it was made public + before those conventions were established. + +A locate module exports a structure object of type +krb5plugin_service_locate_ftable, with the name ``service_locator``. +The structure contains a minor version and pointers to the module's +methods. + +The primary locate method is **lookup**, which accepts a service type, +realm name, desired socket type, and desired address family (which +will be AF_UNSPEC if no specific address family is desired). The +method should invoke the callback function once for each server +address it wants to return, passing a socket type (SOCK_STREAM for TCP +or SOCK_DGRAM for UDP) and socket address. The **lookup** method +should return 0 if it has authoritatively determined the server +addresses for the realm, KRB5_PLUGIN_NO_HANDLE if it wants to let +other location mechanisms determine the server addresses, or another +code if it experienced a failure which should abort the location +process. + +A module can create and destroy per-library-context state objects by +implementing the **init** and **fini** methods. State objects have +the type void \*, and should be cast to an internal type for the state +object. diff --git a/doc/rst_source/krb_plugindev/profile.rst b/doc/rst_source/krb_plugindev/profile.rst new file mode 100644 index 000000000..852bad18a --- /dev/null +++ b/doc/rst_source/krb_plugindev/profile.rst @@ -0,0 +1,86 @@ +Configuration interface (profile) +================================= + +The profile interface allows a module to control how krb5 +configuration information is obtained by the Kerberos library and +applications. For a detailed description of the profile interface, +see the header file ````. + +.. note: The locate interface does not follow the normal conventions + for MIT krb5 pluggable interfaces, because it is part of a + lower-level component of the krb5 library. + +A profile module exports a function named ``profile_module_init`` +matching the signature of the profile_module_init_fn type. This +function accepts a residual string, which may be used to help locate +the configuration source. The function fills in a vtable and may also +create a per-profile state object. If the module uses state objects, +it should implement the **copy** and **cleanup** methods to manage +them. + +A basic read-only profile module need only implement the +**get_values** and **free_values** methods. The **get_values** method +accepts a null-terminated list of C string names (e.g. an array +containing "libdefaults", "clockskew", and NULL for the **clockskew** +variable in the :ref:`libdefaults` section) and returns a +null-terminated list of values, which will be cleaned up with the +**free_values** method when the caller is done with them. + +Iterable profile modules must also define the **iterator_create**, +**iterator**, **iterator_free**, and **free_string** methods. The +core krb5 code does not require profiles to be iterable, but some +applications may iterate over the krb5 profile object in order to +present configuration interfaces. + +Writable profile modules must also define the **writable**, +**modified**, **update_relation**, **rename_section**, +**add_relation**, and **flush** methods. The core krb5 code does not +require profiles to be writable, but some applications may write to +the krb5 profile in order to present configuration interfaces. + +The following is an example of a very basic read-only profile module +which returns a hardcoded value for the **default_realm** variable in +:ref:`libdefaults`, and provides no other configuration information. +(For conciseness, the example omits code for checking the return +values of malloc and strdup.) :: + + #include + #include + #include + + static long + get_values(void *cbdata, const char *const *names, char ***values) + { + if (names[0] != NULL && strcmp(names[0], "libdefaults") == 0 && + names[1] != NULL && strcmp(names[1], "default_realm") == 0) { + *values = malloc(2 * sizeof(char *)); + (*values)[0] = strdup("ATHENA.MIT.EDU"); + (*values)[1] = NULL; + return 0; + } + return PROF_NO_RELATION; + } + + static void + free_values(void *cbdata, char **values) + { + char **v; + + for (v = values; *v; v++) + free(*v); + free(values); + } + + long + profile_module_init(const char *residual, struct profile_vtable *vtable, + void **cb_ret); + + long + profile_module_init(const char *residual, struct profile_vtable *vtable, + void **cb_ret) + { + *cb_ret = NULL; + vtable->get_values = get_values; + vtable->free_values = free_values; + return 0; + } diff --git a/doc/rst_source/krb_plugindev/pwqual.rst b/doc/rst_source/krb_plugindev/pwqual.rst new file mode 100644 index 000000000..a981e7903 --- /dev/null +++ b/doc/rst_source/krb_plugindev/pwqual.rst @@ -0,0 +1,23 @@ +Password quality interface (pwqual) +=================================== + +The pwqual interface allows modules to control what passwords are +allowed when a user changes passwords. For a detailed description of +the pwqual interface, see the header file ````. + +The primary pwqual method is **check**, which receives a password as +input and returns success (0) or a ``KADM5_PASS_Q_`` failure code +depending on whether the password is allowed. The **check** method +also receives the principal name and the name of the principal's +password policy as input; although there is no stable interface for +the module to obtain the fields of the password policy, it can define +its own configuration or data store based on the policy name. + +A module can create and destroy per-process state objects by +implementing the **open** and **close** methods. State objects have +the type krb5_pwqual_moddata, which is an abstract pointer type. A +module should typically cast this to an internal type for the state +object. The **open** method also receives the name of the realm's +dictionary file (as configured by the **dict_file** variable in the +:ref:`kdc_realms` section of :ref:`kdc.conf(5)`) if it wishes to use +it. -- 2.26.2