krb5, kadm5: refactor plugin API

Refactor plugin framework to use a single list of loaded plugins; add a new
plugin API where DSOs export a load function that can declare dependencies and
export multiple plugins; refactor kadm5 hook API to use krb5 plugin framework.

More information in krb5-plugin(7).
This commit is contained in:
Luke Howard
2019-01-01 21:55:36 +11:00
committed by Nico Williams
parent e9b3b2326d
commit 803efebca5
37 changed files with 1293 additions and 639 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, AuriStor Inc.
* Copyright (c) 2018, AuriStor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,9 +29,26 @@
*
*/
#include "kadm5_locl.h"
#include <assert.h>
static char sample_data[1];
#include <krb5.h>
#include <stdio.h>
#include <string.h>
#include "admin.h"
#include "kadm5-hook.h"
/*
* Sample kadm5 hook plugin that just logs when it is called. Install it
* somewhere and configure the path in the [kadmin] section of krb5.conf.
* e.g.
*
* [kadmin]
* plugin_dir = /usr/local/heimdal/lib/plugin/kadm5
*
*/
static char sample_data_1, sample_data_2;
static krb5_error_code
sample_log(krb5_context context,
@@ -43,28 +60,52 @@ sample_log(krb5_context context,
{
char *p = NULL;
krb5_error_code ret;
int which = 0;
if (data != sample_data)
return EINVAL;
if (code != 0 && stage == KADM5_HOOK_STAGE_PRECOMMIT)
return EINVAL;
/* verify we get called with the right contex tpointer */
if (data == &sample_data_1)
which = 1;
else if (data == &sample_data_2)
which = 2;
assert(which != 0);
/* code should always be zero on pre-commit */
assert(code == 0 || stage == KADM5_HOOK_STAGE_POSTCOMMIT);
if (princ)
ret = krb5_unparse_name(context, princ, &p);
krb5_warn(context, code, "sample_hook: %s %s hook princ '%s'", tag,
krb5_warn(context, code, "sample_hook_%d: %s %s hook princ '%s'", which, tag,
stage == KADM5_HOOK_STAGE_PRECOMMIT ? "pre-commit" : "post-commit",
p != NULL ? p : "<unknown>");
krb5_xfree(p);
/* returning zero and KRB5_PLUGIN_NO_HANDLE are the same for hook plugins */
return 0;
}
static krb5_error_code KRB5_CALLCONV
sample_init_1(krb5_context context, void **data)
{
*data = &sample_data_1;
krb5_warn(context, 0, "sample_hook_1: initializing");
return 0;
}
static krb5_error_code KRB5_CALLCONV
sample_init_2(krb5_context context, void **data)
{
*data = &sample_data_2;
krb5_warn(context, 0, "sample_hook_2: initializing");
return 0;
}
static void KRB5_CALLCONV
sample_fini(krb5_context context, void *data)
sample_fini(void *data)
{
krb5_warn(context, 0, "sample_hook: shutting down\n");
krb5_warn(NULL, 0, "sample_fini: finalizing");
}
static krb5_error_code KRB5_CALLCONV
@@ -150,36 +191,82 @@ sample_set_keys_hook(krb5_context context,
return sample_log(context, data, stage, "set_keys", code, princ);
}
static struct kadm5_hook sample_hook = {
"sample-hook",
static krb5_error_code KRB5_CALLCONV
sample_prune_hook(krb5_context context,
void *data,
enum kadm5_hook_stage stage,
krb5_error_code code,
krb5_const_principal princ,
int kvno)
{
return sample_log(context, data, stage, "prune", code, princ);
}
static const kadm5_hook_ftable sample_hook_1 = {
KADM5_HOOK_VERSION_V1,
"Heimdal",
krb5_init_context,
sample_init_1,
sample_fini,
"sample_hook_1",
"Heimdal",
sample_chpass_hook,
sample_create_hook,
sample_modify_hook,
sample_delete_hook,
sample_randkey_hook,
sample_rename_hook,
sample_set_keys_hook
sample_set_keys_hook,
sample_prune_hook,
};
static const kadm5_hook_ftable sample_hook_2 = {
KADM5_HOOK_VERSION_V1,
sample_init_2,
sample_fini,
"sample_hook_2",
"Heimdal",
sample_chpass_hook,
sample_create_hook,
sample_modify_hook,
sample_delete_hook,
sample_randkey_hook,
sample_rename_hook,
sample_set_keys_hook,
sample_prune_hook,
};
/* Arrays of pointers, because hooks may be different versions/sizes */
static const kadm5_hook_ftable *const sample_hooks[] = {
&sample_hook_1,
&sample_hook_2,
};
krb5_error_code
kadm5_hook_init(krb5_context context, uint32_t vers_max,
const kadm5_hook **hook, void **data);
kadm5_hook_plugin_load(krb5_context context,
krb5_get_instance_func_t *get_instance,
size_t *num_hooks,
const kadm5_hook_ftable *const **hooks);
krb5_error_code
kadm5_hook_init(krb5_context context, uint32_t vers_max,
const kadm5_hook **hook, void **data)
static uintptr_t
sample_hook_get_instance(const char *libname)
{
if (vers_max < KADM5_HOOK_VERSION_V1)
return EINVAL;
krb5_warn(context, 0, "sample_hook: init version %u\n", vers_max);
*hook = &sample_hook;
*data = sample_data;
if (strcmp(libname, "kadm5") == 0)
return kadm5_get_instance(libname);
else if (strcmp(libname, "krb5") == 0)
return krb5_get_instance(libname);
return 0;
}
krb5_error_code
kadm5_hook_plugin_load(krb5_context context,
krb5_get_instance_func_t *get_instance,
size_t *num_hooks,
const kadm5_hook_ftable *const **hooks)
{
*get_instance = sample_hook_get_instance;
*num_hooks = sizeof(sample_hooks) / sizeof(sample_hooks[0]);
*hooks = sample_hooks;
return 0;
}