Document the DAL interface in comments, as an aid to module
authorGreg Hudson <ghudson@mit.edu>
Mon, 25 Jan 2010 04:12:21 +0000 (04:12 +0000)
committerGreg Hudson <ghudson@mit.edu>
Mon, 25 Jan 2010 04:12:21 +0000 (04:12 +0000)
implementors.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@23666 dc483132-0cff-0310-8789-dd5450dbe970

src/include/kdb.h

index 8c6f532651941f9fcf41a47d96047357b1c01c73..9d886069863f74926e6673f3dd8ceae1640f3ca7 100644 (file)
@@ -719,197 +719,559 @@ krb5_dbe_free_tl_data(krb5_context, krb5_tl_data *);
 #define KRB5_KDB_OPT_SET_DB_NAME        0
 #define KRB5_KDB_OPT_SET_LOCK_MODE      1
 
+/*
+ * A krb5_context can hold one database object.  Modules should use
+ * context->dal_handle->db_context to store state associated with the database
+ * object.
+ *
+ * Some module functions are mandatory for KDC operation; others are optional
+ * or apply only to administrative operations.  If a function is optional, a
+ * module can leave the function pointer as NULL.  Alternatively, modules can
+ * return KRB5_KDB_DBTYPE_NOSUP when asked to perform an inapplicable action.
+ *
+ * Some module functions have default implementations which will call back into
+ * the vtable interface.  Leave these functions as NULL to use the default
+ * implementations.
+ *
+ * The documentation in these comments describes the DAL as it is currently
+ * implemented and used, not as it should be.  So if anything seems off, that
+ * probably means the current state of things is off.
+ */
+
 typedef struct _kdb_vftabl {
     short int maj_ver;
     short int min_ver;
 
-    krb5_error_code (*init_library)();
-    krb5_error_code (*fini_library)();
-    krb5_error_code (*init_module) ( krb5_context kcontext,
-                                     char * conf_section,
-                                     char ** db_args,
-                                     int mode );
-
-    krb5_error_code (*fini_module) ( krb5_context kcontext );
-
-    krb5_error_code (*db_create) ( krb5_context kcontext,
-                                   char * conf_section,
-                                   char ** db_args );
-
-    krb5_error_code (*db_destroy) ( krb5_context kcontext,
-                                    char *conf_section,
-                                    char ** db_args );
-
-    krb5_error_code (*db_get_age) ( krb5_context kcontext,
-                                    char *db_name,
-                                    time_t *age );
-
-    krb5_error_code (*db_set_option) ( krb5_context kcontext,
-                                       int option,
-                                       void *value );
-
-    krb5_error_code (*db_lock) ( krb5_context kcontext,
-                                 int mode );
-
-    krb5_error_code (*db_unlock) ( krb5_context kcontext);
-
-    krb5_error_code (*db_get_principal) ( krb5_context kcontext,
-                                          krb5_const_principal search_for,
-                                          unsigned int flags,
-                                          krb5_db_entry *entries,
-                                          int *nentries,
-                                          krb5_boolean *more );
-
-    krb5_error_code (*db_free_principal) ( krb5_context kcontext,
-                                           krb5_db_entry *entry,
-                                           int count );
-
-    krb5_error_code (*db_put_principal) ( krb5_context kcontext,
-                                          krb5_db_entry *entries,
-                                          int *nentries,
-                                          char **db_args);
-
-    krb5_error_code (*db_delete_principal) ( krb5_context kcontext,
-                                             krb5_const_principal search_for,
-                                             int *nentries );
-
-    krb5_error_code (*db_iterate) ( krb5_context kcontext,
-                                    char *match_entry,
-                                    int (*func) (krb5_pointer, krb5_db_entry *),
-                                    krb5_pointer func_arg );
-
-    krb5_error_code (*db_create_policy) ( krb5_context kcontext,
-                                          osa_policy_ent_t policy );
-
-    krb5_error_code (*db_get_policy) ( krb5_context kcontext,
-                                       char *name,
-                                       osa_policy_ent_t *policy,
-                                       int *cnt);
-
-    krb5_error_code (*db_put_policy) ( krb5_context kcontext,
-                                       osa_policy_ent_t policy );
-
-    krb5_error_code (*db_iter_policy) ( krb5_context kcontext,
-                                        char *match_entry,
-                                        osa_adb_iter_policy_func func,
-                                        void *data );
-
-
-    krb5_error_code (*db_delete_policy) ( krb5_context kcontext,
-                                          char *policy );
+    /*
+     * Mandatory: Invoked after the module library is loaded, when the first DB
+     * using the module is opened, across all contexts.
+     */
+    krb5_error_code (*init_library)(void);
+
+    /*
+     * Mandatory: Invoked before the module library is unloaded, after the last
+     * DB using the module is closed, across all contexts.
+     */
+    krb5_error_code (*fini_library)(void);
+
+    /*
+     * Mandatory: Initialize a database object.  Profile settings should be
+     * read from conf_section inside KDB_MODULE_SECTION.  db_args communicates
+     * command-line arguments for module-specific flags.  mode will be one of
+     * KRB5_KDB_OPEN_{RW,RO} or'd with one of
+     * KRB5_KDB_SRV_TYPE_{KDC,ADMIN,PASSWD,OTHER}.
+     *
+     * A db_args value of "temporary" is generated programattically by
+     * kdb5_util load.  If this db_args value is present, the module should
+     * open a side copy of the database suitable for loading in a propagation
+     * from master to slave.  This side copy will later be promoted with
+     * promote_db, allowing complete updates of the DB with no loss in read
+     * availability.  If the module cannot comply with this architecture, it
+     * should return an error.
+     */
+    krb5_error_code (*init_module)(krb5_context kcontext, char *conf_section,
+                                   char **db_args, int mode);
+
+    /*
+     * Mandatory: Finalize the database object contained in a context.  Free
+     * any state contained in the db_context pointer and null it out.
+     */
+    krb5_error_code (*fini_module)(krb5_context kcontext);
+
+    /*
+     * Optional: Create, but do not open, a database.  conf_section and db_args
+     * have the same meaning as in init_module.  This function may return an
+     * error if the database already exists.  Used by kdb5_util create.
+     */
+    krb5_error_code (*db_create)(krb5_context kcontext, char *conf_section,
+                                 char **db_args);
+
+    /*
+     * Optional: Destroy a database.  conf_section and db_args have the same
+     * meaning as in init_module.  Used by kdb5_util destroy.  In current
+     * usage, the database is destroyed while open, so the module should handle
+     * that.
+     */
+    krb5_error_code (*db_destroy)(krb5_context kcontext, char *conf_section,
+                                  char **db_args);
+
+    /*
+     * Optional: Set *age to the last modification time of the database.  Used
+     * by the KDC lookaside cache to ensure that lookaside entries are not used
+     * if the database has changed since the entry was recorded.
+     *
+     * If this function is unimplemented, lookaside cache entries will
+     * effectively expire immediately.  Another option is to supply the current
+     * time, which will cause lookaside cache entries to last for one second.
+     */
+    krb5_error_code (*db_get_age)(krb5_context kcontext, char *db_name,
+                                  time_t *age);
+
+    /*
+     * Optional: Set a database option.  This function is not currently used by
+     * any callers.  Behavior depends on the value of option:
+     *
+     * KRB5_KDB_OPT_SET_DB_NAME: Interpret value as a C string.  Set the
+     * database name (e.g. a filename for an embedded database).
+     *
+     * KRB5_KDB_OPT_SET_LOCK_MODE: Interpret value as a pointer to
+     * krb5_boolean.  If *value points to TRUE, set the database to
+     * non-blocking lock mode, causing operations to return OSA_ADB_CANTLOCK_DB
+     * when it would otherwise wait to obtain a lock.  Set *value to the old
+     * value of the non-blocking flag.
+     */
+    krb5_error_code (*db_set_option)(krb5_context kcontext, int option,
+                                     void *value);
+
+    /*
+     * Optional: Lock the database, with semantics depending on the mode
+     * argument:
+     *
+     * KRB5_DB_LOCKMODE_SHARED: Lock may coexist with other shared locks.
+     * KRB5_DB_LOCKMODE_EXCLUSIVE: Lock may not coexist with other locks.
+     * KRB5_DB_LOCKMODE_PERMANENT: Exclusive lock surviving process exit.
+     * (KRB5_DB_LOCKMODE_DONTBLOCK is unused and unimplemented.)
+     *
+     * Used by the "kadmin lock" command, incremental propagation, and
+     * kdb5_util dump.  Incremental propagation support requires shared locks
+     * to operate.  kdb5_util dump will work if the module returns
+     * KRB5_PLUGIN_OP_NOTSUPP; note that this is *not* the usual "operation
+     * not supported" error code.
+     */
+    krb5_error_code (*db_lock)(krb5_context kcontext, int mode);
+
+    /* Optional: Release a lock created with db_lock. */
+    krb5_error_code (*db_unlock)(krb5_context kcontext);
+
+    /*
+     * Mandatory: Fill in *entries with the entry for the principal search_for.
+     * The module must allocate each entry field separately, as callers may
+     * free individual fields using db_free.  If the principal is not found,
+     * set *nentries to 0 and return success.  The meaning of flags are as
+     * follows:
+     *
+     * KRB5_KDB_FLAG_CANONICALIZE: Indicates that a KDC client requested name
+     *     canonicalization.  The module may return an out-of-realm referral by
+     *     filling in an out-of-realm principal name in entries->princ and null
+     *     values elsewhere.  The module may return an in-realm alias by
+     *     filling in an in-realm principal name in entries->princ other than
+     *     the one requested.
+     *
+     * KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY: Set by the KDC when looking up the
+     *     client entry in an AS request.  Indicates that the module should
+     *     return out-of-realm referral information in lieu of cross-realm TGT
+     *     information.
+     *
+     * KRB5_KDB_FLAG_MAP_PRINCIPALS: Set by the KDC when looking up the client
+     *     entry during TGS requests, except for S4U TGS requests and requests
+     *     where the server entry has the KRB5_KDB_NO_AUTH_DATA_REQUIRED
+     *     attribute.  Indicates that the module should map cross-realm
+     *     principals if it is capable of doing so.
+     *
+     * KRB5_KDB_FLAG_PROTOCOL_TRANSITION: Set by the KDC when looking up the
+     *     client entry during an S4U2Self TGS request.  No special behavior is
+     *     needed.
+     *
+     * KRB5_KDB_FLAG_CONSTRAINED_DELEGATION: Set by the KDC when looking up the
+     *     client entry during an S4U2Proxy TGS request.  No special behavior
+     *     is needed.
+     *
+     * KRB5_KDB_FLAG_CROSS_REALM: Set by the KDC when looking up a client entry
+     *     during a TGS request, if the client principal is not part of the
+     *     realm being served.
+     *
+     * The nentries and more arguments appear to be intended to account for
+     * multiple entries for a principal, but this functionality is neither
+     * implemented nor used.  *nentries is set to 1 by all callers and should
+     * be set to 0 or 1 on return; the module should always set *more to FALSE.
+     * Callers will typically error out if modules behave otherwise.
+     */
+    krb5_error_code (*db_get_principal)(krb5_context kcontext,
+                                        krb5_const_principal search_for,
+                                        unsigned int flags,
+                                        krb5_db_entry *entries, int *nentries,
+                                        krb5_boolean *more);
+
+    /*
+     * Mandatory: Free the memory associated with principal entries.  Do not
+     * free entry itself.  All callers ignore the return value.  Entries may
+     * have been constructed by the caller (using the db_alloc function to
+     * allocate associated memory); thus, a plugin must allocate each field
+     * of a principal entry separately.
+     */
+    krb5_error_code (*db_free_principal)(krb5_context kcontext,
+                                         krb5_db_entry *entry, int count);
+
+    /*
+     * Optional: Create or modify one or more principal entries.  All callers
+     * operate on a single entry.  db_args communicates command-line arguments
+     * for module-specific flags.
+     *
+     * The mask field of an entry indicates the changed fields.  Mask values
+     * are defined in kadmin's admin.h header.  If KADM5_PRINCIPAL is set in
+     * the mask, the entry is new; otherwise it already exists.  All fields of
+     * an entry are expected to contain correct values, regardless of whether
+     * they are specified in the mask, so it is acceptable for a module to
+     * ignore the mask and update the entire entry.
+     */
+    krb5_error_code (*db_put_principal)(krb5_context kcontext,
+                                        krb5_db_entry *entries, int *nentries,
+                                        char **db_args);
+
+    /*
+     * Optional: Delete the entry for the principal search_for.  If the
+     * principal does not exist, set *nentries to 0 and return success; if it
+     * did exist, set *nentries to 1.
+     */
+    krb5_error_code (*db_delete_principal)(krb5_context kcontext,
+                                           krb5_const_principal search_for,
+                                           int *nentries);
+
+    /*
+     * Optional: For each principal entry in the database, invoke func with the
+     * argments func_arg and the entry data.  If match_entry is specified, the
+     * module may narrow the iteration to principal names matching that regular
+     * expression; a module may alternatively ignore match_entry.
+     */
+    krb5_error_code (*db_iterate)(krb5_context kcontext,
+                                  char *match_entry,
+                                  int (*func)(krb5_pointer, krb5_db_entry *),
+                                  krb5_pointer func_arg);
+
+    /*
+     * Optional: Create a password policy entry.  Return an error if the policy
+     * already exists.
+     */
+    krb5_error_code (*db_create_policy)(krb5_context kcontext,
+                                        osa_policy_ent_t policy);
+
+    /*
+     * Optional: If a password policy entry exists with the name name, allocate
+     * a policy entry in *policy, fill it in with the policy information, and
+     * set *cnt to 1.  If the entry does not exist, set *cnt to 0 and return
+     * success, or return an error (existing module implementations are not
+     * consistent).
+     */
+    krb5_error_code (*db_get_policy)(krb5_context kcontext, char *name,
+                                     osa_policy_ent_t *policy, int *cnt);
+
+    /*
+     * Optional: Modify an existing password policy entry to match the values
+     * in policy.  Return an error if the policy does not already exist.
+     */
+    krb5_error_code (*db_put_policy)(krb5_context kcontext,
+                                     osa_policy_ent_t policy);
+
+    /*
+     * Optional: For each password policy entry in the database, invoke func
+     * with the argments data and the entry data.  If match_entry is specified,
+     * the module may narrow the iteration to policy names matching that
+     * regular expression; a module may alternatively ignore match_entry.
+     */
+    krb5_error_code (*db_iter_policy)(krb5_context kcontext, char *match_entry,
+                                      osa_adb_iter_policy_func func,
+                                      void *data);
+
+    /*
+     * Optional: Delete the password policy entry with the name policy.  Return
+     * an error if the entry does not exist.
+     */
+    krb5_error_code (*db_delete_policy)(krb5_context kcontext, char *policy);
+
+    /* Optional: Free a policy entry returned by db_get_policy. */
+    void (*db_free_policy)(krb5_context kcontext, osa_policy_ent_t val);
+
+    /*
+     * Optional: Fill in *realms with an array of realm names.  This function
+     * is not used or implemented.
+     */
+    krb5_error_code (*db_supported_realms)(krb5_context kcontext,
+                                           char **realms);
+
+    /* Optional: Free a realm list returned by db_supported_realms. */
+    krb5_error_code (*db_free_supported_realms)(krb5_context kcontext,
+                                                char **realms);
+
+    /*
+     * Optional: Convert an error code returned by a module function (casted
+     * from krb5_error_code to long) into a string.  If this function is
+     * implemented, libkdb5 will invoke it and call krb5_set_error_message with
+     * the result.  This function may never return NULL.
+     *
+     * This function is not productively implemented in current modules, and it
+     * is better for a module to simply call krb5_set_error_message inside
+     * modules when appropriate.
+     */
+    const char *(*errcode_2_string)(krb5_context kcontext, long err_code);
+
+    /* Optional: Free an error string returned by errcode_2_string. */
+    void (*release_errcode_string)(krb5_context kcontext, const char *msg);
+
+    /*
+     * Mandatory: Has the semantics of realloc(ptr, size).  Callers use this to
+     * allocate memory for new or changed principal entries, so the module
+     * should expect to potentially see this memory in db_free_principal.
+     */
+    void *(*db_alloc)(krb5_context kcontext, void *ptr, size_t size);
+
+    /*
+     * Mandatory: Has the semantics of free(ptr).  Callers use this to free
+     * fields from a principal entry (such as key data) before changing it in
+     * place, and in some cases to free data they allocated with db_alloc.
+     */
+    void (*db_free)(krb5_context kcontext, void *ptr);
+
+    /*
+     * Optional with default: Inform the module of the master key.  The module
+     * may remember an alias to the provided memory.  This function is called
+     * at startup by the KDC and kadmind; both supply a NULL pwd argument.  The
+     * module should not need to use a remembered master key value, so current
+     * modules do nothing with it besides return it from get_master_key, which
+     * is never used.  The default implementation does nothing.
+     */
+    krb5_error_code (*set_master_key)(krb5_context kcontext, char *pwd,
+                                      krb5_keyblock *key);
 
-    void (*db_free_policy) ( krb5_context kcontext,
-                             osa_policy_ent_t val );
+    /*
+     * Optional with default: Retrieve an alias to the master keyblock as
+     * previously set by set_master_key.  This function is not used.  The
+     * default implementation returns success without modifying *key, which
+     * would be an invalid implementation if it were ever used.
+     */
+    krb5_error_code (*get_master_key)(krb5_context kcontext,
+                                      krb5_keyblock **key);
+
+    /*
+     * Optional with default: Inform the module of the master key.  The module
+     * may remember an alias to the provided memory.  This function is called
+     * at startup by the KDC and kadmind with the value returned by
+     * fetch_master_key_list.  The default implementation does nothing.
+     */
+    krb5_error_code (*set_master_key_list)(krb5_context kcontext,
+                                           krb5_keylist_node *keylist);
+
+    /*
+     * Optional with default: Retrieve an alias to the master key list as
+     * previously set by set_master_key_list.  This function is used by the KDB
+     * keytab implementation in libkdb5, which is used by kadmind.  The default
+     * implementation returns success without modifying *keylist, which is an
+     * invalid implementation.
+     */
+    krb5_error_code (*get_master_key_list)(krb5_context kcontext,
+                                           krb5_keylist_node **keylist);
+
+    /* This function has no entry point in libkdb5; leave it as NULL. */
+    krb5_error_code (*setup_master_key_name)(krb5_context kcontext,
+                                             char *keyname, char *realm,
+                                             char **fullname,
+                                             krb5_principal *principal);
+
+    /*
+     * Optional with default: Save a master keyblock into the stash file
+     * db_arg.  master_pwd indicates the password used to derive the keyblock,
+     * if it is known.  mname is the name of the master principal for the
+     * realm.
+     *
+     * The default implementation ignores master_pwd and saves the master key
+     * in a keytab-format file.
+     */
+    krb5_error_code (*store_master_key)(krb5_context kcontext, char *db_arg,
+                                        krb5_principal mname, krb5_kvno kvno,
+                                        krb5_keyblock *key, char *master_pwd);
+
+    /*
+     * Optional with default: Retrieve a master keyblock from the stash file
+     * db_args, filling in *key and *kvno.  mname is the name of the master
+     * principal for the realm.
+     *
+     * The default implementation reads the master keyblock from a keytab or
+     * old-format stash file.
+     */
+    krb5_error_code (*fetch_master_key)(krb5_context kcontext,
+                                        krb5_principal mname,
+                                        krb5_keyblock *key, krb5_kvno *kvno,
+                                        char *db_args);
+
+    /*
+     * Optional with default: Verify that the keyblock mkey is a valid master
+     * key for the realm.  This function used to be used by the KDC and
+     * kadmind, but is now used only by kdb5_util dump -mkey_convert.
+     *
+     * The default implementation retrieves the master key principal and
+     * attempts to decrypt its key with mkey.  This only works for the current
+     * master keyblock.
+     */
+    krb5_error_code (*verify_master_key)(krb5_context kcontext,
+                                         krb5_principal mprinc, krb5_kvno kvno,
+                                         krb5_keyblock *mkey);
+
+    /*
+     * Optional with default: Given a keyblock for some version of the
+     * database's master key, fetch the decrypted master key values from the
+     * database and store the list into *mkeys_list.  The caller will free
+     * *mkeys_list using a libkdb5 function which uses the standard free()
+     * function, so the module must not use a custom allocator.
+     *
+     * The default implementation tries the key against the current master key
+     * data and all KRB5_TL_MKEY_AUX values, which contain copies of the master
+     * keys encrypted with old master keys.
+     */
+    krb5_error_code (*fetch_master_key_list)(krb5_context kcontext,
+                                             krb5_principal mname,
+                                             const krb5_keyblock *key,
+                                             krb5_kvno kvno,
+                                             krb5_keylist_node **mkeys_list);
+
+    /*
+     * Optional with default: Save a list of master keyblocks, obtained from
+     * fetch_master_key_list, into the stash file db_arg.  The caller will set
+     * master_pwd to NULL, so the module should just ignore it.  mname is the
+     * name of the master principal for the realm.
+     *
+     * The default implementation saves the list of master keys in a
+     * keytab-format file.
+     */
+    krb5_error_code (*store_master_key_list)(krb5_context kcontext,
+                                             char *db_arg,
+                                             krb5_principal mname,
+                                             krb5_keylist_node *keylist,
+                                             char *master_pwd);
+
+    /*
+     * Optional with default: Starting at position *start, scan the key data of
+     * a database entry for a key matching the enctype ktype, the salt type
+     * stype, and the version kvno.  Store the resulting key into *kdatap and
+     * set *start to the position after the key found.  If ktype is negative,
+     * match any enctype.  If stype is negative, match any salt type.  If kvno
+     * is zero or negative, find the most recent key version satisfying the
+     * other constraints.
+     */
+    krb5_error_code (*dbe_search_enctype)(krb5_context kcontext,
+                                          krb5_db_entry *dbentp,
+                                          krb5_int32 *start, krb5_int32 ktype,
+                                          krb5_int32 stype, krb5_int32 kvno,
+                                          krb5_key_data **kdatap);
 
-    krb5_error_code (*db_supported_realms) ( krb5_context kcontext,
-                                             char **realms );
 
-    krb5_error_code (*db_free_supported_realms) ( krb5_context kcontext,
-                                                  char **realms );
-
-
-    const char * (*errcode_2_string) ( krb5_context kcontext,
-                                       long err_code );
-
-    void (*release_errcode_string) (krb5_context kcontext, const char *msg);
-
-    void * (*db_alloc) (krb5_context kcontext, void *ptr, size_t size);
-    void   (*db_free)  (krb5_context kcontext, void *ptr);
-
-
-
-    /* optional functions */
-    krb5_error_code (*set_master_key)    ( krb5_context kcontext,
-                                           char *pwd,
-                                           krb5_keyblock *key);
-
-    krb5_error_code (*get_master_key)    ( krb5_context kcontext,
-                                           krb5_keyblock **key);
-
-    krb5_error_code (*set_master_key_list) ( krb5_context kcontext,
-                                             krb5_keylist_node *keylist);
-
-    krb5_error_code (*get_master_key_list) ( krb5_context kcontext,
-                                             krb5_keylist_node **keylist);
-
-    krb5_error_code (*setup_master_key_name) ( krb5_context kcontext,
-                                               char *keyname,
-                                               char *realm,
-                                               char **fullname,
-                                               krb5_principal  *principal);
-
-    krb5_error_code (*store_master_key)  ( krb5_context kcontext,
-                                           char *db_arg,
-                                           krb5_principal mname,
-                                           krb5_kvno kvno,
-                                           krb5_keyblock *key,
-                                           char *master_pwd);
-
-    krb5_error_code (*fetch_master_key)  ( krb5_context kcontext,
-                                           krb5_principal mname,
-                                           krb5_keyblock *key,
-                                           krb5_kvno *kvno,
-                                           char *db_args);
-
-    krb5_error_code (*verify_master_key) ( krb5_context kcontext,
-                                           krb5_principal mprinc,
-                                           krb5_kvno kvno,
-                                           krb5_keyblock *mkey );
-
-    krb5_error_code (*fetch_master_key_list) (krb5_context kcontext,
-                                              krb5_principal mname,
-                                              const krb5_keyblock *key,
-                                              krb5_kvno            kvno,
-                                              krb5_keylist_node  **mkeys_list);
-
-    krb5_error_code (*store_master_key_list)  ( krb5_context kcontext,
-                                                char *db_arg,
-                                                krb5_principal mname,
-                                                krb5_keylist_node *keylist,
-                                                char *master_pwd);
-
-    krb5_error_code (*dbe_search_enctype) ( krb5_context kcontext,
-                                            krb5_db_entry *dbentp,
-                                            krb5_int32 *start,
-                                            krb5_int32 ktype,
-                                            krb5_int32 stype,
-                                            krb5_int32 kvno,
-                                            krb5_key_data **kdatap);
-
-
-    krb5_error_code
-    (*db_change_pwd) ( krb5_context       context,
-                       krb5_keyblock       * master_key,
-                       krb5_key_salt_tuple      * ks_tuple,
-                       int                        ks_tuple_count,
-                       char             * passwd,
-                       int                        new_kvno,
-                       krb5_boolean       keepold,
-                       krb5_db_entry    * db_entry);
-
-    /* Promote a temporary database to be the live one.  */
-    krb5_error_code (*promote_db) (krb5_context context,
-                                   char *conf_section,
-                                   char **db_args);
-
-    krb5_error_code (*dbekd_decrypt_key_data) ( krb5_context kcontext,
-                                                const krb5_keyblock *mkey,
-                                                const krb5_key_data *key_data,
-                                                krb5_keyblock *dbkey,
-                                                krb5_keysalt *keysalt );
-
-    krb5_error_code (*dbekd_encrypt_key_data) ( krb5_context kcontext,
-                                                const krb5_keyblock *mkey,
-                                                const krb5_keyblock *dbkey,
-                                                const krb5_keysalt *keyselt,
-                                                int keyver,
-                                                krb5_key_data *key_data );
-
-    krb5_error_code
-    (*db_invoke) ( krb5_context context,
-                   unsigned int method,
-                   const krb5_data *req,
-                   krb5_data *rep );
+    /*
+     * Optional with default: Change the key data for db_entry to include keys
+     * derived from the password passwd in each of the specified key-salt
+     * types, at version new_kvno.  Discard the old key data if keepold is not
+     * set.
+     *
+     * The default implementation uses the keyblock master_key to encrypt each
+     * new key, via the function dbekd_encrypt_key_data.
+     */
+    krb5_error_code (*db_change_pwd)(krb5_context context,
+                                     krb5_keyblock *master_key,
+                                     krb5_key_salt_tuple *ks_tuple,
+                                     int ks_tuple_count, char *passwd,
+                                     int new_kvno, krb5_boolean keepold,
+                                     krb5_db_entry *db_entry);
+
+    /*
+     * Optional with default: Promote a temporary database to be the live one.
+     * kdb5_util load opens the database with the "temporary" db_arg and then
+     * invokes this function when the load is complete, thus replacing the live
+     * database with no loss of read availability.
+     *
+     * The default implementation returns KRB5_PLUGIN_OP_NOTSUPP (which is
+     * *not* the usual "operation not supported" error code); kdb5_util dump
+     * recognizes and ignores this error code.
+     */
+    krb5_error_code (*promote_db)(krb5_context context, char *conf_section,
+                                  char **db_args);
+
+    /*
+     * Optional with default: Decrypt the key in key_data with master keyblock
+     * mkey, placing the result into dbkey.  Copy the salt from key_data, if
+     * any, into keysalt.  Either dbkey or keysalt may be left unmodified on
+     * successful return if key_data does not contain key or salt information.
+     *
+     * The default implementation expects the encrypted key (in krb5_c_encrypt
+     * format) to be stored in key_data_contents[0], with length given by
+     * key_data_length[0].  If key_data_ver is 2, it expects the salt to be
+     * stored, unencrypted, in key_data_contents[1], with length given by
+     * key_data_length[1].
+     */
+    krb5_error_code (*dbekd_decrypt_key_data)(krb5_context kcontext,
+                                              const krb5_keyblock *mkey,
+                                              const krb5_key_data *key_data,
+                                              krb5_keyblock *dbkey,
+                                              krb5_keysalt *keysalt);
+
+    /*
+     * Optional with default: Encrypt dbkey with master keyblock mkey, placing
+     * the result into key_data along with keysalt.
+     *
+     * The default implementation stores the encrypted key (in krb5_c_encrypt
+     * format) in key_data_contents[0] and the length in key_data_length[0].
+     * If keysalt is specified, it sets key_data_ver to 2, and stores the salt
+     * in key_data_contents[1] and its length in key_data_length[1].  If
+     * keysalt is not specified, key_data_ver is set to 1.
+     */
+    krb5_error_code (*dbekd_encrypt_key_data)(krb5_context kcontext,
+                                              const krb5_keyblock *mkey,
+                                              const krb5_keyblock *dbkey,
+                                              const krb5_keysalt *keysalt,
+                                              int keyver,
+                                              krb5_key_data *key_data);
+
+    /*
+     * Optional: Perform an operation on input data req with output stored in
+     * rep.  Return KRB5_KDB_DBTYPE_NOSUP if the module does not implement the
+     * method.  Defined methods are:
+     *
+     * KRB5_KDB_METHOD_SIGN_AUTH_DATA: req contains a krb5_sign_auth_data_req
+     *     structure.  Generate signed authorization data, such as a Windows
+     *     PAC, for the ticket to be returned to the client.  Place the signed
+     *     authorization data in rep using a krb5_sign_auth_data_rep structure.
+     *     This function will be invoked for an AS request if the client
+     *     included padata requesting a PAC.  This function will be invoked for
+     *     a TGS request if there is authorization data in the TGT, if the
+     *     client is from another realm, or if the TGS request is an S4U2Self
+     *     or S4U2Proxy request.
+     *
+     * KRB5_KDB_METHOD_CHECK_TRANSITED_REALMS: req contains a
+     *     kdb_check_transited_realms_req structure.  Perform a policy check on
+     *     a cross-realm ticket's transited field and return an error (other
+     *     than KRB5_KDB_DBTYPE_NOSUP) if the check fails.  Leave rep alone.
+     *
+     * KRB5_KDB_METHOD_CHECK_POLICY_AS: req contains a kdb_check_policy_as_req
+     *     structure.  Perform a policy check on an AS request, in addition to
+     *     the standard policy checks.  Return 0 if the AS request is allowed
+     *     or an appropriate error (such as KDC_ERR_POLICY) if it is
+     *     disallowed.  Place in rep a kdb_check_policy_as_rep structure
+     *     containing a status string and e_data value to return to the client
+     *     if the policy check fails.  The status string may be NULL, but must
+     *     not contain allocated data as it will not be freed.  The e_data
+     *     structure may be empty; if not, it will be freed by the caller using
+     *     the standard free function.
+     *
+     * KRB5_KDB_METHOD_CHECK_POLICY_TGS: Same as above, except the structures
+     *     are kdb_check_policy_tgs_req and kdb_check_policy_tgs_rep.
+     *
+     * KRB5_KDB_METHOD_AUDIT_AS: req contains a kdb_audit_as_req structure.
+     *     Informs the module of a successful or unsuccessful AS request.  Do
+     *     not place any data in rep.
+     *
+     * KRB5_KDB_METHOD_AUDIT_TGS: Same as above, except req contains a
+     *     kdb_audit_tgs_req structure.
+     *
+     * KRB5_KDB_METHOD_REFRESH_POLICY: req and rep are NULL.  Informs the
+     *     module that the KDC received a request to reload configuration
+     *     (that is, a SIGHUP).
+     *
+     * KRB5_KDB_METHOD_CHECK_ALLOWED_TO_DELEGATE: req contains a
+     *     kdb_check_allowed_to_delegate_req structure.  Perform a policy check
+     *     on proxy being allowed to act on behalf of client to server.  Return
+     *     0 if policy allows it, or an appropriate error (such as
+     *     KRB5KDC_ERR_POLICY) if not.  If this method is not implemented, all
+     *     S4U2Proxy delegation requests will be rejected.  Do not place any
+     *     data in rep.
+     */
+    krb5_error_code (*db_invoke)(krb5_context context, unsigned int method,
+                                 const krb5_data *req, krb5_data *rep);
 } kdb_vftabl;
 
 #endif /* !defined(_WIN32) */