<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>https://k5wiki.kerberos.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Hardjono</id>
		<title>K5Wiki - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="https://k5wiki.kerberos.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Hardjono"/>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki/Special:Contributions/Hardjono"/>
		<updated>2026-05-13T03:40:01Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.27.4</generator>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=4317</id>
		<title>Projects/Documentation Tasks</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=4317"/>
				<updated>2011-11-08T19:34:16Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Most commonly used API functions (in alphabetical order) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
To keep track of the various tasks that need to be documented such as function documentation, administration, troubleshooting etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Matrix of Document-Type VS Intended Readership&lt;br /&gt;
|-&lt;br /&gt;
! Doc-type/Reader&lt;br /&gt;
! Architectural Guide&lt;br /&gt;
! Setup &amp;amp; Config of Kerberos&lt;br /&gt;
! Admin &amp;amp; Operations of Kerberos&lt;br /&gt;
! Custom Build&lt;br /&gt;
! API Description&lt;br /&gt;
! API Details&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| End-users || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Architects || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|System Admins || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Application Developers || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|GSSAPI Developers || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Kerberos Developers || || || || || ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Application development ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! task&lt;br /&gt;
! Proposed Author&lt;br /&gt;
! Target Date&lt;br /&gt;
! Reviewer&lt;br /&gt;
! Reviewer Comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| Designing a new protocol, or extending existing one, to use GSS-API || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Choosing security API|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; GSS-API vs SASL vs KRB5 &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; A guide to the similarities and differences between Heimdal and MIT Kerberos API &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| GSS-API || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; A basic introduction to GSS-API, making use of the sample client and server, with special attention paid to Kerberos-related GSS-API issues&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; How to tell the GSS-API library on the client side where the existing Kerberos ticket cache is &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; How to write mechanism-independent GSS-API code&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  Acceptor naming - How to get servers to use any key in a keytab&amp;lt;/ul&amp;gt;|| GH|| || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; A guide to GSS-API naming as compared to Kerberos principal naming&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Using IAKERB&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Anonymous credentials&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Delegating credentials&amp;lt;/ul&amp;gt;|| MIT || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Available extensions&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Thread safety&amp;lt;/ul&amp;gt;|| KR || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Validating the flags set on the connection  to ensure things like mutual authentication, confidentiality, integrity, replay protection, and sequence protection&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Developing plugins|| GH || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; A guide to developing plugins &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Overview of existing pluggable interfaces   &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Krb5 library guide|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  A more advanced introduction to using the Kerberos libraries for initial authentication, focusing on the authentication steps, validating initial credential&amp;lt;/ul&amp;gt;|| TY || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Kerberos prompter behavior&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  An introduction to ticket caches and keytabs and their corresponding APIs &amp;lt;/ul&amp;gt;|| KR || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; An advanced guide to the pre-auth mechanisms, FAST&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; An advanced guide to the principal manipulation and parsing&amp;lt;/ul&amp;gt;|| TY || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Thread safety&amp;lt;/ul&amp;gt;|| KR || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  Password change including the automatic internal support for password change on expired passwords if a prompter is provided&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  krb5_appdefault_* functions and their alternatives &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| MIT Kerberos features : quick facts || ZT || || || ongoing&lt;br /&gt;
|-&lt;br /&gt;
| How to build Kerberos from source || ZT || || || ready for review&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Administration ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! task&lt;br /&gt;
! Proposed Author&lt;br /&gt;
! Target Date&lt;br /&gt;
! Reviewer&lt;br /&gt;
! Reviewer Comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|Setting a new realm|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Choosing backend: LDAP vs DB2&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Replication&amp;lt;/ul&amp;gt;|| ZT|| || ||ready for review&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; DNS configuration and SRV records - how they are used, in what order&amp;lt;/ul&amp;gt;|| ZT|| || ||&lt;br /&gt;
|-&lt;br /&gt;
| Integration Kerberos with Login System|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Difference between real Kerberos authentication, Kerberos password verification on the server side, and &amp;quot;LDAP authentication&amp;quot; in a Kerberos environment&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Validating Kerberos tickets&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Clear text password over HTTPS &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Configuring with pam_krb5 module&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Storing/locating keytab&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Cross-realm|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;cross-realm interaction with AD &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Transitive trust&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Referrals&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Performance|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Performance tuning tips&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Performance tradeoffs&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| kadmin interface|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Keying workstation/ host key setting&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Using Smartcard with PKINIT|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Kerberized ssh|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Configuration&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Cross-realm and ssh&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Selecting and configuring plugins|| GH || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Anonymity support|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| A guide to principal naming basics and structure|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Troubleshooting|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Troubleshooting  errors&amp;lt;/ul&amp;gt; || ZT || || || ongoing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Trace logging&amp;lt;/ul&amp;gt;||GH || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Realm renaming &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Using LDAP server for Kerberos backend|| ZT || ||Ubuntu 10.4 (lucid)|| &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== API documentation ==&lt;br /&gt;
&lt;br /&gt;
===Most commonly used API functions (in alphabetical order)===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Tier 1 - Highest priority&lt;br /&gt;
|-&lt;br /&gt;
! API&lt;br /&gt;
! Proposed Author&lt;br /&gt;
! Target Date&lt;br /&gt;
! Reviewer&lt;br /&gt;
! Reviewer Comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_build_principal.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|krb5_build_principal_alloc_va [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_build_principal_alloc_va.html] || ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal_ext [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_build_principal_ext.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_close  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_close.html] ||ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_default.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default_name [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_default_name.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_destroy [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_destroy.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_dup [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_dup.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_name [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_get_name.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_cc_get_principal [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_get_principal.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_cc_get_type [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_get_type.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_cc_initialize [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_initialize.html]|| ZT||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_cc_new_unique [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_new_unique.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_cc_resolve [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_resolve.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_change_password  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_change_password.html]|| ZT||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_context  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_free_context.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_error_message  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_free_error_message.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_principal  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_free_principal.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_fwd_tgt_cred  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_fwd_tgt_cred.html]|| ZT || GH|| || Needs example&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_default_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_default_realm.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_error_message  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_error_message.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_host_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_host_realm.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_credentials  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_credentials.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_fallback_host_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_fallback_host_realm.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_keytab  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_keytab.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_alloc  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_alloc.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_free  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_free.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_get_fast_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_get_fast_flags.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_init  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_init.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_address_list  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_address_list.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_anonymous  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_anonymous.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_canonicalize  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_canonicalize.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_change_password_prompt  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_change_password_prompt.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_etype_list  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_etype_list.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_expire_callback  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_expire_callback.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_fast_ccache.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache_name   [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_fast_ccache_name.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_fast_flags.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_forwardable  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_forwardable.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_out_ccache  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_out_ccache.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_pa  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_pa.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_preauth_list  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_preauth_list.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_proxiable  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_proxiable.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_renew_life  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_renew_life.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_salt  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_salt.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_tkt_life  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_tkt_life.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_password  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_password.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_profile  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_profile.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_prompt_types  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_prompt_types.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_renewed_creds  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_renewed_creds.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_validated_creds  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_validated_creds.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_context  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_init_context.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_secure_context  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_init_secure_context.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_config_principal  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_is_config_principal.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_thread_safe  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_is_thread_safe.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_close  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_close.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_default.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default_name  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_default_name.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_name  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_get_name.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_type  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_get_type.html] || ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_resolve  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_resolve.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kuserok  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kuserok.html] || ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_parse_name.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_parse_name_flags.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_principal_compare.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_any_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_principal_compare_any_realm.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_principal_compare_flags.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_prompter_posix  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_prompter_posix.html]|| ZT||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_realm_compare  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_realm_compare.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_recvauth.html]||ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth_version  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_recvauth_version.html] ||ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_default_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_default_realm.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_set_password  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_password.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_password_using_ccache  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_password_using_ccache.html] || ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_principal_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_principal_realm.html] || ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_callback  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_trace_callback.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_filename  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_trace_filename.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_sname_to_principal  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_sname_to_principal.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_unparse_name.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_ext  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_unparse_name_ext.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_unparse_name_flags.html] || ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags_ext  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_unparse_name_flags_ext.html] || ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_us_timeofday  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_us_timeofday.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_verify_authdata_kdc_issued  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_verify_authdata_kdc_issued.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Abbreviations ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! abbreviation&lt;br /&gt;
! full names?&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| GH || Greg Hudson&lt;br /&gt;
|-&lt;br /&gt;
| KR || Ken Raeburn&lt;br /&gt;
|-&lt;br /&gt;
| MIT || MITKC group&lt;br /&gt;
|-&lt;br /&gt;
|  TY|| Tom Yu&lt;br /&gt;
|-&lt;br /&gt;
| ZT || Zhanna Tsitkova&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=4316</id>
		<title>Projects/Documentation Tasks</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=4316"/>
				<updated>2011-11-08T19:33:27Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Administration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
To keep track of the various tasks that need to be documented such as function documentation, administration, troubleshooting etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Matrix of Document-Type VS Intended Readership&lt;br /&gt;
|-&lt;br /&gt;
! Doc-type/Reader&lt;br /&gt;
! Architectural Guide&lt;br /&gt;
! Setup &amp;amp; Config of Kerberos&lt;br /&gt;
! Admin &amp;amp; Operations of Kerberos&lt;br /&gt;
! Custom Build&lt;br /&gt;
! API Description&lt;br /&gt;
! API Details&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| End-users || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Architects || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|System Admins || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Application Developers || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|GSSAPI Developers || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Kerberos Developers || || || || || ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Application development ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! task&lt;br /&gt;
! Proposed Author&lt;br /&gt;
! Target Date&lt;br /&gt;
! Reviewer&lt;br /&gt;
! Reviewer Comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| Designing a new protocol, or extending existing one, to use GSS-API || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Choosing security API|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; GSS-API vs SASL vs KRB5 &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; A guide to the similarities and differences between Heimdal and MIT Kerberos API &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| GSS-API || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; A basic introduction to GSS-API, making use of the sample client and server, with special attention paid to Kerberos-related GSS-API issues&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; How to tell the GSS-API library on the client side where the existing Kerberos ticket cache is &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; How to write mechanism-independent GSS-API code&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  Acceptor naming - How to get servers to use any key in a keytab&amp;lt;/ul&amp;gt;|| GH|| || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; A guide to GSS-API naming as compared to Kerberos principal naming&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Using IAKERB&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Anonymous credentials&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Delegating credentials&amp;lt;/ul&amp;gt;|| MIT || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Available extensions&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Thread safety&amp;lt;/ul&amp;gt;|| KR || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Validating the flags set on the connection  to ensure things like mutual authentication, confidentiality, integrity, replay protection, and sequence protection&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Developing plugins|| GH || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; A guide to developing plugins &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Overview of existing pluggable interfaces   &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Krb5 library guide|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  A more advanced introduction to using the Kerberos libraries for initial authentication, focusing on the authentication steps, validating initial credential&amp;lt;/ul&amp;gt;|| TY || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Kerberos prompter behavior&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  An introduction to ticket caches and keytabs and their corresponding APIs &amp;lt;/ul&amp;gt;|| KR || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; An advanced guide to the pre-auth mechanisms, FAST&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; An advanced guide to the principal manipulation and parsing&amp;lt;/ul&amp;gt;|| TY || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Thread safety&amp;lt;/ul&amp;gt;|| KR || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  Password change including the automatic internal support for password change on expired passwords if a prompter is provided&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  krb5_appdefault_* functions and their alternatives &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| MIT Kerberos features : quick facts || ZT || || || ongoing&lt;br /&gt;
|-&lt;br /&gt;
| How to build Kerberos from source || ZT || || || ready for review&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Administration ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! task&lt;br /&gt;
! Proposed Author&lt;br /&gt;
! Target Date&lt;br /&gt;
! Reviewer&lt;br /&gt;
! Reviewer Comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|Setting a new realm|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Choosing backend: LDAP vs DB2&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Replication&amp;lt;/ul&amp;gt;|| ZT|| || ||ready for review&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; DNS configuration and SRV records - how they are used, in what order&amp;lt;/ul&amp;gt;|| ZT|| || ||&lt;br /&gt;
|-&lt;br /&gt;
| Integration Kerberos with Login System|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Difference between real Kerberos authentication, Kerberos password verification on the server side, and &amp;quot;LDAP authentication&amp;quot; in a Kerberos environment&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Validating Kerberos tickets&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Clear text password over HTTPS &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Configuring with pam_krb5 module&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Storing/locating keytab&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Cross-realm|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;cross-realm interaction with AD &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Transitive trust&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Referrals&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Performance|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Performance tuning tips&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Performance tradeoffs&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| kadmin interface|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Keying workstation/ host key setting&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Using Smartcard with PKINIT|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Kerberized ssh|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Configuration&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Cross-realm and ssh&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Selecting and configuring plugins|| GH || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Anonymity support|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| A guide to principal naming basics and structure|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Troubleshooting|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Troubleshooting  errors&amp;lt;/ul&amp;gt; || ZT || || || ongoing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Trace logging&amp;lt;/ul&amp;gt;||GH || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Realm renaming &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Using LDAP server for Kerberos backend|| ZT || ||Ubuntu 10.4 (lucid)|| &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== API documentation ==&lt;br /&gt;
&lt;br /&gt;
===Most commonly used API functions (in alphabetical order)===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Tier 1 - Highest priority&lt;br /&gt;
|-&lt;br /&gt;
! API&lt;br /&gt;
! who writes?&lt;br /&gt;
! who reviews?&lt;br /&gt;
! reviewed?&lt;br /&gt;
! comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_build_principal.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|krb5_build_principal_alloc_va [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_build_principal_alloc_va.html] || ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal_ext [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_build_principal_ext.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_close  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_close.html] ||ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_default.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default_name [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_default_name.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_destroy [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_destroy.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_dup [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_dup.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_name [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_get_name.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_cc_get_principal [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_get_principal.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_cc_get_type [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_get_type.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_cc_initialize [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_initialize.html]|| ZT||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_cc_new_unique [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_new_unique.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_cc_resolve [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_resolve.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_change_password  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_change_password.html]|| ZT||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_context  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_free_context.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_error_message  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_free_error_message.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_principal  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_free_principal.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_fwd_tgt_cred  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_fwd_tgt_cred.html]|| ZT || GH|| || Needs example&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_default_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_default_realm.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_error_message  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_error_message.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_host_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_host_realm.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_credentials  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_credentials.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_fallback_host_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_fallback_host_realm.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_keytab  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_keytab.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_alloc  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_alloc.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_free  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_free.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_get_fast_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_get_fast_flags.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_init  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_init.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_address_list  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_address_list.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_anonymous  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_anonymous.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_canonicalize  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_canonicalize.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_change_password_prompt  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_change_password_prompt.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_etype_list  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_etype_list.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_expire_callback  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_expire_callback.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_fast_ccache.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache_name   [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_fast_ccache_name.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_fast_flags.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_forwardable  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_forwardable.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_out_ccache  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_out_ccache.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_pa  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_pa.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_preauth_list  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_preauth_list.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_proxiable  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_proxiable.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_renew_life  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_renew_life.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_salt  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_salt.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_tkt_life  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_tkt_life.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_password  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_password.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_profile  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_profile.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_prompt_types  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_prompt_types.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_renewed_creds  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_renewed_creds.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_validated_creds  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_validated_creds.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_context  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_init_context.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_secure_context  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_init_secure_context.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_config_principal  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_is_config_principal.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_thread_safe  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_is_thread_safe.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_close  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_close.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_default.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default_name  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_default_name.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_name  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_get_name.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_type  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_get_type.html] || ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_resolve  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_resolve.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kuserok  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kuserok.html] || ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_parse_name.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_parse_name_flags.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_principal_compare.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_any_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_principal_compare_any_realm.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_principal_compare_flags.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_prompter_posix  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_prompter_posix.html]|| ZT||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_realm_compare  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_realm_compare.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_recvauth.html]||ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth_version  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_recvauth_version.html] ||ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_default_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_default_realm.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_set_password  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_password.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_password_using_ccache  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_password_using_ccache.html] || ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_principal_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_principal_realm.html] || ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_callback  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_trace_callback.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_filename  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_trace_filename.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_sname_to_principal  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_sname_to_principal.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_unparse_name.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_ext  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_unparse_name_ext.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_unparse_name_flags.html] || ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags_ext  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_unparse_name_flags_ext.html] || ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_us_timeofday  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_us_timeofday.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_verify_authdata_kdc_issued  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_verify_authdata_kdc_issued.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Abbreviations ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! abbreviation&lt;br /&gt;
! full names?&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| GH || Greg Hudson&lt;br /&gt;
|-&lt;br /&gt;
| KR || Ken Raeburn&lt;br /&gt;
|-&lt;br /&gt;
| MIT || MITKC group&lt;br /&gt;
|-&lt;br /&gt;
|  TY|| Tom Yu&lt;br /&gt;
|-&lt;br /&gt;
| ZT || Zhanna Tsitkova&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=4315</id>
		<title>Projects/Documentation Tasks</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=4315"/>
				<updated>2011-11-08T16:29:24Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Application development */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
To keep track of the various tasks that need to be documented such as function documentation, administration, troubleshooting etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Matrix of Document-Type VS Intended Readership&lt;br /&gt;
|-&lt;br /&gt;
! Doc-type/Reader&lt;br /&gt;
! Architectural Guide&lt;br /&gt;
! Setup &amp;amp; Config of Kerberos&lt;br /&gt;
! Admin &amp;amp; Operations of Kerberos&lt;br /&gt;
! Custom Build&lt;br /&gt;
! API Description&lt;br /&gt;
! API Details&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| End-users || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Architects || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|System Admins || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Application Developers || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|GSSAPI Developers || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Kerberos Developers || || || || || ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Application development ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! task&lt;br /&gt;
! Proposed Author&lt;br /&gt;
! Target Date&lt;br /&gt;
! Reviewer&lt;br /&gt;
! Reviewer Comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| Designing a new protocol, or extending existing one, to use GSS-API || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Choosing security API|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; GSS-API vs SASL vs KRB5 &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; A guide to the similarities and differences between Heimdal and MIT Kerberos API &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| GSS-API || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; A basic introduction to GSS-API, making use of the sample client and server, with special attention paid to Kerberos-related GSS-API issues&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; How to tell the GSS-API library on the client side where the existing Kerberos ticket cache is &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; How to write mechanism-independent GSS-API code&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  Acceptor naming - How to get servers to use any key in a keytab&amp;lt;/ul&amp;gt;|| GH|| || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; A guide to GSS-API naming as compared to Kerberos principal naming&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Using IAKERB&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Anonymous credentials&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Delegating credentials&amp;lt;/ul&amp;gt;|| MIT || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Available extensions&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Thread safety&amp;lt;/ul&amp;gt;|| KR || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Validating the flags set on the connection  to ensure things like mutual authentication, confidentiality, integrity, replay protection, and sequence protection&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Developing plugins|| GH || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; A guide to developing plugins &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Overview of existing pluggable interfaces   &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Krb5 library guide|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  A more advanced introduction to using the Kerberos libraries for initial authentication, focusing on the authentication steps, validating initial credential&amp;lt;/ul&amp;gt;|| TY || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Kerberos prompter behavior&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  An introduction to ticket caches and keytabs and their corresponding APIs &amp;lt;/ul&amp;gt;|| KR || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; An advanced guide to the pre-auth mechanisms, FAST&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; An advanced guide to the principal manipulation and parsing&amp;lt;/ul&amp;gt;|| TY || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Thread safety&amp;lt;/ul&amp;gt;|| KR || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  Password change including the automatic internal support for password change on expired passwords if a prompter is provided&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;  krb5_appdefault_* functions and their alternatives &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| MIT Kerberos features : quick facts || ZT || || || ongoing&lt;br /&gt;
|-&lt;br /&gt;
| How to build Kerberos from source || ZT || || || ready for review&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Administration ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! task&lt;br /&gt;
! who writes/due date&lt;br /&gt;
! who reviews/due date&lt;br /&gt;
! comments&lt;br /&gt;
! status&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|Setting a new realm|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Choosing backend: LDAP vs DB2&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Replication&amp;lt;/ul&amp;gt;|| ZT|| || ||ready for review&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; DNS configuration and SRV records - how they are used, in what order&amp;lt;/ul&amp;gt;|| ZT|| || ||&lt;br /&gt;
|-&lt;br /&gt;
| Integration Kerberos with Login System|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Difference between real Kerberos authentication, Kerberos password verification on the server side, and &amp;quot;LDAP authentication&amp;quot; in a Kerberos environment&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Validating Kerberos tickets&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Clear text password over HTTPS &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Configuring with pam_krb5 module&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Storing/locating keytab&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Cross-realm|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;cross-realm interaction with AD &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Transitive trust&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Referrals&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Performance|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Performance tuning tips&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Performance tradeoffs&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| kadmin interface|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Keying workstation/ host key setting&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Using Smartcard with PKINIT|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Kerberized ssh|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt; Configuration&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Cross-realm and ssh&amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Selecting and configuring plugins|| GH || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Anonymity support|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| A guide to principal naming basics and structure|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Troubleshooting|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Troubleshooting  errors&amp;lt;/ul&amp;gt; || ZT || || || ongoing&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Trace logging&amp;lt;/ul&amp;gt;||GH || || ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Realm renaming &amp;lt;/ul&amp;gt;|| || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Using LDAP server for Kerberos backend|| ZT || ||Ubuntu 10.4 (lucid)|| &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== API documentation ==&lt;br /&gt;
&lt;br /&gt;
===Most commonly used API functions (in alphabetical order)===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Tier 1 - Highest priority&lt;br /&gt;
|-&lt;br /&gt;
! API&lt;br /&gt;
! who writes?&lt;br /&gt;
! who reviews?&lt;br /&gt;
! reviewed?&lt;br /&gt;
! comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_build_principal.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|krb5_build_principal_alloc_va [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_build_principal_alloc_va.html] || ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal_ext [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_build_principal_ext.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_close  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_close.html] ||ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_default.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default_name [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_default_name.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_destroy [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_destroy.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_dup [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_dup.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_name [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_get_name.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_cc_get_principal [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_get_principal.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_cc_get_type [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_get_type.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_cc_initialize [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_initialize.html]|| ZT||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_cc_new_unique [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_new_unique.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_cc_resolve [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_cc_resolve.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_change_password  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_change_password.html]|| ZT||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_context  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_free_context.html]|| ZT|| GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_error_message  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_free_error_message.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_principal  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_free_principal.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_fwd_tgt_cred  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_fwd_tgt_cred.html]|| ZT || GH|| || Needs example&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_default_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_default_realm.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_error_message  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_error_message.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_host_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_host_realm.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_credentials  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_credentials.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_fallback_host_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_fallback_host_realm.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_keytab  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_keytab.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_alloc  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_alloc.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_free  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_free.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_get_fast_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_get_fast_flags.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_init  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_init.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_address_list  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_address_list.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_anonymous  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_anonymous.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_canonicalize  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_canonicalize.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_change_password_prompt  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_change_password_prompt.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_etype_list  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_etype_list.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_expire_callback  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_expire_callback.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_fast_ccache.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache_name   [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_fast_ccache_name.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_fast_flags.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_forwardable  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_forwardable.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_out_ccache  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_out_ccache.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_pa  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_pa.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_preauth_list  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_preauth_list.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_proxiable  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_proxiable.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_renew_life  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_renew_life.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_salt  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_salt.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_tkt_life  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_opt_set_tkt_life.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_password  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_init_creds_password.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_profile  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_profile.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_prompt_types  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_prompt_types.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_renewed_creds  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_renewed_creds.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_validated_creds  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_get_validated_creds.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_context  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_init_context.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_secure_context  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_init_secure_context.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_config_principal  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_is_config_principal.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_thread_safe  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_is_thread_safe.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_close  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_close.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_default.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default_name  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_default_name.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_name  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_get_name.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_type  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_get_type.html] || ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_resolve  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kt_resolve.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kuserok  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_kuserok.html] || ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_parse_name.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_parse_name_flags.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_principal_compare.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_any_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_principal_compare_any_realm.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_principal_compare_flags.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_prompter_posix  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_prompter_posix.html]|| ZT||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_realm_compare  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_realm_compare.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_recvauth.html]||ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth_version  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_recvauth_version.html] ||ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_default_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_default_realm.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_set_password  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_password.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_password_using_ccache  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_password_using_ccache.html] || ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_principal_realm  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_principal_realm.html] || ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_callback  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_trace_callback.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_filename  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_set_trace_filename.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_sname_to_principal  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_sname_to_principal.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_unparse_name.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_ext  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_unparse_name_ext.html]|| ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_unparse_name_flags.html] || ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags_ext  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_unparse_name_flags_ext.html] || ZT ||GH || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_us_timeofday  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_us_timeofday.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_verify_authdata_kdc_issued  [http://web.mit.edu/tsitkova/www/build/refs/api/krb5_verify_authdata_kdc_issued.html]|| ZT || GH|| ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Abbreviations ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ &lt;br /&gt;
|-&lt;br /&gt;
! abbreviation&lt;br /&gt;
! full names?&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| GH || Greg Hudson&lt;br /&gt;
|-&lt;br /&gt;
| KR || Ken Raeburn&lt;br /&gt;
|-&lt;br /&gt;
| MIT || MITKC group&lt;br /&gt;
|-&lt;br /&gt;
|  TY|| Tom Yu&lt;br /&gt;
|-&lt;br /&gt;
| ZT || Zhanna Tsitkova&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Release_1.10&amp;diff=3864</id>
		<title>Release 1.10</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Release_1.10&amp;diff=3864"/>
				<updated>2011-05-19T15:17:02Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Timeline ==&lt;br /&gt;
&lt;br /&gt;
This is only an approximate timeline.&lt;br /&gt;
&lt;br /&gt;
* Jul. 2010 -- make release branch&lt;br /&gt;
* Oct. 2010 -- final release&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
&lt;br /&gt;
* Kernel / user split (for NFS, etc.): Add build infrastructure demonstrating and testing a message-processing subset of the gss-krb5 mechanism suitable for kernel filesystems.&lt;br /&gt;
* Localization: Create infrastructure for localization of client user interface messages using gettext.&lt;br /&gt;
* Improve API documentation: Create documentation for the libkrb5 API.&lt;br /&gt;
* Selective refactoring of KDC (to support libKDC etc.): Reorganize parts of the KDC code for improved modularity and maintainability.&lt;br /&gt;
* Pluggable configuration back-end: Allow applications and integrators to override krb5.conf as the source of krb5 configuration data.&lt;br /&gt;
* Credential selection: Add a facility to select between credentials for different Kerberos identities based on the service being contacted. (This will be confirmed).&lt;br /&gt;
* Referrals: Finish implementation following IETF updates.&lt;br /&gt;
* PKINIT hash agility: Allow PKINIT to use newer hash algorithms than SHA-1.&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=3775</id>
		<title>Projects/Documentation Tasks</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=3775"/>
				<updated>2011-01-13T17:14:21Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* API documentation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
To keep track of the various tasks that need to be documented such as function documentation, administration, troubleshooting etc.&lt;br /&gt;
&lt;br /&gt;
=== API documentation ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Matrix of Document-Type VS Intended Readership&lt;br /&gt;
|-&lt;br /&gt;
! Doc-type/Reader&lt;br /&gt;
! Architectural Guide&lt;br /&gt;
! Setup &amp;amp; Config of Kerberos&lt;br /&gt;
! Admin &amp;amp; Operations of Kerberos&lt;br /&gt;
! Custom Build&lt;br /&gt;
! API Description&lt;br /&gt;
! API Details&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| End-users || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Architects || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|System Admins || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Application Developers || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|GSSAPI Developers || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Kerberos Developers || || || || || || ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Tier 1 - most commonly used API functions (in alphabetical order)&lt;br /&gt;
|-&lt;br /&gt;
! API&lt;br /&gt;
! who writes?&lt;br /&gt;
! who reviews?&lt;br /&gt;
! reviewed?&lt;br /&gt;
! comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|krb5_build_principal_alloc_val || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_close || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_destroy || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_cc_dup || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_type || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_initialize || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_new_unique || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_resolve || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_change_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_error_message || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_fwd_tgt_cred || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_default_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_error_message || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_host_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_credentials || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_fallback_host_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_keytab || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_alloc || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_free || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_get_fast_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_init || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_address_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_anonymous || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_canonicalize || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_change_password_prompt || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_etype_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_expire_callback || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache_name  || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_forwardable || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_out_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_pa || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_preauth_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_proxiable || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_renew_life || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_salt || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_tkt_life || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_profile || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_prompt_types || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_renewed_creds || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_validated_creds || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_secure_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_config_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_thread_safe || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_close || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_type  || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_resolve || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kuserok || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_any_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_prompter_posix || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_realm_compare || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth_version || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_default_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_set_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_password_using_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_principal_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_callback || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_filename || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_sname_to_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_us_timeofday || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_verify_authdata_kdc_issued || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=3774</id>
		<title>Projects/Documentation Tasks</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=3774"/>
				<updated>2011-01-13T17:13:45Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* API documentation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
To keep track of the various tasks that need to be documented such as function documentation, administration, troubleshooting etc.&lt;br /&gt;
&lt;br /&gt;
=== API documentation ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Matrix of Document-Type VS Intended Readership&lt;br /&gt;
|-&lt;br /&gt;
! Doc-type/Reader&lt;br /&gt;
! Architectural Guide&lt;br /&gt;
! Setup and Config of Kerberos&lt;br /&gt;
! Admin &amp;amp; Operations of Kerberos&lt;br /&gt;
! Custom Build&lt;br /&gt;
! API Description&lt;br /&gt;
! API Details&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| End-users || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Architects || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Sys Admins || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Application Developers || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|GSSAPI Developers || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Kerberos Developers || || || || || || ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Tier 1 - most commonly used API functions (in alphabetical order)&lt;br /&gt;
|-&lt;br /&gt;
! API&lt;br /&gt;
! who writes?&lt;br /&gt;
! who reviews?&lt;br /&gt;
! reviewed?&lt;br /&gt;
! comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|krb5_build_principal_alloc_val || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_close || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_destroy || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_cc_dup || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_type || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_initialize || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_new_unique || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_resolve || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_change_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_error_message || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_fwd_tgt_cred || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_default_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_error_message || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_host_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_credentials || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_fallback_host_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_keytab || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_alloc || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_free || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_get_fast_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_init || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_address_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_anonymous || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_canonicalize || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_change_password_prompt || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_etype_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_expire_callback || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache_name  || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_forwardable || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_out_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_pa || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_preauth_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_proxiable || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_renew_life || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_salt || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_tkt_life || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_profile || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_prompt_types || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_renewed_creds || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_validated_creds || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_secure_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_config_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_thread_safe || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_close || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_type  || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_resolve || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kuserok || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_any_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_prompter_posix || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_realm_compare || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth_version || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_default_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_set_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_password_using_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_principal_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_callback || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_filename || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_sname_to_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_us_timeofday || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_verify_authdata_kdc_issued || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=3773</id>
		<title>Projects/Documentation Tasks</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=3773"/>
				<updated>2011-01-13T17:13:21Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* API documentation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
To keep track of the various tasks that need to be documented such as function documentation, administration, troubleshooting etc.&lt;br /&gt;
&lt;br /&gt;
=== API documentation ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Matrix of Document-Type VS Intended Readership&lt;br /&gt;
|-&lt;br /&gt;
! Doc-type/Reader&lt;br /&gt;
! Architectural Guide&lt;br /&gt;
! Setup and Config of Kerberos&lt;br /&gt;
! Admin &amp;amp; Operations of Kerberos&lt;br /&gt;
! Custom Build&lt;br /&gt;
! API Description&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| End-users || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Architects || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Sys Admins || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Application Developers || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|GSSAPI Developers || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Kerberos Developers || || || || || || ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Tier 1 - most commonly used API functions (in alphabetical order)&lt;br /&gt;
|-&lt;br /&gt;
! API&lt;br /&gt;
! who writes?&lt;br /&gt;
! who reviews?&lt;br /&gt;
! reviewed?&lt;br /&gt;
! comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|krb5_build_principal_alloc_val || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_close || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_destroy || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_cc_dup || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_type || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_initialize || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_new_unique || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_resolve || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_change_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_error_message || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_fwd_tgt_cred || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_default_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_error_message || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_host_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_credentials || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_fallback_host_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_keytab || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_alloc || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_free || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_get_fast_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_init || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_address_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_anonymous || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_canonicalize || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_change_password_prompt || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_etype_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_expire_callback || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache_name  || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_forwardable || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_out_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_pa || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_preauth_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_proxiable || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_renew_life || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_salt || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_tkt_life || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_profile || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_prompt_types || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_renewed_creds || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_validated_creds || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_secure_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_config_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_thread_safe || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_close || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_type  || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_resolve || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kuserok || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_any_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_prompter_posix || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_realm_compare || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth_version || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_default_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_set_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_password_using_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_principal_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_callback || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_filename || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_sname_to_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_us_timeofday || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_verify_authdata_kdc_issued || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=3772</id>
		<title>Projects/Documentation Tasks</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=3772"/>
				<updated>2011-01-13T17:12:46Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* API documentation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
To keep track of the various tasks that need to be documented such as function documentation, administration, troubleshooting etc.&lt;br /&gt;
&lt;br /&gt;
=== API documentation ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Matrix of Document-Type VS Intended Readership&lt;br /&gt;
|-&lt;br /&gt;
! Architectural Guide&lt;br /&gt;
! Setup and Config of Kerberos&lt;br /&gt;
! Admin &amp;amp; Operations of Kerberos&lt;br /&gt;
! Custom Build&lt;br /&gt;
! API Description&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| End-users || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Architects || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Sys Admins || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Application Developers || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|GSSAPI Developers || || || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Kerberos Developers || || || || || || ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Tier 1 - most commonly used API functions (in alphabetical order)&lt;br /&gt;
|-&lt;br /&gt;
! API&lt;br /&gt;
! who writes?&lt;br /&gt;
! who reviews?&lt;br /&gt;
! reviewed?&lt;br /&gt;
! comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|krb5_build_principal_alloc_val || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_close || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_destroy || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_cc_dup || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_type || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_initialize || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_new_unique || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_resolve || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_change_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_error_message || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_fwd_tgt_cred || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_default_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_error_message || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_host_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_credentials || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_fallback_host_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_keytab || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_alloc || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_free || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_get_fast_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_init || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_address_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_anonymous || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_canonicalize || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_change_password_prompt || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_etype_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_expire_callback || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache_name  || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_forwardable || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_out_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_pa || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_preauth_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_proxiable || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_renew_life || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_salt || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_tkt_life || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_profile || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_prompt_types || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_renewed_creds || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_validated_creds || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_secure_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_config_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_thread_safe || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_close || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_type  || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_resolve || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kuserok || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_any_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_prompter_posix || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_realm_compare || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth_version || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_default_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_set_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_password_using_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_principal_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_callback || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_filename || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_sname_to_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_us_timeofday || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_verify_authdata_kdc_issued || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=3771</id>
		<title>Projects/Documentation Tasks</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=3771"/>
				<updated>2011-01-13T17:11:59Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* API documentation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
To keep track of the various tasks that need to be documented such as function documentation, administration, troubleshooting etc.&lt;br /&gt;
&lt;br /&gt;
=== API documentation ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Matrix of Document-Type VS Intended Readership&lt;br /&gt;
|-&lt;br /&gt;
! Architectural Guide&lt;br /&gt;
! Setup and Config of Kerberos&lt;br /&gt;
! Admin &amp;amp; Operations of Kerberos&lt;br /&gt;
! Custom Build&lt;br /&gt;
! API Description&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| End-users || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Architects || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Sys Admins || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Application Developers || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|GSSAPI Developers || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|Kerberos Developers || || || || ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Tier 1 - most commonly used API functions (in alphabetical order)&lt;br /&gt;
|-&lt;br /&gt;
! API&lt;br /&gt;
! who writes?&lt;br /&gt;
! who reviews?&lt;br /&gt;
! reviewed?&lt;br /&gt;
! comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|krb5_build_principal_alloc_val || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_close || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_destroy || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_cc_dup || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_type || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_initialize || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_new_unique || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_resolve || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_change_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_error_message || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_fwd_tgt_cred || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_default_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_error_message || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_host_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_credentials || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_fallback_host_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_keytab || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_alloc || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_free || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_get_fast_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_init || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_address_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_anonymous || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_canonicalize || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_change_password_prompt || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_etype_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_expire_callback || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache_name  || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_forwardable || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_out_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_pa || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_preauth_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_proxiable || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_renew_life || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_salt || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_tkt_life || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_profile || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_prompt_types || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_renewed_creds || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_validated_creds || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_secure_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_config_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_thread_safe || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_close || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_type  || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_resolve || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kuserok || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_any_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_prompter_posix || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_realm_compare || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth_version || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_default_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_set_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_password_using_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_principal_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_callback || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_filename || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_sname_to_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_us_timeofday || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_verify_authdata_kdc_issued || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=3770</id>
		<title>Projects/Documentation Tasks</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Documentation_Tasks&amp;diff=3770"/>
				<updated>2011-01-13T17:10:14Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Purpose */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Purpose ==&lt;br /&gt;
&lt;br /&gt;
To keep track of the various tasks that need to be documented such as function documentation, administration, troubleshooting etc.&lt;br /&gt;
&lt;br /&gt;
=== API documentation ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Tier 1 - most commonly used API functions (in alphabetical order)&lt;br /&gt;
|-&lt;br /&gt;
! Architectural Guide&lt;br /&gt;
! Setup and Config of Kerberos&lt;br /&gt;
! Admin &amp;amp; Operations of Kerberos&lt;br /&gt;
! Custom Build&lt;br /&gt;
! API Description&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|krb5_build_principal_alloc_val || || || || ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Tier 1 - most commonly used API functions (in alphabetical order)&lt;br /&gt;
|-&lt;br /&gt;
! API&lt;br /&gt;
! who writes?&lt;br /&gt;
! who reviews?&lt;br /&gt;
! reviewed?&lt;br /&gt;
! comments&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|krb5_build_principal_alloc_val || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_build_principal_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_close || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_default_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_destroy || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_cc_dup || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_get_type || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_initialize || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_new_unique || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_cc_resolve || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_change_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_error_message || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_free_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_fwd_tgt_cred || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_default_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_error_message || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_host_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_credentials || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_fallback_host_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_keytab || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_alloc || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_free || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_get_init_creds_opt_get_fast_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_init || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_address_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_anonymous || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_canonicalize || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_change_password_prompt || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_etype_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_expire_callback || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_ccache_name  || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_fast_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_forwardable || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_out_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_pa || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_preauth_list || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_proxiable || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_renew_life || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_salt || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_opt_set_tkt_life || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_init_creds_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_profile || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_prompt_types || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_renewed_creds || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_get_validated_creds || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_init_secure_context || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_config_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_is_thread_safe || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_close || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_default_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_get_type  || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kt_resolve || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_kuserok || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_parse_name_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_any_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_principal_compare_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_prompter_posix || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_realm_compare || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_recvauth_version || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_default_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|   krb5_set_password || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_password_using_ccache || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|  krb5_set_principal_realm || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_callback || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_set_trace_filename || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_sname_to_principal || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_unparse_name_flags_ext || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_us_timeofday || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| krb5_verify_authdata_kdc_issued || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3574</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3574"/>
				<updated>2010-08-03T19:13:20Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Background */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
* Project inception and first proposal:  Zhanna Tsitkova (see [[Projects/Plugin_support_improvements_%28first_version%29]]).&lt;br /&gt;
* Further revisions (this page): Greg Hudson, Tom Yu and Thomas Hardjono.&lt;br /&gt;
&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin manager uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin manager to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The architecture is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin support:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin support:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin support which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support architecture uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3573</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3573"/>
				<updated>2010-08-03T19:12:47Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Background */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
* Project inception and first proposal:  Zhanna Tsitkova (see [[Projects/Plugin_support_improvements_%28first_version%29]]).&lt;br /&gt;
* Further revisions: Greg Hudson, Tom Yu and Thomas Hardjono.&lt;br /&gt;
&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin manager uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin manager to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The architecture is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin support:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin support:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin support which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support architecture uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3572</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3572"/>
				<updated>2010-08-03T19:12:39Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Background */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
* Project inception and first proposal:  Zhanna Tsitkova (see [[Projects/Plugin_support_improvements_%28first_version%29]]).&lt;br /&gt;
* Further revision: Greg Hudson, Tom Yu and Thomas Hardjono.&lt;br /&gt;
&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin manager uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin manager to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The architecture is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin support:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin support:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin support which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support architecture uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3571</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3571"/>
				<updated>2010-08-03T19:12:12Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
* Project inception:  Zhanna Tsitkova (see [[Projects/Plugin_support_improvements_%28first_version%29]]).&lt;br /&gt;
* Further revision: Greg Hudson, Tom Yu and Thomas Hardjono.&lt;br /&gt;
&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin manager uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin manager to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The architecture is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin support:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin support:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin support which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support architecture uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3570</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3570"/>
				<updated>2010-08-03T19:05:45Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
* Project inception:  Zhanna Tsitkova [[Projects/Plugin_support_improvements_%28first_version%29]]&lt;br /&gt;
* Further revision: Greg Hudson and Tom Yu.&lt;br /&gt;
&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin manager uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin manager to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The architecture is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin support:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin support:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin support which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support architecture uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements_(first_version)&amp;diff=3563</id>
		<title>Projects/Plugin support improvements (first version)</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements_(first_version)&amp;diff=3563"/>
				<updated>2010-08-03T18:54:45Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: Projects/Plugin support improvements moved to Projects/Plugin support improvements (first version)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{project-early}}&lt;br /&gt;
&lt;br /&gt;
==Motivation ==&lt;br /&gt;
&lt;br /&gt;
We set up our goal on creating a framework that &lt;br /&gt;
&lt;br /&gt;
* Separates plugin interface from its implementation;&lt;br /&gt;
* Provides simple and clear mechanism that facilitates additions of new plugin interfaces and their implementations(modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same plugin interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Structure==&lt;br /&gt;
[[Image:Slide1.jpg]]&lt;br /&gt;
&lt;br /&gt;
==Participants==&lt;br /&gt;
&lt;br /&gt;
* Plugin Manager ('''PM''') - Module that implements operations that  manage plugin configuration and registry services. PM is responsible  to maintain a container populated with plugin handles (references  to plugin objects) and provide the search capabilities for callers requesting the plugin services.  &lt;br /&gt;
* Plugin Loader ('''PL''') - Abstract module that declares an interface for operations that facilitate manipulation with the set of plugin implementations;&lt;br /&gt;
* Plugin Loader Implementation ('''PLI''') - Concrete implementation of PL. It knows about the set of the available implementations and how to create them;&lt;br /&gt;
* Plugin Interface ('''PI''')  - Abstract  module that declares plugin interface. &lt;br /&gt;
* Plugin Interface Implementation ('''PII''')  - Concrete implementation of the plugin interface;&lt;br /&gt;
* Caller - Plugin caller.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Collaboration==&lt;br /&gt;
&lt;br /&gt;
* An instance ''pl_manager'' of  PM is created as part of ''krb5_init_context'' operation at run-time (1). This instance will use PM methods to configure and register the desired plugin implementations;&lt;br /&gt;
* The list of the desired plugin implementations is known to the specific PLI which is aggregated within PM (2);&lt;br /&gt;
* PM delegates acquiring of plugin interfaces to PLI (3);&lt;br /&gt;
* The caller uses ''pl_manager'' to invoke the desired plugin interface (4).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==User Interface==&lt;br /&gt;
&lt;br /&gt;
; plugin_manager_get_service: - perform a search in the plugin manager registry to locate the particular interface based on plugin interface name and plugin id. If the search is successful, the plhandle structure gets populated with reference to the plugin interface and the function return code is set to success. Otherwise, this function returns an error;&lt;br /&gt;
; plugin_manager_configure: - parse a configuration file. Based on the obtained information construct plugin objects and load them into the plugin registry;&lt;br /&gt;
; plugin_manager_start: - complete necessary initializations of plugin objects and make them available for use;&lt;br /&gt;
; plugin_manager_stop: - free resources;&lt;br /&gt;
; plugin_manager_get_instance: - instantiate an instance of plugin manager if it does not exist.&lt;br /&gt;
; plugin_loader_create_api: - return the vtable with the implementation pertained to the specific interface;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Implementation==&lt;br /&gt;
&lt;br /&gt;
; MT safety :  Implementation must be MT safe.&lt;br /&gt;
&lt;br /&gt;
; Proof of concept code is available from ''plugins'' branch: ''svn+ssh://svn.mit.edu/krb5/branches/plugins''&lt;br /&gt;
&lt;br /&gt;
; k5-int.h: ''plugin_manager *pl_manager'' is added to _krb5_context;&lt;br /&gt;
&lt;br /&gt;
; PM: The purpose of PM  is to provide the configuration and registry services. In future the ability to have multiple implementations of the PM may be desired to allow one to have flexible configuration environment (For example, the configuration service can be implemented using various file formats or be completely hardcoded.) &lt;br /&gt;
; PM vs PLI: In general  PM is tied to one or more PLIs. In its turn, each PLI is responsible for loading one or more plugins. The notion of the multiple plugins per PLI is justified by the convenience of the grouping based on the plugin  functionality, level of optimization  or other features;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Consequences==&lt;br /&gt;
&lt;br /&gt;
The framework is designed to hide the management details, such as configuration and loading, from the plugin writers and callers.&lt;br /&gt;
&lt;br /&gt;
* The responsibility of the writer of the '''new plugin interface (PI)''' is limited to the writing source and header as described at Template_1:&lt;br /&gt;
&lt;br /&gt;
 ''Template 1''&lt;br /&gt;
 &lt;br /&gt;
 ''HEADER''&lt;br /&gt;
 #include &amp;lt;plugin_manager.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;k5-int.h&amp;gt;&lt;br /&gt;
 typedef struct {&lt;br /&gt;
                int version;&lt;br /&gt;
                char plugin_name[MAX_PL_NAME_LEN];&lt;br /&gt;
                krb5_error_code (*fn1)(...);&lt;br /&gt;
 } plugin_PLName;&lt;br /&gt;
 krb5_error_code plugin_PLName_fn1(plhandle handle, ...); &lt;br /&gt;
  &lt;br /&gt;
 ''SOURCE''&lt;br /&gt;
 krb5_error_code plugin_PLName_fn1(plhandle handle, ...)&lt;br /&gt;
 {&lt;br /&gt;
    plugin_PLName* api = (plugin_PLName*) handle.api;&lt;br /&gt;
    api-&amp;gt;plugin_PLName_fn1(...);&lt;br /&gt;
    return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* The responsibility of the writer of the '''new plugin interface implementation (PII)''' is limited to the writing source and header as described at Template_2 and the notifying the plugin loader about its availability Template_3:&lt;br /&gt;
&lt;br /&gt;
 ''Template 2''&lt;br /&gt;
 &lt;br /&gt;
 ''HEADER''&lt;br /&gt;
 plhandle plugin_pwd_qlty_krb_create(void);&lt;br /&gt;
 &lt;br /&gt;
 ''SOURCE''&lt;br /&gt;
 static krb5_error_code&lt;br /&gt;
 plugin_PLName_fn1(...)&lt;br /&gt;
 { /*intended functionality */}&lt;br /&gt;
  &lt;br /&gt;
 static void&lt;br /&gt;
 plugin_PLName_cleanup(...) &lt;br /&gt;
 { /* cleanup */ }&lt;br /&gt;
 &lt;br /&gt;
 static krb5_error_code&lt;br /&gt;
 plugin_PLName_init(...)&lt;br /&gt;
 { /* init */ } &lt;br /&gt;
 &lt;br /&gt;
 plhandle  plugin_PLName_PLImpl_create()&lt;br /&gt;
 {&lt;br /&gt;
    plhandle handle;;&lt;br /&gt;
    plugin_PLName* api = malloc(sizeof(plugin_PLName));&lt;br /&gt;
    api-&amp;gt;fn1 = plugin_PLName_fn1;&lt;br /&gt;
    api-&amp;gt;PLName_init = plugin_PLName_init;&lt;br /&gt;
    api-&amp;gt;PLName_cleanup = plugin_PLName_cleanup;&lt;br /&gt;
    handle.api = api;&lt;br /&gt;
    return handle;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 ''Template 3''&lt;br /&gt;
 &lt;br /&gt;
 static plugin_descr _table[] = {&lt;br /&gt;
    {&amp;quot;plugin_PLImpl_PLName&amp;quot;, plugin_PLName_PLImpl_create},&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
''For better readability some of the verification, clean-up, error handling code is omitted from the templates''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Built-in Plugins==&lt;br /&gt;
&lt;br /&gt;
*; Examples: PreAuth, AuthData, Password Quality (see ''Current plugins'' section for details)&lt;br /&gt;
&lt;br /&gt;
*; Invoking multiple implementations of the same plugin: This is achieved by using the aimed ''plugin_id'''s in ''plugin_manager_get_service'' calls. For example, two specific implementations of the password quality plugins may be invoked in password check. &lt;br /&gt;
&lt;br /&gt;
*; Invoking ''all available'' plugin implementations:  See also &amp;quot;Defaults&amp;quot; section&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Dynamic Plugins==&lt;br /&gt;
&lt;br /&gt;
*; Examples: Audit, Password sync&lt;br /&gt;
&lt;br /&gt;
*; Requirements: &lt;br /&gt;
&lt;br /&gt;
# The difference between dynamic and built-in plugins (both interface and implementation) should be on the level of linkage. &lt;br /&gt;
# Plugin consumer should not have the knowledge about the type of plugins  it is using (in terms of dynamic/built-in). On the caller side  the code invoking plugin should stay the same for both dynamic and built-in plugins.&lt;br /&gt;
# Similar to built-in plugins, the plugin consumer may call the multiple implementations of the same plugin interface. For example, two implementations of the audit plugin interface may be used to handle password change and intruder lockout events.&lt;br /&gt;
# Similar to built-in plugins, one can choose to use ''all available'' plugin implementations. Their location may be some default one, or passed via env variable, or defined in the configuration.&lt;br /&gt;
# In the case one wants to have better control over the configuration and management of the plugins selection, it  responsibility of the administrator to point to the location of the dynamic plugin as part of the configuration.&lt;br /&gt;
&lt;br /&gt;
*; Creating dynamic plugin: The appropriate loader is linked with the set of the desired plugins resulting into the shared library. Details:&lt;br /&gt;
# One of the deliverables of the plugin framework is the loader file. Its responsibility is to load  modules that are listed in its local table (see  below). ;&lt;br /&gt;
# The dynamic plugin creator must fill this table with the list of the desired pluginmodules. &lt;br /&gt;
# The dynamic plugin creator then links the loader with the set of the desired plugin modules resulting into the shared library;&lt;br /&gt;
# Administrator points to the location of the dynamic plugin by setting ''plugin_loader_path'' configuration attribute to this library.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 NOTE: This approach allows to bundle dynamic plugins. &lt;br /&gt;
       It also hides loading details from the plugin writer making code for dynamic and built-in plugin indistinguishable. &lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
''The following is the example of how the table in the loader may look:''&lt;br /&gt;
  static plugin_descr  plugin_dyn_factory_table[] = {&lt;br /&gt;
    {&amp;quot;plugin_pwd_qlty_DYN&amp;quot;,   plugin_pwd_qlty_DYN_create},&lt;br /&gt;
    {&amp;quot;plugin_pwd_qlty_XYZ&amp;quot;,   plugin_pwd_qlty_XYZ_create},&lt;br /&gt;
    {NULL,NULL}&lt;br /&gt;
 };&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*; Invoking dynamic plugin:  Similar to  builtin plugins with the following additions. The option ''plugin_loader_path'' in the configuration file refers to the location of the dynamic plugin shared library and the option ''plugin_loader_type'' must be set to ''dynamic''. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Configuration==&lt;br /&gt;
If no plugin configuration is provided  the new plugin framework should act upon some default behavior. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*; '''Configuration file attributes'''&lt;br /&gt;
:: ''plugin list'' -   list of the desired plugins;&lt;br /&gt;
:: ''plugin_api'' -   name of the plugin interface;&lt;br /&gt;
:: ''plugin_name'' -   concrete plugin implementation;&lt;br /&gt;
:: ''plugin_version'' -   desired version of plugin implementation; This may be used by the administrator to point to the most recent plugin implementation (perhaps, bug fix).  &lt;br /&gt;
:: ''plugin_loader_name'' -   name of the loader the particular implementation is associated with;&lt;br /&gt;
:: ''plugin_loader_type'' -   defines the plugin type:  built-in or dynamic; &lt;br /&gt;
:: ''plugin_loader_path'' -   path to the plugin dynamic library&lt;br /&gt;
:: ''plugin_disable'' -   don't use this plugin implementation &lt;br /&gt;
:: ''plugin_properties'' -   plugin implementation initialization parameters (when needed) &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*; '''Example of the plugin section in krb5.conf'''&lt;br /&gt;
 [plugins]&lt;br /&gt;
        /* By default, all built-in plugin impls are enabled. To disable a particular built-in plugin one need to specify it */&lt;br /&gt;
        plugin_list = PQ1&lt;br /&gt;
        PQ1 = {&lt;br /&gt;
                plugin_api = plugin_pwd_qlty        &lt;br /&gt;
                plugin_name = plugin_pwd_qlty_krb   &lt;br /&gt;
                plugin_disable = yes&lt;br /&gt;
        }&lt;br /&gt;
       &lt;br /&gt;
        /* dynamic plugin */&lt;br /&gt;
        plugin_list = PQ_DYN&lt;br /&gt;
        PQ_DYN = {&lt;br /&gt;
               plugin_api = plugin_pwd_qlty&lt;br /&gt;
               plugin_name = plugin_pwd_qlty_DYN&lt;br /&gt;
               plugin_loader_type = dynamic&lt;br /&gt;
               plugin_loader_path = /path-to-the-lib/libplugin_dynamic.so   # if default, may be omitted&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*; '''Alternatives'''&lt;br /&gt;
The choice of plugin configuration format is a matter of preference. It may be presented in  XML, YAML, JSON etc. One needs only an appropriate parser. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*; '''Configuration change at run-time'''&lt;br /&gt;
TBD&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Directory Structure==&lt;br /&gt;
&lt;br /&gt;
*; src/plugin_core:  plugin_manager.[ch], plugin_loader.[ch], impl/plugin_XXX_manager.[ch],  impl/plugin_XXX_loader.[ch]&lt;br /&gt;
&lt;br /&gt;
*; src/plugins:  pluginA/plugin_A.[ch], pluginA/plugin_A_implN/plugin_A_implN.[ch]&lt;br /&gt;
&lt;br /&gt;
*; src/plugin_dynamic: plugin_dyn_factory.[ch]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Defaults==&lt;br /&gt;
If no plugin configuration is provided new plugin framework should act upon some default behavior. &lt;br /&gt;
&lt;br /&gt;
There are two default loaders. &lt;br /&gt;
The first loader aggregates built-in plugin implementations, while the second one -  dynamically loadable ones located in some default directory.  If the administrator wishes to have all of these plugin implementations available and they need no additional configuration (for example, for their initialization), the configuration file may not have any plugin related information. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Build process==&lt;br /&gt;
&lt;br /&gt;
*; Options: DEBUG_PLUGINS - output more info for debugging&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Sample Code==&lt;br /&gt;
&lt;br /&gt;
*; Plugin initialization&lt;br /&gt;
The following is an example of the plugin manager initialization:&lt;br /&gt;
 &lt;br /&gt;
 plugin_manager_get_instance(&amp;amp;ctx-&amp;gt;pl_manager);&lt;br /&gt;
 plugin_manager_configure(ctx-&amp;gt;pl_manager, conf_path);&lt;br /&gt;
 plugin_manager_start(ctx-&amp;gt;pl_manager);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*; How to call plugins&lt;br /&gt;
The following is an example of invoking Password Quality plugin:   &lt;br /&gt;
&lt;br /&gt;
 plugin_manager_get_service(ctx-&amp;gt;pl_manager, PWD_QLTY, PWD_QLTY_KRB, &amp;amp;plugin_handle);&lt;br /&gt;
 plugin_pwd_qlty_check(plugin_handle, srv_handle, password, use_policy, pol, principal);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*;How to construct plugin interface (PI)&lt;br /&gt;
The following is an example of how plugin interface called &amp;quot;password quality&amp;quot; may look:&lt;br /&gt;
&lt;br /&gt;
 #ifndef PLUGIN_PWD_QLTY_H_&lt;br /&gt;
 #define PLUGIN_PWD_QLTY_H_&lt;br /&gt;
 &lt;br /&gt;
 typedef struct {&lt;br /&gt;
        int version;&lt;br /&gt;
        char plugin_id[MAX_PL_NAME_LEN];&lt;br /&gt;
        kadm5_ret_t (*pwd_qlty_init)(kadm5_server_handle_t);&lt;br /&gt;
        void (*pwd_qlty_cleanup)();&lt;br /&gt;
        kadm5_ret_t (*pwd_qlty_check)(kadm5_server_handle_t, char*,  int, kadm5_policy_ent_t, krb5_principal);&lt;br /&gt;
 } plugin_pwd_qlty;&lt;br /&gt;
 &lt;br /&gt;
 kadm5_ret_t plugin_pwd_qlty_init(plhandle, kadm5_server_handle_t);&lt;br /&gt;
 kadm5_ret_t plugin_pwd_qlty_cleanup(plhandle);&lt;br /&gt;
 kadm5_ret_t plugin_pwd_qlty_check(plhandle, kadm5_server_handle_t, char*, int,  kadm5_policy_ent_t, krb5_principal);&lt;br /&gt;
 &lt;br /&gt;
 #endif /* PLUGIN_PWD_QLTY_H_ */&lt;br /&gt;
  &lt;br /&gt;
 &lt;br /&gt;
 ''SOURCE'' &lt;br /&gt;
 kadm5_ret_t &lt;br /&gt;
 plugin_pwd_qlty_check( plhandle handle, kadm5_server_handle_t srv_handle, char *password, int use_policy, kadm5_policy_ent_t pol, krb5_principal principal) &lt;br /&gt;
 {&lt;br /&gt;
    plugin_pwd_qlty* api = (plugin_pwd_qlty*) handle.api;&lt;br /&gt;
    api-&amp;gt;pwd_qlty_check(srv_handle, password, use_policy, pol, principal);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 kadm5_ret_t&lt;br /&gt;
 plugin_pwd_qlty_init(plhandle, kadm5_server_handle_t)&lt;br /&gt;
 { /*  init */ } &lt;br /&gt;
 &lt;br /&gt;
 void&lt;br /&gt;
 plugin_pwd_qlty_cleanup(plhandle) &lt;br /&gt;
 { /* clean-up */ } &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*; How to construct plugin interface implementation (PII)&lt;br /&gt;
Every PII should have only one public ''create'' function.  For PII called &amp;quot;password quality krb&amp;quot; it would be ''plhandle plugin_pwd_qlty_krb_create()''.The following is an example of the this PII:&lt;br /&gt;
&lt;br /&gt;
 #ifndef PLUGIN_PWD_QLTY_KRB_IMPL_H_&lt;br /&gt;
 #define PLUGIN_PWD_QLTY_KRB_IMPL_H_&lt;br /&gt;
 &lt;br /&gt;
 plhandle plugin_pwd_qlty_krb_create(void);&lt;br /&gt;
 &lt;br /&gt;
 #endif /* PLUGIN_PWD_QLTY_KRB_IMPL_H_ */&lt;br /&gt;
  &lt;br /&gt;
 &lt;br /&gt;
 ''SOURCE''&lt;br /&gt;
 plhandle plugin_pwd_qlty_krb_create()&lt;br /&gt;
 {&lt;br /&gt;
    plhandle handle;&lt;br /&gt;
    ...&lt;br /&gt;
    api-&amp;gt;pwd_qlty_init    = plugin_pwd_qlty_init;&lt;br /&gt;
    api-&amp;gt;pwd_qlty_check   = plugin_pwd_qlty_check;&lt;br /&gt;
    api-&amp;gt;pwd_qlty_cleanup = plugin_pwd_qlty_clean;&lt;br /&gt;
    handle.api = api;&lt;br /&gt;
    return handle;&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 static kadm5_ret_t &lt;br /&gt;
 plugin_pwd_qlty_check(kadm5_server_handle_t srv_handle, char *password, int use_policy, kadm5_policy_ent_t pol, krb5_principal principal)&lt;br /&gt;
 { /* do some quality verification */ }&lt;br /&gt;
  &lt;br /&gt;
 static  kadm5_ret_t  &lt;br /&gt;
 plugin_pwd_qlty_init(kadm5_server_handle_t handle)&lt;br /&gt;
 { /* initialization */ } &lt;br /&gt;
  &lt;br /&gt;
 static kadm5_ret_t   &lt;br /&gt;
 plugin_pwd_qlty_cleanup()&lt;br /&gt;
 { /* cleanup */ } &lt;br /&gt;
&lt;br /&gt;
''For better readability some of the verification, clean-up, error handling code is omitted from the samples''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Current plugins==&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Future plugins==&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
==Current support infrastructure==&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
==Problem areas==&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were. (Dependent library shared objects of the calling library can contain &amp;quot;built-in&amp;quot; modules for the calling library.)  The distinguishing feature of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3562</id>
		<title>Projects/Plugin Support</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3562"/>
				<updated>2010-08-03T18:49:39Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Original Proposal: [[projects/Plugin_support_improvements]].&lt;br /&gt;
* Revised Proposal [[http://k5wiki.kerberos.org/wiki/User:Hardjono/Plugin_Support]]&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3561</id>
		<title>Projects/Plugin Support</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3561"/>
				<updated>2010-08-03T18:49:12Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Original Proposal: [[Plugin_support_improvements]].&lt;br /&gt;
* Revised Proposal [[http://k5wiki.kerberos.org/wiki/User:Hardjono/Plugin_Support]]&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3560</id>
		<title>Projects/Plugin Support</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3560"/>
				<updated>2010-08-03T18:40:13Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Original Proposal: [[http://k5wiki.kerberos.org/wiki/Projects/Plugin_support_improvements]].&lt;br /&gt;
* Revised Proposal [[http://k5wiki.kerberos.org/wiki/User:Hardjono/Plugin_Support]]&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3559</id>
		<title>Projects/Plugin Support</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3559"/>
				<updated>2010-08-03T18:38:13Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Original Proposal: [[http://k5wiki.kerberos.org/wiki/Projects/Plugin_support_improvements]].&lt;br /&gt;
* Revised Proposal.&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3558</id>
		<title>Projects/Plugin Support</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3558"/>
				<updated>2010-08-03T18:35:48Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[Original Proposal]].&lt;br /&gt;
* Revised Proposal.&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3557</id>
		<title>Projects/Plugin Support</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3557"/>
				<updated>2010-08-03T18:34:28Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* Original Proposal&lt;br /&gt;
* Revised Proposal.&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3556</id>
		<title>Projects/Plugin Support</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3556"/>
				<updated>2010-08-03T18:34:05Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [Original Proposal] http://k5wiki.kerberos.org/wiki/Projects/Plugin_support_improvements.&lt;br /&gt;
* Revised Proposal.&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3555</id>
		<title>Projects/Plugin Support</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3555"/>
				<updated>2010-08-03T18:33:53Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [Original Proposal]http://k5wiki.kerberos.org/wiki/Projects/Plugin_support_improvements.&lt;br /&gt;
* Revised Proposal.&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3554</id>
		<title>Projects/Plugin Support</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_Support&amp;diff=3554"/>
				<updated>2010-08-03T18:32:23Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: New page:  * Original Proposal. * Revised Proposal.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
* Original Proposal.&lt;br /&gt;
* Revised Proposal.&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3553</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3553"/>
				<updated>2010-08-03T18:28:00Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Background */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
* Project inception:  Zhanna Tsitkova.&lt;br /&gt;
* Further revision: Greg Hudson and Tom Yu.&lt;br /&gt;
&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin manager uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin manager to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The architecture is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin support:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin support:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin support which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support architecture uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3552</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3552"/>
				<updated>2010-08-03T18:26:50Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Motivations, Priorities &amp;amp; Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin manager uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin manager to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The architecture is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin support:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin support:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin support which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support architecture uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3550</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3550"/>
				<updated>2010-07-28T18:55:04Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Definitions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin manager uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin manager to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The architecture is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin support:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin support:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin support which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support architecture uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3549</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3549"/>
				<updated>2010-07-28T18:54:38Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Current plugins */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin manager uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin manager to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The architecture is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin support:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin support:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin support which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3548</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3548"/>
				<updated>2010-07-28T18:53:28Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Deliverables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin manager uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin manager to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The architecture is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3547</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3547"/>
				<updated>2010-07-28T18:52:55Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Code and Proof of Concept */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin manager uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin manager to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3546</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3546"/>
				<updated>2010-07-28T18:52:19Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Provider interface */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin manager uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3545</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3545"/>
				<updated>2010-07-28T18:51:57Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Consumer interface */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin manager.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3544</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3544"/>
				<updated>2010-07-28T18:51:01Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Motivations, Priorities &amp;amp; Requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture:&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the architecture to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new architecture.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3543</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3543"/>
				<updated>2010-07-28T18:49:58Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Function signatures */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
:k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
: k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
: k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3542</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3542"/>
				<updated>2010-07-28T18:49:23Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:  [plugins]&lt;br /&gt;
:  interfacename = {&lt;br /&gt;
::    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
::    enable_only = name&lt;br /&gt;
: &lt;br /&gt;
::    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
::    disable = name&lt;br /&gt;
: &lt;br /&gt;
::    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
::    module = modname:pathname&lt;br /&gt;
:   }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3541</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3541"/>
				<updated>2010-07-28T18:48:19Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Code and Proof of Concept */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
  [plugins]&lt;br /&gt;
  interfacename = {&lt;br /&gt;
    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
    enable_only = name&lt;br /&gt;
&lt;br /&gt;
    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
    disable = name&lt;br /&gt;
&lt;br /&gt;
    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
    module = modname:pathname&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3540</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3540"/>
				<updated>2010-07-28T18:47:13Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Code and Proof of Concept */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
  [plugins]&lt;br /&gt;
  interfacename = {&lt;br /&gt;
    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
    enable_only = name&lt;br /&gt;
&lt;br /&gt;
    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
    disable = name&lt;br /&gt;
&lt;br /&gt;
    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
    module = modname:pathname&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
:    /* Allocate a large enough list of handles. */&lt;br /&gt;
:    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
:    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
:    if (list == NULL)&lt;br /&gt;
::        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
:    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
:     * modules which don't successfully initialize. */&lt;br /&gt;
:    count = 0;&lt;br /&gt;
:    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
::        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
::        if (handle == NULL)&lt;br /&gt;
:::            goto cleanup;&lt;br /&gt;
::        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
::        if (ret == 0)&lt;br /&gt;
:::            list[count++] = handle;&lt;br /&gt;
::        else&lt;br /&gt;
:::            free(handle);&lt;br /&gt;
:    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3539</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3539"/>
				<updated>2010-07-28T18:45:07Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Code and Proof of Concept */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
  [plugins]&lt;br /&gt;
  interfacename = {&lt;br /&gt;
    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
    enable_only = name&lt;br /&gt;
&lt;br /&gt;
    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
    disable = name&lt;br /&gt;
&lt;br /&gt;
    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
    module = modname:pathname&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
:    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
:    if (ret != 0)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* Allocate a large enough list of handles. */&lt;br /&gt;
    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
    if (list == NULL)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
     * modules which don't successfully initialize. */&lt;br /&gt;
    count = 0;&lt;br /&gt;
    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
        if (handle == NULL)&lt;br /&gt;
            goto cleanup;&lt;br /&gt;
        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
        if (ret == 0)&lt;br /&gt;
            list[count++] = handle;&lt;br /&gt;
        else&lt;br /&gt;
            free(handle);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3538</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3538"/>
				<updated>2010-07-28T18:44:25Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Code and Proof of Concept */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
  [plugins]&lt;br /&gt;
  interfacename = {&lt;br /&gt;
    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
    enable_only = name&lt;br /&gt;
&lt;br /&gt;
    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
    disable = name&lt;br /&gt;
&lt;br /&gt;
    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
    module = modname:pathname&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
:: }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&lt;br /&gt;
    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* Allocate a large enough list of handles. */&lt;br /&gt;
    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
    if (list == NULL)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
     * modules which don't successfully initialize. */&lt;br /&gt;
    count = 0;&lt;br /&gt;
    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
        if (handle == NULL)&lt;br /&gt;
            goto cleanup;&lt;br /&gt;
        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
        if (ret == 0)&lt;br /&gt;
            list[count++] = handle;&lt;br /&gt;
        else&lt;br /&gt;
            free(handle);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3537</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3537"/>
				<updated>2010-07-28T18:44:07Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Code and Proof of Concept */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
  [plugins]&lt;br /&gt;
  interfacename = {&lt;br /&gt;
    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
    enable_only = name&lt;br /&gt;
&lt;br /&gt;
    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
    disable = name&lt;br /&gt;
&lt;br /&gt;
    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
    module = modname:pathname&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
:: ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&lt;br /&gt;
    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* Allocate a large enough list of handles. */&lt;br /&gt;
    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
    if (list == NULL)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
     * modules which don't successfully initialize. */&lt;br /&gt;
    count = 0;&lt;br /&gt;
    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
        if (handle == NULL)&lt;br /&gt;
            goto cleanup;&lt;br /&gt;
        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
        if (ret == 0)&lt;br /&gt;
            list[count++] = handle;&lt;br /&gt;
        else&lt;br /&gt;
            free(handle);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3536</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3536"/>
				<updated>2010-07-28T18:43:20Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Code and Proof of Concept */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
  [plugins]&lt;br /&gt;
  interfacename = {&lt;br /&gt;
    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
    enable_only = name&lt;br /&gt;
&lt;br /&gt;
    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
    disable = name&lt;br /&gt;
&lt;br /&gt;
    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
    module = modname:pathname&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
    for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
	ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
	if (ret != 0)&lt;br /&gt;
            return ret;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&lt;br /&gt;
    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* Allocate a large enough list of handles. */&lt;br /&gt;
    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
    if (list == NULL)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
     * modules which don't successfully initialize. */&lt;br /&gt;
    count = 0;&lt;br /&gt;
    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
        if (handle == NULL)&lt;br /&gt;
            goto cleanup;&lt;br /&gt;
        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
        if (ret == 0)&lt;br /&gt;
            list[count++] = handle;&lt;br /&gt;
        else&lt;br /&gt;
            free(handle);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3535</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3535"/>
				<updated>2010-07-28T18:42:10Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Code and Proof of Concept */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
  [plugins]&lt;br /&gt;
  interfacename = {&lt;br /&gt;
    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
    enable_only = name&lt;br /&gt;
&lt;br /&gt;
    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
    disable = name&lt;br /&gt;
&lt;br /&gt;
    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
    module = modname:pathname&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&lt;br /&gt;
: ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL, &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
:: if (ret != 0)&lt;br /&gt;
::: return ret;&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
    ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        return ret;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
    for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
	ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
	if (ret != 0)&lt;br /&gt;
            return ret;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&lt;br /&gt;
    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* Allocate a large enough list of handles. */&lt;br /&gt;
    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
    if (list == NULL)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
     * modules which don't successfully initialize. */&lt;br /&gt;
    count = 0;&lt;br /&gt;
    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
        if (handle == NULL)&lt;br /&gt;
            goto cleanup;&lt;br /&gt;
        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
        if (ret == 0)&lt;br /&gt;
            list[count++] = handle;&lt;br /&gt;
        else&lt;br /&gt;
            free(handle);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3534</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3534"/>
				<updated>2010-07-28T18:39:59Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Code and Proof of Concept */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
  [plugins]&lt;br /&gt;
  interfacename = {&lt;br /&gt;
    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
    enable_only = name&lt;br /&gt;
&lt;br /&gt;
    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
    disable = name&lt;br /&gt;
&lt;br /&gt;
    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
    module = modname:pathname&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;svn://anonsvn.mit.edu/krb5/branches/plugins2&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
    ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL,&lt;br /&gt;
                             &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        return ret;&lt;br /&gt;
&lt;br /&gt;
    ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL,&lt;br /&gt;
                             &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        return ret;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
    ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        return ret;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
    for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
	ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
	if (ret != 0)&lt;br /&gt;
            return ret;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&lt;br /&gt;
    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* Allocate a large enough list of handles. */&lt;br /&gt;
    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
    if (list == NULL)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
     * modules which don't successfully initialize. */&lt;br /&gt;
    count = 0;&lt;br /&gt;
    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
        if (handle == NULL)&lt;br /&gt;
            goto cleanup;&lt;br /&gt;
        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
        if (ret == 0)&lt;br /&gt;
            list[count++] = handle;&lt;br /&gt;
        else&lt;br /&gt;
            free(handle);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3533</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3533"/>
				<updated>2010-07-28T18:39:05Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Code and Proof of Concept */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
  [plugins]&lt;br /&gt;
  interfacename = {&lt;br /&gt;
    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
    enable_only = name&lt;br /&gt;
&lt;br /&gt;
    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
    disable = name&lt;br /&gt;
&lt;br /&gt;
    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
    module = modname:pathname&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;&lt;br /&gt;
The Subversion URL for the proof of concept is:&lt;br /&gt;
&lt;br /&gt;
  svn://anonsvn.mit.edu/krb5/branches/plugins2&lt;br /&gt;
&lt;br /&gt;
There is a README.BRANCH file as the top level containing a walkthrough of the changes on the branch.&lt;br /&gt;
&lt;br /&gt;
This is a consumer registering built-in plugin modules for the password quality interface:&lt;br /&gt;
&lt;br /&gt;
    ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL,&lt;br /&gt;
                             &amp;quot;dict&amp;quot;, pwqual_dict_init);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        return ret;&lt;br /&gt;
&lt;br /&gt;
    ret = k5_plugin_register(context, PLUGIN_INTERFACE_PWQUAL,&lt;br /&gt;
                             &amp;quot;policy&amp;quot;, pwqual_policy_init);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        return ret;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to create a list of handles for all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
    ret = k5_pwqual_load(handle-&amp;gt;context, &amp;amp;list);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        return ret;&lt;br /&gt;
&lt;br /&gt;
This is a consumer using the pwqual consumer API to check a password against all available password quality modules:&lt;br /&gt;
&lt;br /&gt;
    for (h = handle-&amp;gt;qual_handles; *h != NULL; h++) {&lt;br /&gt;
	ret = k5_pwqual_check(handle-&amp;gt;context, *h, password, policy, princ);&lt;br /&gt;
	if (ret != 0)&lt;br /&gt;
            return ret;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
This is the password quality loader function invoking the plugin framework to get a list of all available password quality vtable constructors, and then invoking the vtable constructors to create plugin&lt;br /&gt;
handles:&lt;br /&gt;
&lt;br /&gt;
    ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_PWQUAL, &amp;amp;modules);&lt;br /&gt;
    if (ret != 0)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* Allocate a large enough list of handles. */&lt;br /&gt;
    for (count = 0; modules[count] != NULL; count++);&lt;br /&gt;
    list = k5alloc((count + 1) * sizeof(*list), &amp;amp;ret);&lt;br /&gt;
    if (list == NULL)&lt;br /&gt;
        goto cleanup;&lt;br /&gt;
&lt;br /&gt;
    /* For each module, allocate a handle and initialize its vtable.  Skip      &lt;br /&gt;
     * modules which don't successfully initialize. */&lt;br /&gt;
    count = 0;&lt;br /&gt;
    for (mod = modules; *mod != NULL; mod++) {&lt;br /&gt;
        handle = k5alloc(sizeof(*handle), &amp;amp;ret);&lt;br /&gt;
        if (handle == NULL)&lt;br /&gt;
            goto cleanup;&lt;br /&gt;
        ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&amp;amp;handle-&amp;gt;vt);&lt;br /&gt;
        if (ret == 0)&lt;br /&gt;
            list[count++] = handle;&lt;br /&gt;
        else&lt;br /&gt;
            free(handle);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3532</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3532"/>
				<updated>2010-07-28T18:37:28Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
Here is a description of the configuration used by the proof of concept:&lt;br /&gt;
&lt;br /&gt;
  [plugins]&lt;br /&gt;
  interfacename = {&lt;br /&gt;
    # May take multiple values; only named plugins will be enabled.&lt;br /&gt;
    enable_only = name&lt;br /&gt;
&lt;br /&gt;
    # May take multiple values; named plugins will be disabled.&lt;br /&gt;
    disable = name&lt;br /&gt;
&lt;br /&gt;
    # Establishes a mapping from a module name to a dynamic object.&lt;br /&gt;
    module = modname:pathname&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3531</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3531"/>
				<updated>2010-07-28T18:36:07Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Sample Code and Proof of Concept */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
=== Code and Proof of Concept ===&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3530</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3530"/>
				<updated>2010-07-28T18:35:32Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3529</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3529"/>
				<updated>2010-07-28T18:33:29Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Function signatures */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id, krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname, krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	<entry>
		<id>https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3528</id>
		<title>Projects/Plugin support improvements</title>
		<link rel="alternate" type="text/html" href="https://k5wiki.kerberos.org/wiki?title=Projects/Plugin_support_improvements&amp;diff=3528"/>
				<updated>2010-07-28T18:32:52Z</updated>
		
		<summary type="html">&lt;p&gt;Hardjono: /* Function signatures */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Motivations, Priorities &amp;amp; Requirements ==&lt;br /&gt;
&lt;br /&gt;
'''Motivations''': there are a number of motivations behind the creation of the plugin architecture framework.&lt;br /&gt;
&lt;br /&gt;
* Desire to separate pluggable interface from its implementation;&lt;br /&gt;
* Desire to provide simple and clear mechanism that facilitates additions of new pluggable interfaces and their implementations (modules);&lt;br /&gt;
* Handles both built-in and dynamic plugin modules;&lt;br /&gt;
* Allows multiple implementation of the same pluggable interface;&lt;br /&gt;
* Provides uniform way to supply parameters for plugin configuration;&lt;br /&gt;
* Allows one plugin implementation (module) to use services provided by the other plugin implementations.&lt;br /&gt;
&lt;br /&gt;
'''Requirements''': from these items we have developed a more formal set of requirements&lt;br /&gt;
covering the design and the implementation of the framework to&lt;br /&gt;
support the plugins. These are as follows:&lt;br /&gt;
&lt;br /&gt;
# Allow third parties to implement multiple plugin modules for each pluggable interface.&lt;br /&gt;
# Allow a plugin module to build as dynamic or built-in from the same source code.&lt;br /&gt;
# Allow third parties to more easily create new plugin modules.&lt;br /&gt;
# Provide a uniform method for configuring discovery of plugin modules.&lt;br /&gt;
# Improve readability of code that calls pluggable interfaces.&lt;br /&gt;
# Allow easier creation of new pluggable interfaces.&lt;br /&gt;
# Allow incremental transition of existing pluggable interfaces to the new framework.&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview and Concepts ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
The architecture for the plugin support is shown in the following figure.&lt;br /&gt;
The participants and components are described in the section below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:plugin_architecture_v3_png.png]]&lt;br /&gt;
&lt;br /&gt;
=== Participants ===&lt;br /&gt;
&lt;br /&gt;
The following is a summary of participants and components&lt;br /&gt;
within the architecture. Further details are provided in the sections below.&lt;br /&gt;
&lt;br /&gt;
'''Plugin Manager''': The plugin manager provides a set of generic capabilities that are independent of individual plugin interfaces. The plugin manager implements operations that manage plugin configuration and plugin registry services.&lt;br /&gt;
&lt;br /&gt;
'''Pluggable Interface''': A pluggable interface is an interface that can be implemented by a third party in a modular manner. An implementation of  a pluggable interface is referred to as  a ''plugin module''. Furthermore, a pluggable interface itself consist of a ''consumer interface'' and ''provider interface'' (see below).&lt;br /&gt;
&lt;br /&gt;
'''Plugin Module''': A plugin module is an implementation of a pluggable interface. For example, in the Figure Plugin_A is shown to have two implementations (modules).&lt;br /&gt;
&lt;br /&gt;
'''Consumer''': The consumer or caller is the entity that uses the plugin module.&lt;br /&gt;
&lt;br /&gt;
=== Collaboration: Flows ===&lt;br /&gt;
&lt;br /&gt;
As shown in the above Figure,&lt;br /&gt;
the plugin architecture is designed based on the notion&lt;br /&gt;
of pluggable interfaces, each of which are defined based on an abstract design.&lt;br /&gt;
&lt;br /&gt;
When a third party wishes to develop a loadable plugin module&lt;br /&gt;
(e.g. Plugin_Module_A1)&lt;br /&gt;
that implements a specific task (e.g. implement password&lt;br /&gt;
quality check), the developer of the module must&lt;br /&gt;
conform to the pluggable interface (Pluggable Interface A) defined for that&lt;br /&gt;
&amp;quot;family&amp;quot; of plugin modules.&lt;br /&gt;
&lt;br /&gt;
The consumer (or caller) that later makes use of the plugin module,&lt;br /&gt;
must invoke functions implemented in that module&lt;br /&gt;
through a specific consumer interface (Consumer_Interface_A).&lt;br /&gt;
Discovery (and filtering) is triggered by the first load operation (within a krb5_context).&lt;br /&gt;
&lt;br /&gt;
== Architecture Components ==&lt;br /&gt;
&lt;br /&gt;
In this section we provide further details on the components&lt;br /&gt;
of the architecture, describing its features and behaviors.&lt;br /&gt;
&lt;br /&gt;
=== Plugin Manager ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The plugin manager provides a set of generic support capabilities that are independent of individual pluggable interfaces. It centralizes the discovery process for plugin modules.  Typically, consumers of pluggable interfaces do not call it directly. Instead a consumer calls a loader function (of the specific pluggable interface) which in-turn calls the plugin manager.&lt;br /&gt;
&lt;br /&gt;
In this architecture, the &amp;lt;code&amp;gt;krb5_init_context()&amp;lt;/code&amp;gt; functions will create and configure a plugin manager context that will exist in the krb5_context.  &lt;br /&gt;
&lt;br /&gt;
The plugin manager locates plugin modules using both a ''numeric identifier'' (that designates a plugin interface) and a ''string'' (that names a module which implements that pluggable interface).  The primary way to use the plugin manager is to query it for the vtable constructor for a specified module (or a set of vtable constructors for all modules of that interface).&lt;br /&gt;
&lt;br /&gt;
The plugin manager keeps track of modules through its registries. These are discussed as follows.&lt;br /&gt;
&lt;br /&gt;
==== Registry of built-in modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of built-in modules.  Typically, libkrb5 will initialize this with locators for all of the built-in modules that are linked into it.  Other code units can also register private built-in plugin modules using this registry.&lt;br /&gt;
&lt;br /&gt;
==== Registry of loadable modules ====&lt;br /&gt;
&lt;br /&gt;
This registry keeps track of a few additional items needed for loadable modules:&lt;br /&gt;
&lt;br /&gt;
* Each interface's registry starts out empty.&lt;br /&gt;
&lt;br /&gt;
* The consumer (typically) populates the registry by registering vtable constructors for built-in modules.&lt;br /&gt;
&lt;br /&gt;
* When k5_plugin_load() is invoked on an interface for the first time, discovery is performed.  This has two steps:&lt;br /&gt;
&lt;br /&gt;
** Dynamic module mappings are read from the profile.  Each named dynamic module is dlopened and dlsym'd to obtain the vtable constructor, and that constructor is added to the interface registry.&lt;br /&gt;
&lt;br /&gt;
** Enable/disable information is read from the profile.  The interface registry is pruned to contain only enabled modules.&lt;br /&gt;
&lt;br /&gt;
* Thereafter, the interface's registry is unchanging.&lt;br /&gt;
&lt;br /&gt;
=== Pluggable Interfaces ===&lt;br /&gt;
&lt;br /&gt;
A pluggable interface is an interface (possibly internal to a library) that can be implemented by a third party in a modular, well-compartmentalized manner.  These implementations of pluggable interfaces are called plugin modules. Pluggable interfaces allow a consumer to use the capabilities of the interface without needing to be aware of the implementation details.  In particular, a pluggable interface prevents the consumer from needing to know whether the module is a built-in or a dynamically loadable module.  &lt;br /&gt;
&lt;br /&gt;
Pluggable interfaces can be one-to-one, or one-to-many.  An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
A pluggable interface has two parts: a ''consumer interface'' and a ''provider interface''.  Typically, library code implements the consumer interface, and application code or other library code calls the functions of the consumer interface.&lt;br /&gt;
&lt;br /&gt;
==== Consumer interface ====&lt;br /&gt;
&lt;br /&gt;
The consumer interface isolates the consumer from implementation details of the pluggable interface.  The consumer does not generally need to know about whether a given module is built-in or dynamically loaded.  The implementation of a consumer interface is essentially a glue layer, and can make use of domain-independent (not specific to any pluggable interface) capabilities of the plugin framework.  The consumer might explicitly register a new plugin module that it implements: this capability is part of the plugin manager.&lt;br /&gt;
&lt;br /&gt;
A consumer of a pluggable interface uses an opaque handle (obtained from a loader function that is part of the pluggable interface) to call the methods of a plugin module.  Each handle represents one plugin module, and perhaps associated resource information.  For one-to-many pluggable interfaces, the loader function will return a list of handles.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Each method of the consumer interface is an ordinary C function that takes the opaque handle either explicitly as its first argument or implicitly by some means such as a module name.  In essence, these pluggable interface functions in the architecture are wrapper functions that call through function pointers contained in the opaque plugin module handle object.&lt;br /&gt;
&lt;br /&gt;
One rationale for using wrapper functions instead of having the consumer directly invoke methods through a function pointer is to make it easier for debuggers and analysis tools to recognize when a particular interface method is being called. (Function pointers might have identifier names that look nothing like the actual name of the function they point to, in addition to enabling confusing aliasing.)&lt;br /&gt;
&lt;br /&gt;
The loader function is specific to the pluggable interface.  One reason is for type safety: there will be a distinct opaque handle type for each pluggable interface, allowing compile-time checking to catch some sorts of programming errors.  Another reason is backward compatibility: it allows a pluggable interface to support plugin modules that implement an older provider interface.&lt;br /&gt;
&lt;br /&gt;
==== Provider interface ====&lt;br /&gt;
&lt;br /&gt;
A plugin module is a unit of code that implements (among others) the provider interface portion of a pluggable interface.  Plugin modules can be built in or dynamically loaded.  Several alternatives exist for the form of the provider interface, but some have significant advantages in allowing the plugin module to use identical source code for both built-in and loadable modules.&lt;br /&gt;
&lt;br /&gt;
A built-in module is a module whose implementation is already available within the consumer's symbol namespace at the time of module discovery.  This typically means a module whose implementation is part of the same code unit as the consumer, though it could also mean a module which was registered by some other code unit.&lt;br /&gt;
&lt;br /&gt;
A dynamically loaded module is a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  (In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
===== Loadable module provider interface =====&lt;br /&gt;
&lt;br /&gt;
The contents of the vtable are specific to the interface, as well as the major version of the interface.  The constructor signature uses an abstract type to represent the vtable pointer.&lt;br /&gt;
&lt;br /&gt;
The constructor takes as arguments a major version number, a minor version number, and a pointer to a caller-allocated vtable structure.&lt;br /&gt;
&lt;br /&gt;
The name of the function symbol is constructed from the name of the plugin interface and the name of the plugin module. This allows the caller to see just from the symbol name which interface and plugin it is calling.&lt;br /&gt;
&lt;br /&gt;
===== Built-in-module provider interface =====&lt;br /&gt;
&lt;br /&gt;
A built-in module provides the same interface as a loadable module. In this architecture we use an exported function symbol for each loadable module implementing a pluggable interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Operational Flow ==&lt;br /&gt;
&lt;br /&gt;
=== Startup ===&lt;br /&gt;
&lt;br /&gt;
*  The krb5_init_context() function initializes an empty registry for each pluggable interface.  &lt;br /&gt;
&lt;br /&gt;
* It then registers libkrb5 built-in modules.&lt;br /&gt;
&lt;br /&gt;
=== Consumer ===&lt;br /&gt;
&lt;br /&gt;
* The consumer registers built-in modules for the desired pluggable interface, if they were not registered by krb5_init_context (because they are not libkrb5 built-in modules).&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the plugin loader function for the desired pluggable interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function calls the plugin manager to retrieve the vtable constructor function for the appropriate module.&lt;br /&gt;
&lt;br /&gt;
* If this is the first load operation for the pluggable interface, the plugin manager performs module discovery and filtering using the appropriate profile variables for the interface.&lt;br /&gt;
&lt;br /&gt;
* The loader function uses the resulting vtable to build an opaque handle to give to the consumer.&lt;br /&gt;
&lt;br /&gt;
* The consumer calls the wrapper functions of the pluggable interface, passing the opaque module handle in order to access the capabilities of the plugin module.&lt;br /&gt;
&lt;br /&gt;
== Interfaces and Functions ==&lt;br /&gt;
&lt;br /&gt;
=== Consumer accessible functions ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a consumer of pluggable interfaces:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; k5_plugin_register&amp;lt;/code&amp;gt;: Register a vtable constructor for a built-in module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
=== Loader accessible function ===&lt;br /&gt;
&lt;br /&gt;
The following functions are meant to be used by a loader function of a pluggable interface:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load&amp;lt;/code&amp;gt;: Obtain a vtable constructor for a named module of a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_load_all&amp;lt;/code&amp;gt;: Obtain a list of all available vtable constructors for a specified interface.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;k5_plugin_free_modules&amp;lt;/code&amp;gt;: Free a list of vtable constructors allocated by k5_plugin_load_all.&lt;br /&gt;
&lt;br /&gt;
=== Function signatures ===&lt;br /&gt;
&lt;br /&gt;
The function signatures as as follows:&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt; krb5_error_code  &lt;br /&gt;
k5_plugin_load(krb5_context context, int interface_id, const char *modname,&lt;br /&gt;
               krb5_plugin_init_fn *module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_load_all(krb5_context context, int interface_id,&lt;br /&gt;
                   krb5_plugin_init_fn **modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;void&lt;br /&gt;
k5_plugin_free_modules(krb5_context context, krb5_plugin_init_fn *modules); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;krb5_error_code&lt;br /&gt;
k5_plugin_register(krb5_context context, int interface_id, const char *modname,&lt;br /&gt;
                   krb5_plugin_init_fn module); &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
== Sample Code and Proof of Concept ==&lt;br /&gt;
&lt;br /&gt;
== Deliverables ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For Release 1.9, the deliverables are (a) plugin framework/manager and pluggable interfaces that can support (b) password strength and (c) password synchronization plugin modules.  &lt;br /&gt;
&lt;br /&gt;
These should support the capabilities of two existing extensions written by Russ Allbery -- krb5-strength and krb5-sync.  The framework is subject to change in the future, so it doesn't have to accommmodate all eventualities, but we will have a goal of not painting ourselves into a corner with respect to reasonably plausible future requirements.&lt;br /&gt;
&lt;br /&gt;
== Existing Support ==&lt;br /&gt;
&lt;br /&gt;
This section provides some background material&lt;br /&gt;
on existing support for pluggable interfaces.&lt;br /&gt;
&lt;br /&gt;
=== Current plugins ===&lt;br /&gt;
&lt;br /&gt;
We currently have the following plugin frameworks:&lt;br /&gt;
&lt;br /&gt;
* Preauth: All shared objects from profile-specified or installation directory are loaded.  Two vtables are read from the shared objects, one for libkrb5 and one for the KDC.  The preauth framework iterates over the module list invoking functions to generate or handle preauth data.  Preauth vtable functions receive a callback function and data object which allow it to request information such as the expected enctype or FAST armor key for the request.&lt;br /&gt;
&lt;br /&gt;
* Authdata: Very similar to the preauth framework.&lt;br /&gt;
&lt;br /&gt;
* KDB: The profile specifies a database library name for each realm.  Shared objects matching the library name are loaded from a profile-specified and installation directory; the first matching object with an appropriately-named vtable data object is used, and the rest are ignored.  libkdb5 contains wrappers which invoke functions in the library's vtable, or (for some optional functions) default implementations if the vtable left the function pointer as NULL.&lt;br /&gt;
&lt;br /&gt;
* KDC location: All shared objects from an installation directory are located.  A vtable is read from the shared objects.  The KDC location framework iterates over each vtable and invokes a lookup function; modules can return success with a location, an error (which halts the location process), or a distinguished error code which passes control along to the next module or the built-in location mechanisms.&lt;br /&gt;
&lt;br /&gt;
* GSSAPI: The file /etc/gss/mechs can specify a list of mechanism OIDs and shared object filenames; filenames are taken as relative to an installation directory.  Shared objects implementing mechanisms can export either a function returning a vtable, or can export each GSSAPI interface individually.&lt;br /&gt;
&lt;br /&gt;
The following areas of functionality are virtualized but have no exposed plugin framework:&lt;br /&gt;
&lt;br /&gt;
* Serialization: Serialization table entries can be registered with krb5_register_serializer.  Data objects are matched to table entries by magic number.  The registration function is exported by libkrb5 and is named with the krb5_ prefix, but it and its associated structure are declared in k5-int.h rather than krb5.h.  It is not used outside of libkrb5.&lt;br /&gt;
&lt;br /&gt;
* ccache: Very similar to serialization, except that ccache implementations are selected using a URL-style prefix in the ccache name.&lt;br /&gt;
&lt;br /&gt;
* keytab: Very similar to ccache, except that the keytab registration function is used outside of libkrb5 to register a &amp;quot;KDB keytab&amp;quot;, which is used by kadmind to serve GSSRPC without requiring a keytab file containing the kadmin keys.&lt;br /&gt;
&lt;br /&gt;
* Replay cache: Very similar to ccache, except that the replay cache registration function is not used anywhere (even inside libkrb5).&lt;br /&gt;
&lt;br /&gt;
Plugin frameworks which are &amp;quot;not exposed&amp;quot; may still be productively used by vendor forks of the krb5 tree.&lt;br /&gt;
&lt;br /&gt;
=== Future planned plugins ===&lt;br /&gt;
&lt;br /&gt;
The following areas are candidates for future plugin support:&lt;br /&gt;
&lt;br /&gt;
* PRNG&lt;br /&gt;
* profile / configuration&lt;br /&gt;
* DNS / host-realm mapping&lt;br /&gt;
* password quality policy&lt;br /&gt;
* lockout&lt;br /&gt;
* audit&lt;br /&gt;
* password synchronization&lt;br /&gt;
&lt;br /&gt;
=== Current support infrastructure ===&lt;br /&gt;
&lt;br /&gt;
In libkrb5support, we have functions to facilitate loading plugins from shared objects.  There is a set of functions to load individual plugins from named files and mechglue; these are currently used by the HDB bridge and GSS mechglue:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin - Create a plugin handle from a filename&lt;br /&gt;
* krb5int_close_plugin - Close a plugin handle&lt;br /&gt;
* krb5int_get_plugin_data - Retrieve a data object from a plugin handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_func - Retrieve a function object from a plugin handle by symbol name&lt;br /&gt;
&lt;br /&gt;
There is another set of functions to scan a list of directories for plugins:&lt;br /&gt;
&lt;br /&gt;
* krb5int_open_plugin_dirs - Create a plugin dir handle from a list of directories and (optionally) filebases&lt;br /&gt;
* krb5int_close_plugin_dirs - Close a plugin dir handle&lt;br /&gt;
* krb5int_get_plugin_dir_data - Retrieve a list of data objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_get_plugin_dir_func - Retrieve a list of function objects from a plugin dir handle by symbol name&lt;br /&gt;
* krb5int_free_plugin_dir_data - Free a list of data objects returned by krb5int_get_plugin_dir_data&lt;br /&gt;
* krb5int_free_plugin_dir_func - Free a list of function objects returned by krb5int_get_plugin_dir_func&lt;br /&gt;
&lt;br /&gt;
=== Problem areas ===&lt;br /&gt;
&lt;br /&gt;
* Every caller of krb5int_open_plugin_dirs specifies either no filebases (e.g. preauth plugins) or a single filebase (KDB plugins).  Accepting and processing a list of filebases is probably needless complexity.&lt;br /&gt;
&lt;br /&gt;
* Callers of krb5int_open_plugin_dirs have to know what directories to supply, which means they need to know the krb5 install root as well as the magic plugin area for OS X, and they need logic for reading a profile variable to determine the alternate plugin directory for the test suite (currently only implemented for KDB and preauth plugins).&lt;br /&gt;
&lt;br /&gt;
* In most uses of plugins, we read a data object containing a list of function pointers.  This makes it mostly impossible to supply a plugin which works with multiple versions of krb5.  If we instead read a function object which we invoked with a version number to retrieve the vtable, it would be possible (though perhaps awkward) to create a shared object which works with multiple versions.&lt;br /&gt;
&lt;br /&gt;
* We are somewhat schizophrenic about how plugins can access krb5 library functionality, and in particular internal symbols.  Sometimes we call functions directly, sometimes we make use of a vtable passed into the plugin (e.g. the preauth_get_client_data_proc function), sometimes we use the accessor to invoke internal functions, and sometimes we call APIs or internal functions directly.  Ideally we should have a consistent policy with a sound justification.&lt;br /&gt;
&lt;br /&gt;
* When measuring code coverage with gcov, we cannot use shared libraries; this means we need to link in-tree plugins statically into the libraries or programs which load them.  We have an ad-hoc method to do this with KDB plugins, but not with other plugin types.&lt;br /&gt;
&lt;br /&gt;
* Administrators have an easier time writing scripts than creating linkable shared objects.  In some cases it might yield a better administrator experience to create plugin interfaces via subprocesses than loading shared objects, although in many cases this might not be feasible.&lt;br /&gt;
&lt;br /&gt;
* In some scenarios such as embedded environments, it may be more useful to allow applications to supply plugin vtables via an API (as we do for keytabs and ccaches, though those APIs are not public) than to load them from shared objects in the filesystem.&lt;br /&gt;
&lt;br /&gt;
== Definitions ==&lt;br /&gt;
&lt;br /&gt;
; pluggable interface: an (internal) interface that can be implemented by a third party.  These can be one-to-one, or one-to-many. An example of one-to-one is the DAL, and an example of one-to-many is preauth.&lt;br /&gt;
&lt;br /&gt;
; module: a unit of code that implements a pluggable interface.  It can be built in, or it can be dynamically loadable.&lt;br /&gt;
:; built-in: a module whose executable code is located within the library shared object or executable program file, or behaves as if it were.  (While separate library shared objects that the calling library depends on can contain &amp;quot;built-in&amp;quot; modules for the calling library, this can cause problems with cyclic references.)  The distinguishing characteristic of a built-in module is that, as part of program startup, the operating system automatically maps the executable code of the module into the address space of the process that calls it, without any explicit action by the library or program.&lt;br /&gt;
:; dynamically loaded: a module whose executable code is located within a file that is distinct from the library or program that calls it.  The plugin support framework uses the runtime linker (or equivalent) to explicitly map the executable code of the module into the process address space.  In POSIX systems, this is typically done using &amp;lt;code&amp;gt;dlopen()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; discovery: process of enumerating what modules are available for a pluggable interface.  Includes possible filtering of the raw discovered set.&lt;br /&gt;
:* compiled-in&lt;br /&gt;
:* directory scan&lt;br /&gt;
:* explicit inclusion by configuration&lt;br /&gt;
:* explicit exclusion by configuration&lt;br /&gt;
&lt;br /&gt;
; loading: the process of making modules available for calling.  This can involve dynamically loading a module using the runtime linker, or it can involve registering a vtable provided by an application.&lt;br /&gt;
:* built-in&lt;br /&gt;
:* dynamic loading&lt;br /&gt;
:* application-registered&lt;br /&gt;
&lt;br /&gt;
; selection: the process of a caller invoking one specific module from the set of loaded modules that implement an interface.&lt;br /&gt;
&lt;br /&gt;
; consumer interface: the interface that a caller uses to access the services of a pluggable interface.  Typically, but not always, the krb5 library implements the consumer interface.&lt;br /&gt;
&lt;br /&gt;
; provider interface: the interface that a module author implements&lt;/div&gt;</summary>
		<author><name>Hardjono</name></author>	</entry>

	</feed>