summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorSam Hartman <hartmans@mit.edu>2010-09-29 21:29:14 +0000
committerSam Hartman <hartmans@mit.edu>2010-09-29 21:29:14 +0000
commit36ad7da6dc4dbd1090b2f39b93b30b3ac8eee396 (patch)
treea96683b12490351b9a16ddc041b9e5714f95658a /src/lib
parent59388bb146c8268f070d93b893e1bc2e96e1e837 (diff)
downloadkrb5-36ad7da6dc4dbd1090b2f39b93b30b3ac8eee396.tar.gz
krb5-36ad7da6dc4dbd1090b2f39b93b30b3ac8eee396.tar.xz
krb5-36ad7da6dc4dbd1090b2f39b93b30b3ac8eee396.zip
kadm5_hook: new plugin interface
Implement http://k5wiki.kerberos.org/wiki/Projects/Kadmin_hook_interface This provides an interface that allows a plugin to track kadmin operations. This can be used for projects like the krb5-sync project. ticket: 6791 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24375 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/kadm5/server_internal.h55
-rw-r--r--src/lib/kadm5/srv/Makefile.in3
-rw-r--r--src/lib/kadm5/srv/kadm5_hook.c189
-rw-r--r--src/lib/kadm5/srv/server_init.c11
-rw-r--r--src/lib/kadm5/srv/svr_principal.c72
-rw-r--r--src/lib/krb5/krb/plugin.c3
6 files changed, 323 insertions, 10 deletions
diff --git a/src/lib/kadm5/server_internal.h b/src/lib/kadm5/server_internal.h
index fd0f7b4ae..59c7b0512 100644
--- a/src/lib/kadm5/server_internal.h
+++ b/src/lib/kadm5/server_internal.h
@@ -37,6 +37,8 @@
/* A pwqual_handle represents a password quality plugin module. */
typedef struct pwqual_handle_st *pwqual_handle;
+typedef struct kadm5_hook_handle_st *kadm5_hook_handle;
+
typedef struct _kadm5_server_handle_t {
krb5_ui_4 magic_number;
krb5_ui_4 struct_version;
@@ -47,6 +49,7 @@ typedef struct _kadm5_server_handle_t {
struct _kadm5_server_handle_t *lhandle;
char **db_args;
pwqual_handle *qual_handles;
+ kadm5_hook_handle *hook_handles;
} kadm5_server_handle_rec, *kadm5_server_handle_t;
#define OSA_ADB_PRINC_VERSION_1 0x12345C01
@@ -198,4 +201,56 @@ krb5_error_code
pwqual_princ_initvt(krb5_context context, int maj_ver, int min_ver,
krb5_plugin_vtable vtable);
+/** @{
+ * @name kadm5_hook plugin support
+ */
+
+/**Load all kadm5_hook plugins*/
+krb5_error_code
+k5_kadm5_hook_load(krb5_context context,
+ kadm5_hook_handle **handles_out);
+
+/** Free handles allocated by k5_kadm5_hook_load()*/
+void
+k5_kadm5_hook_free_handles(krb5_context context, kadm5_hook_handle *handles);
+
+/**Call the chpass entry point on every kadm5_hook in @a handles*/
+kadm5_ret_t
+k5_kadm5_hook_chpass (krb5_context context,
+ kadm5_hook_handle *handles,
+ int stage, krb5_principal princ,
+ krb5_boolean keepold,
+ int n_ks_tuple,
+ krb5_key_salt_tuple *ks_tuple,
+ const char *newpass);
+
+/** Call the create entry point for kadm5_hook_plugins*/
+kadm5_ret_t
+k5_kadm5_hook_create (krb5_context context,
+ kadm5_hook_handle *handles,
+ int stage,
+ kadm5_principal_ent_t princ, long mask,
+ int n_ks_tuple,
+ krb5_key_salt_tuple *ks_tuple,
+ const char *newpass);
+
+/** Call modify kadm5_hook entry point*/
+kadm5_ret_t
+k5_kadm5_hook_modify (krb5_context context,
+ kadm5_hook_handle *handles,
+ int stage,
+ kadm5_principal_ent_t princ, long mask);
+
+/** call remove kadm5_hook entry point*/
+kadm5_ret_t
+k5_kadm5_hook_remove (krb5_context context,
+ kadm5_hook_handle *handles,
+ int stage,
+ krb5_principal princ);
+
+/** @}*/
+
+
+
+
#endif /* __KADM5_SERVER_INTERNAL_H__ */
diff --git a/src/lib/kadm5/srv/Makefile.in b/src/lib/kadm5/srv/Makefile.in
index a513035d5..378e03c76 100644
--- a/src/lib/kadm5/srv/Makefile.in
+++ b/src/lib/kadm5/srv/Makefile.in
@@ -28,6 +28,7 @@ SHLIB_RDIRS=$(KRB5_LIBDIR)
RELDIR=kadm5/srv
SRCS = $(srcdir)/pwqual.c \
+ $(srcdir)/kadm5_hook.c \
$(srcdir)/pwqual_dict.c \
$(srcdir)/pwqual_empty.c \
$(srcdir)/pwqual_hesiod.c \
@@ -47,6 +48,7 @@ OBJS = pwqual.$(OBJEXT) \
pwqual_empty.$(OBJEXT) \
pwqual_hesiod.$(OBJEXT) \
pwqual_princ.$(OBJEXT) \
+ kadm5_hook.$(OBJEXT) \
svr_policy.$(OBJEXT) \
svr_principal.$(OBJEXT) \
server_acl.$(OBJEXT) \
@@ -63,6 +65,7 @@ STLIBOBJS = \
pwqual_empty.o \
pwqual_hesiod.o \
pwqual_princ.o \
+ kadm5_hook.o \
svr_policy.o \
svr_principal.o \
server_acl.o \
diff --git a/src/lib/kadm5/srv/kadm5_hook.c b/src/lib/kadm5/srv/kadm5_hook.c
new file mode 100644
index 000000000..b86ab4297
--- /dev/null
+++ b/src/lib/kadm5/srv/kadm5_hook.c
@@ -0,0 +1,189 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * lib/kadm5/srv/kadm5_hook.c
+ *
+ * Copyright (C) 2010 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+/* Consumer interface for kadm5_hook plugins*/
+
+
+#include "k5-int.h"
+#include "server_internal.h"
+#include <krb5/kadm5_hook_plugin.h>
+#include <adm_proto.h>
+#include <syslog.h>
+
+struct kadm5_hook_handle_st {
+ kadm5_hook_vftable_1 vt;
+ kadm5_hook_modinfo *data;
+};
+
+krb5_error_code
+k5_kadm5_hook_load(krb5_context context,
+ kadm5_hook_handle **handles_out)
+{
+ krb5_error_code ret;
+ krb5_plugin_initvt_fn *modules = NULL, *mod;
+ size_t count;
+ kadm5_hook_handle *list = NULL, handle = NULL;
+
+ *handles_out = NULL;
+
+ ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_KADM5_HOOK, &modules);
+ if (ret != 0)
+ goto cleanup;
+
+ /* Allocate a large enough list of handles. */
+ for (count = 0; modules[count] != NULL; count++);
+ list = k5alloc((count + 1) * sizeof(*list), &ret);
+ if (list == NULL)
+ goto cleanup;
+
+ /* For each module, allocate a handle, initialize its vtable, and initialize the module*/
+ count = 0;
+ for (mod = modules; *mod != NULL; mod++) {
+ handle = k5alloc(sizeof(*handle), &ret);
+ if (handle == NULL)
+ goto cleanup;
+ ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&handle->vt);
+ if (ret != 0) { /* Failed vtable init is non-fatal. */
+ free(handle);
+ handle = NULL;
+ continue;
+ }
+ handle->data = NULL;
+ if (handle->vt.init != NULL) {
+ ret = handle->vt.init(context, &handle->data);
+ if (ret != 0) /* Failed dictionary binding is fatal. */
+ goto cleanup;
+ }
+ list[count++] = handle;
+ list[count] = NULL;
+ handle = NULL;
+ }
+ list[count] = NULL;
+
+ ret = 0;
+ *handles_out = list;
+ list = NULL;
+
+cleanup:
+ free(handle);
+ k5_plugin_free_modules(context, modules);
+ k5_kadm5_hook_free_handles(context, list);
+ return ret;
+}
+
+void
+k5_kadm5_hook_free_handles(krb5_context context, kadm5_hook_handle *handles)
+{
+ kadm5_hook_handle *hp, handle;
+
+ if (handles == NULL)
+ return;
+ for (hp = handles; *hp != NULL; hp++) {
+ handle = *hp;
+ if (handle->vt.fini != NULL)
+ handle->vt.fini(context, handle->data);
+ }
+ free(handles);
+}
+
+static void
+log_failure(krb5_context context,
+ const char *name,
+ const char *function,
+ krb5_error_code ret)
+{
+ const char *e = krb5_get_error_message(context, ret);
+ if (e)
+ krb5_klog_syslog(LOG_ERR, "kadm5_hook %s failed postcommit %s: %s",
+ name, function, e);
+ krb5_free_error_message(context, e);
+}
+
+#define ITERATE(operation, params) \
+ for (; *handles; handles++) { \
+ kadm5_hook_handle h = *handles; \
+ krb5_error_code ret = 0; \
+ if (h->vt.operation) { \
+ ret = h->vt.operation params; \
+ } \
+ if (ret) { \
+ if (stage == KADM5_HOOK_STAGE_PRECOMMIT) \
+ return ret; \
+ else log_failure(context, h->vt.name, #operation, ret); \
+ } \
+ }
+
+
+kadm5_ret_t
+k5_kadm5_hook_chpass (krb5_context context,
+ kadm5_hook_handle *handles,
+ int stage, krb5_principal princ,
+ krb5_boolean keepold,
+ int n_ks_tuple,
+ krb5_key_salt_tuple *ks_tuple,
+ const char *newpass)
+{
+ ITERATE(chpass, (context, h->data,
+ stage, princ, keepold,
+ n_ks_tuple, ks_tuple, newpass));
+ return 0;
+}
+
+kadm5_ret_t
+k5_kadm5_hook_create (krb5_context context,
+ kadm5_hook_handle *handles,
+ int stage,
+ kadm5_principal_ent_t princ, long mask,
+ int n_ks_tuple,
+ krb5_key_salt_tuple *ks_tuple,
+ const char *newpass)
+{
+ ITERATE(create, (context, h->data,
+ stage, princ, mask, n_ks_tuple, ks_tuple, newpass));
+ return 0;
+}
+
+kadm5_ret_t
+k5_kadm5_hook_modify (krb5_context context,
+ kadm5_hook_handle *handles,
+ int stage,
+ kadm5_principal_ent_t princ, long mask)
+{
+ ITERATE(modify, (context, h->data,
+ stage, princ, mask));
+ return 0;
+}
+
+kadm5_ret_t
+k5_kadm5_hook_remove (krb5_context context,
+ kadm5_hook_handle *handles,
+ int stage,
+ krb5_principal princ)
+{
+ ITERATE(remove, (context, h->data,
+ stage, princ));
+ return 0;
+}
diff --git a/src/lib/kadm5/srv/server_init.c b/src/lib/kadm5/srv/server_init.c
index 9ebc13eea..21604a32c 100644
--- a/src/lib/kadm5/srv/server_init.c
+++ b/src/lib/kadm5/srv/server_init.c
@@ -317,8 +317,18 @@ kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass,
return ret;
}
+ ret = k5_kadm5_hook_load(context,&handle->hook_handles);
+ if (ret) {
+ krb5_db_fini(handle->context);
+ krb5_free_principal(handle->context, handle->current_caller);
+ free_db_args(handle);
+ free(handle);
+ return ret;
+ }
+
ret = init_pwqual(handle);
if (ret) {
+ k5_kadm5_hook_free_handles(context, handle->hook_handles);
krb5_db_fini(handle->context);
krb5_free_principal(handle->context, handle->current_caller);
free_db_args(handle);
@@ -339,6 +349,7 @@ kadm5_ret_t kadm5_destroy(void *server_handle)
destroy_pwqual(handle);
+ k5_kadm5_hook_free_handles(handle->context, handle->hook_handles);
adb_policy_close(handle);
krb5_db_fini(handle->context);
krb5_free_principal(handle->context, handle->current_caller);
diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c
index 132078ce3..6ba2c43dc 100644
--- a/src/lib/kadm5/srv/svr_principal.c
+++ b/src/lib/kadm5/srv/svr_principal.c
@@ -4,11 +4,7 @@
*
* $Header$
*/
-
-#if !defined(lint) && !defined(__CODECENTER__)
-static char *rcsid = "$Header$";
-#endif
-
+#include <assert.h>
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
@@ -25,6 +21,8 @@ static char *rcsid = "$Header$";
#endif
+#include <krb5/kadm5_hook_plugin.h>
+
#ifdef USE_VALGRIND
#include <valgrind/memcheck.h>
#else
@@ -393,6 +391,13 @@ kadm5_create_principal_3(void *server_handle,
if (ret)
goto cleanup;
+ ret = k5_kadm5_hook_create(handle->context, handle->hook_handles,
+ KADM5_HOOK_STAGE_PRECOMMIT, entry, mask,
+ n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
+ n_ks_tuple?ks_tuple:handle->params.keysalts, password);
+ if (ret)
+ goto cleanup;
+
/* populate the admin-server-specific fields. In the OV server,
this used to be in a separate database. Since there's already
marshalling code for the admin fields, to keep things simple,
@@ -440,6 +445,11 @@ kadm5_create_principal_3(void *server_handle,
}
}
+ (void) k5_kadm5_hook_create(handle->context, handle->hook_handles,
+ KADM5_HOOK_STAGE_POSTCOMMIT, entry, mask,
+ n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
+ n_ks_tuple?ks_tuple:handle->params.keysalts, password);
+
cleanup:
krb5_db_free_principal(handle->context, kdb);
if (have_polent)
@@ -466,6 +476,12 @@ kadm5_delete_principal(void *server_handle, krb5_principal principal)
if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
return(ret);
+ ret = k5_kadm5_hook_remove(handle->context, handle->hook_handles,
+ KADM5_HOOK_STAGE_PRECOMMIT, principal);
+ if (ret) {
+ kdb_free_entry(handle, kdb, &adb);
+ return ret;
+ }
if ((adb.aux_attributes & KADM5_POLICY)) {
if ((ret = kadm5_get_policy(handle->lhandle,
@@ -490,6 +506,11 @@ kadm5_delete_principal(void *server_handle, krb5_principal principal)
kdb_free_entry(handle, kdb, &adb);
+ if (ret == 0)
+ (void) k5_kadm5_hook_remove(handle->context,
+ handle->hook_handles,
+ KADM5_HOOK_STAGE_POSTCOMMIT, principal);
+
return ret;
}
@@ -681,8 +702,15 @@ kadm5_modify_principal(void *server_handle,
/* let the mask propagate to the database provider */
kdb->mask = mask;
+ ret = k5_kadm5_hook_modify(handle->context, handle->hook_handles,
+ KADM5_HOOK_STAGE_PRECOMMIT, entry, mask);
+ if (ret)
+ goto done;
+
ret = kdb_put_entry(handle, kdb, &adb);
if (ret) goto done;
+ (void) k5_kadm5_hook_modify(handle->context, handle->hook_handles,
+ KADM5_HOOK_STAGE_POSTCOMMIT, entry, mask);
ret = KADM5_OK;
done:
@@ -834,7 +862,7 @@ kadm5_get_principal(void *server_handle, krb5_principal principal,
if (mask & KADM5_KVNO)
for (entry->kvno = 0, i=0; i<kdb->n_key_data; i++)
- if (kdb->key_data[i].key_data_kvno > entry->kvno)
+ if ((krb5_kvno) kdb->key_data[i].key_data_kvno > entry->kvno)
entry->kvno = kdb->key_data[i].key_data_kvno;
if (mask & KADM5_MKVNO) {
@@ -941,13 +969,14 @@ check_pw_reuse(krb5_context context,
krb5_keyblock newkey, histkey;
krb5_error_code ret;
- for (x = 0; x < n_new_key_data; x++) {
+ assert (n_new_key_data >= 0);
+ for (x = 0; x < (unsigned) n_new_key_data; x++) {
ret = krb5_dbe_decrypt_key_data(context, NULL, &(new_key_data[x]),
&newkey, NULL);
if (ret)
return(ret);
for (y = 0; y < n_pw_hist_data; y++) {
- for (z = 0; z < pw_hist_data[y].n_key_data; z++) {
+ for (z = 0; z < (unsigned int) pw_hist_data[y].n_key_data; z++) {
ret = krb5_dbe_decrypt_key_data(context, hist_keyblock,
&pw_hist_data[y].key_data[z],
&histkey, NULL);
@@ -1170,7 +1199,7 @@ static kadm5_ret_t add_to_history(krb5_context context,
knext = adb->old_key_next = 0;
/* free the old pw history entry if it contains data */
histp = &adb->old_keys[knext];
- for (i = 0; i < histp->n_key_data; i++)
+ for (i = 0; i < (unsigned int) histp->n_key_data; i++)
krb5_free_key_data_contents(context, &histp->key_data[i]);
free(histp->key_data);
@@ -1472,9 +1501,22 @@ kadm5_chpass_principal_3(void *server_handle,
KADM5_FAIL_AUTH_COUNT;
/* | KADM5_CPW_FUNCTION */
+ ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
+ KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold,
+ n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
+ n_ks_tuple?ks_tuple:handle->params.keysalts,
+ password);
+ if (ret)
+ goto done;
+
if ((ret = kdb_put_entry(handle, kdb, &adb)))
goto done;
+ (void) k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
+ KADM5_HOOK_STAGE_POSTCOMMIT, principal, keepold,
+ n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
+ n_ks_tuple?ks_tuple:handle->params.keysalts,
+ password);
ret = KADM5_OK;
done:
if (!hist_added && hist.key_data)
@@ -1608,9 +1650,21 @@ kadm5_randkey_principal_3(void *server_handle,
kdb->mask = KADM5_KEY_DATA | KADM5_FAIL_AUTH_COUNT;
/* | KADM5_RANDKEY_USED */;
+ ret = k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
+ KADM5_HOOK_STAGE_PRECOMMIT, principal, keepold,
+ n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
+ n_ks_tuple?ks_tuple:handle->params.keysalts,
+ NULL);
+ if (ret)
+ goto done;
if ((ret = kdb_put_entry(handle, kdb, &adb)))
goto done;
+ (void) k5_kadm5_hook_chpass(handle->context, handle->hook_handles,
+ KADM5_HOOK_STAGE_POSTCOMMIT, principal, keepold,
+ n_ks_tuple?n_ks_tuple:handle->params.num_keysalts,
+ n_ks_tuple?ks_tuple:handle->params.keysalts,
+ NULL);
ret = KADM5_OK;
done:
kdb_free_entry(handle, kdb, &adb);
diff --git a/src/lib/krb5/krb/plugin.c b/src/lib/krb5/krb/plugin.c
index 277da2472..0df393ad9 100644
--- a/src/lib/krb5/krb/plugin.c
+++ b/src/lib/krb5/krb/plugin.c
@@ -31,7 +31,8 @@
#include "k5-int.h"
const char *interface_names[PLUGIN_NUM_INTERFACES] = {
- "pwqual"
+ "pwqual",
+ "kadm5_hook"
};
/* Return the context's interface structure for id, or NULL if invalid. */