Projects/Pluggable configuration
Contents
Requirements and scope
This project will allow krb5 library and application configuration to come from sources other than profile-format krb5.conf files. The configuration source must be controllable in two ways:
- An application can, when creating a krb5 context, specify a programmatic source of configuration for that context.
- The system can cause krb5 configuration to come from a dynamically loaded library for all processes or for a subset of processes.
Currently, GSSAPI applications cannot specify or directly access the krb5 context used by the GSSAPI library. This problem is out of scope, but must be resolved (through a separate project) before application-level configuration control will be very useful.
Design constraints
The public krb5 API incorporates the libprofile API. An application can call krb5_get_profile() on a context to obtain a logical copy of the profile object for that context, and may invoke profile functions such as profile_get_values() on it. Since the profile object is a copy, it can survive longer than the krb5 context it was obtained from.
Moreover, in the current implementation, a krb5 context is not fully constructed until it has read a number of configuration values.
Because of this, the normal conventions for a krb5 pluggable interface are difficult to support. Instead, it makes the most sense to do almost all of the work inside libprofile, and then make it possible to create a krb5 context using an application-created profile.
Design
vtable profiles
The profile API is extended with a new type, struct profile_vtable, containing a list of callback functions roughly mirroring the existing profile API. A new function profile_init_vtable() creates a profile object with a specified vtable and callback data pointer. Profile operations performed against this object will redirect to the vtable methods.
Declarations for the API extensions are as follows. Documentation comments are omitted for brevity. Most of the methods are optional. A profile object used for a krb5 context need only implement the get_values and free_values methods, and possibly the cleanup and copy methods.
typedef long (*profile_get_values_fn)(void *cbdata, const char *const *names, char ***ret_values); typedef void (*profile_free_values_fn)(void *cbdata, char **values); typedef void (*profile_cleanup_fn)(void *cbdata); typedef long (*profile_copy_fn)(void *cbdata, void **ret_cbdata); typedef long (*profile_iterator_create_fn)(void *cbdata, const char *const *names, int flags, void **ret_iter); typedef long (*profile_iterator_fn)(void *cbdata, void *iter, char **ret_name, char **ret_value); typedef void (*profile_iterator_free_fn)(void *cbdata, void *iter); typedef void (*profile_free_string_fn)(void *cbdata, char *string); typedef long (*profile_writable_fn)(void *cbdata, int *writable); typedef long (*profile_modified_fn)(void *cbdata, int *modified); typedef long (*profile_update_relation_fn)(void *cbdata, const char **names, const char *old_value, const char *new_value); typedef long (*profile_rename_section_fn)(void *cbdata, const char **names, const char *new_name); typedef long (*profile_add_relation_fn)(void *cbdata, const char **names, const char *new_value); typedef long (*profile_flush_fn)(void *cbdata); struct profile_vtable { int min_ver; profile_get_values_fn get_values; profile_free_values_fn free_values; profile_cleanup_fn cleanup; profile_copy_fn copy; profile_iterator_create_fn iterator_create; profile_iterator_fn iterator; profile_iterator_free_fn iterator_free; profile_free_string_fn free_string; profile_writable_fn writable; profile_modified_fn modified; profile_update_relation_fn update_relation; profile_rename_section_fn rename_section; profile_add_relation_fn add_relation; profile_flush_fn flush; }; long KRB5_CALLCONV profile_init_vtable (struct profile_vtable *vtable, void *cbdata, profile_t *ret_profile);
A vtable profile may be copied (and will be copied in the normal course of use). The caller may either provide a copy method to make a new callback data pointer for the new profile object, or it can omit the copy method, in which case copied profile objects will use the same callback data as the original. To prevent double-free mishaps, the copy method is required if a cleanup method is supplied.
Application control of profile
A new function krb5_init_context_profile allows a krb5 context to be created using a profile object supplied by the application. It has the following signature:
#define KRB5_INIT_CONTEXT_SECURE 0x1 #define KRB5_INIT_CONTEXT_KDC 0x2 krb5_error_code krb5_init_context_profile(profile_t profile, krb5_flags flags, krb5_context *context);
As a side benefit, this function can be used (with a null profile argument) to create a context for KDC-ish programs, which was previously not possible without using the non-public function krb5int_init_context_kdc().
Dynamic profile modules
A loadable profile module defines a function named "profile_module_init" with the following prototype:
long profile_module_init(const char *residual, struct profile_vtable *vtable, void **cb_ret);
This signature differs from the usual krb5 loadable module conventions in several ways, because profile modules are tailored to libprofile instead of libkrb5. Because there is no separate cleanup function, a loadable module must implement the copy and cleanup methods unless it has no need for an allocated callback data pointer.
Using dynamic profile modules
To make use of a dynamic profile module, the system replaces the contents of the first profile file (krb5.conf or kdc.conf, or the values of KRB5_CONFIG or KRB5_KDC_PROFILE for non-secure contexts) with a module directive:
module modpath:residual
modpath may be relative to the library directory of the krb5 build. When parsing the profile files for the first time, if a module directive is encountered before any other content, libprofile will halt parsing, load the specified module, and invoke the module's profile_module_init function to create a vtable and callback data pointer. The library handle for the module will be released when all copies of the resulting profile are released.
In the profile API, a new initialization function is added to allow the use of modules when loading a profile:
#define PROFILE_INIT_ALLOW_MODULE 0x0001 long profile_init_flags(const_profile_filespec_t *files, int flags, profile_t *ret_profile);
The new function will be used by libkrb5 to initialize profiles. Other profile API consumers will not load profile modules unless they specify the appropriate flag, since they may have security reasons to treat profile files purely as data rather than code.
Testing
Automated C-language test programs will be added for vtable profiles and for loadable profile modules. A simple test module will be added in a subdirectory of util/profile to make the loadable profile test possible.
Relevant mailing list discussions
http://mailman.mit.edu/pipermail/krbdev/2011-June/010142.html
Release notes
Administrator experience:
- Add plugin interface for configuration.