From e61396b03dc643ee9c55f0f881eec7eb25395020 Mon Sep 17 00:00:00 2001 From: Russell Jancewicz Date: Wed, 2 Jul 2014 15:24:05 -0400 Subject: [PATCH 1/4] headers include once, prepare for iteration --- PyKAdminErrors.h | 5 ++ PyKAdminIterator.h | 8 +++ PyKAdminObject.c | 103 ++++++++++++++++++++++++++++++++++++++ PyKAdminObject.h | 7 +++ PyKAdminPolicyObject.h | 5 ++ PyKAdminPrincipalObject.c | 4 +- PyKAdminPrincipalObject.h | 5 ++ setup.py | 2 + 8 files changed, 138 insertions(+), 1 deletion(-) diff --git a/PyKAdminErrors.h b/PyKAdminErrors.h index c40f7fc..edc0845 100644 --- a/PyKAdminErrors.h +++ b/PyKAdminErrors.h @@ -1,4 +1,7 @@ +#ifndef PYKADMINERRORS_H +#define PYKADMINERRORS_H + #include #include #include @@ -15,3 +18,5 @@ PyObject *KAdminErrorsDict; void PyKAdminError_init(PyObject *module); PyObject *PyKAdmin_RaiseKAdminError(kadm5_ret_t retval, char *caller); + +#endif diff --git a/PyKAdminIterator.h b/PyKAdminIterator.h index 2526a1d..9e8e663 100644 --- a/PyKAdminIterator.h +++ b/PyKAdminIterator.h @@ -1,4 +1,7 @@ +#ifndef PYKADMINITERATOROBJECT_H +#define PYKADMINITERATOROBJECT_H + #include #include #include @@ -25,9 +28,14 @@ typedef struct { PyKAdminObject *kadmin; + PyObject *each_principal_func; + PyObject *each_policy_func; + } PyKAdminIterator; PyTypeObject PyKAdminIterator_Type; PyKAdminIterator *PyKAdminIterator_create(PyKAdminObject *kadmin, PyKadminIteratorModes mode, char *filter); void PyKAdminIterator_destroy(PyKAdminIterator *self); + +#endif \ No newline at end of file diff --git a/PyKAdminObject.c b/PyKAdminObject.c index ebec445..884b915 100644 --- a/PyKAdminObject.c +++ b/PyKAdminObject.c @@ -5,6 +5,8 @@ #include "PyKAdminPrincipalObject.h" #include "PyKAdminPolicyObject.h" +#include "PyKAdminCommon.h" + #define IS_NULL(ptr) (ptr == NULL) static void PyKAdminObject_dealloc(PyKAdminObject *self) { @@ -178,6 +180,103 @@ static PyKAdminIterator *PyKAdminObject_policy_iter(PyKAdminObject *self, PyObje return PyKAdminIterator_create(self, mode, match); } +/* +static krb5_error_code +kdb_iter_func(krb5_pointer data, krb5_db_entry *kdb) +{ + iter_data *id = (iter_data *) data; + + (*(id->func))(id->data, kdb->princ); + + return(0); +} + +krb5_error_code +kdb_iter_entry(kadm5_server_handle_t handle, char *match_entry, + void (*iter_fct)(void *, krb5_principal), void *data) +{ + iter_data id; + krb5_error_code ret; + + id.func = iter_fct; + id.data = data; + + ret = krb5_db_iterate(handle->context, match_entry, kdb_iter_func, &id); + if (ret) + return(ret); + + return(0); +} +*/ + +static krb5_error_code kdb_iter_func(void *data, krb5_db_entry *kdb) { + + PyKAdminObject *self = (PyKAdminObject *)data; + + //char *name = NULL; + PyObject *result = NULL; + + if (krb5_unparse_name(self->context, kdb->princ, &name) != 0) + return 1; + + //PyKAdminPrincipalObject *principal = PyKAdminPrincipalObject_create(self, NULL); + + //kadm5_principal_ent_rec *entry = malloc(sizeof(kadm5_principal_ent_rec)); + + + //PyKadmin_kadm_entry_from_kdb_entry(self, kdb, entry, KADM5_PRINCIPAL_NORMAL_MASK); + + //memcpy(&principal->entry, entry, sizeof(kadm5_principal_ent_rec)); + + //PyObject *args = Py_BuildValue("(O)", principal); + + //principal->entry.principal = kdb->princ; + + PyObject *args = Py_BuildValue("(s)", name); + + if (self->each_callback) { + //result = PyObject_CallFunctionObjArgs(self->each_callback, principal, NULL); + result = PyObject_CallObject(self->each_callback, args); + Py_XDECREF(args); + if (!result) { + printf("callback failed\n"); + } + } + + //KAdminPrincipal_destroy(principal); +// + //printf("%s\n", name); + + return 0; + +} + + +static PyObject *PyKAdminObject_each_principal(PyKAdminObject *self, PyObject *args, PyObject *kwds) { + + krb5_error_code ret = 0; + + if (!PyArg_ParseTuple(args, "O!", &PyFunction_Type, &self->each_callback)) + return NULL; + + // we need to hold the refernce to the object while we plan on using it + Py_XINCREF(self->each_callback); + // TODO kdb5_lock(excusive) + ret = krb5_db_iterate(self->context, NULL, kdb_iter_func, self); + // TODO kdb5_unlock + Py_XDECREF(self->each_callback); + + if (ret) + return NULL; + + Py_RETURN_TRUE; + +} + +static PyObject *PyKAdminObject_each_policy(PyKAdminObject *self, PyObject *args, PyObject *kwds) { + // todo + return NULL; +} static PyKAdminPrincipalObject *PyKAdminObject_list_principals(PyKAdminObject *self, PyObject *args, PyObject *kwds) { @@ -198,6 +297,10 @@ static PyMethodDef PyKAdminObject_methods[] = { {"list_principals", (PyCFunction)PyKAdminObject_list_principals, METH_VARARGS, ""}, {"principals", (PyCFunction)PyKAdminObject_principal_iter, (METH_VARARGS | METH_KEYWORDS), ""}, {"policies", (PyCFunction)PyKAdminObject_policy_iter, (METH_VARARGS | METH_KEYWORDS), ""}, + + {"each_principal", (PyCFunction)PyKAdminObject_each_principal, METH_VARARGS, ""}, + {"each_policy", (PyCFunction)PyKAdminObject_each_policy, METH_VARARGS, ""}, + {NULL, NULL, 0, NULL} }; diff --git a/PyKAdminObject.h b/PyKAdminObject.h index f2cf6da..f1b906e 100644 --- a/PyKAdminObject.h +++ b/PyKAdminObject.h @@ -1,4 +1,7 @@ +#ifndef PYKADMINOBJECT_H +#define PYKADMINOBJECT_H + #include #include #include @@ -13,8 +16,12 @@ typedef struct { void *server_handle; char *realm; + PyObject *each_callback; + } PyKAdminObject; PyTypeObject PyKAdminObject_Type; PyKAdminObject *PyKAdminObject_create(void); void PyKAdminObject_destroy(PyKAdminObject *self); + +#endif \ No newline at end of file diff --git a/PyKAdminPolicyObject.h b/PyKAdminPolicyObject.h index cf19198..18611cf 100644 --- a/PyKAdminPolicyObject.h +++ b/PyKAdminPolicyObject.h @@ -1,4 +1,7 @@ +#ifndef PYKADMINPOLICYOBJECT_H +#define PYKADMINPOLICYOBJECT_H + #include #include #include @@ -18,3 +21,5 @@ PyTypeObject PyKAdminPolicyObject_Type; PyKAdminPolicyObject *PyKAdminPolicyObject_create(PyKAdminObject *kadmin, char *name); void PyKAdminPolicyObject_destroy(PyKAdminPolicyObject *self); + +#endif diff --git a/PyKAdminPrincipalObject.c b/PyKAdminPrincipalObject.c index e6a853a..829e725 100644 --- a/PyKAdminPrincipalObject.c +++ b/PyKAdminPrincipalObject.c @@ -5,6 +5,7 @@ #include "PyKAdminPrincipalObject.h" #include "PyKAdminPolicyObject.h" + #define IS_NULL(ptr) (ptr == NULL) static void KAdminPrincipal_dealloc(PyKAdminPrincipalObject *self) { @@ -281,7 +282,6 @@ PyTypeObject PyKAdminPrincipalObject_Type = { }; - PyKAdminPrincipalObject *PyKAdminPrincipalObject_create(PyKAdminObject *kadmin, char *client_name) { PyKAdminPrincipalObject *principal = NULL; @@ -309,3 +309,5 @@ void KAdminPrincipal_destroy(PyKAdminPrincipalObject *self) { KAdminPrincipal_dealloc(self); } + + diff --git a/PyKAdminPrincipalObject.h b/PyKAdminPrincipalObject.h index 13ae07e..7361344 100644 --- a/PyKAdminPrincipalObject.h +++ b/PyKAdminPrincipalObject.h @@ -1,4 +1,7 @@ +#ifndef PYKADMINPRINCIPALOBJECT_H +#define PYKADMINPRINCIPALOBJECT_H + #include #include #include @@ -18,3 +21,5 @@ PyTypeObject PyKAdminPrincipalObject_Type; PyKAdminPrincipalObject *PyKAdminPrincipalObject_create(PyKAdminObject *kadmin, char *client_name); void KAdminPrincipal_destroy(PyKAdminPrincipalObject *self); + +#endif \ No newline at end of file diff --git a/setup.py b/setup.py index 05ff577..fb41ae7 100644 --- a/setup.py +++ b/setup.py @@ -27,6 +27,7 @@ "./PyKAdminIterator.c", "./PyKAdminPrincipalObject.c", "./PyKAdminPolicyObject.c", + "./PyKAdminCommon.c", "./getdate.c" ] ) @@ -65,6 +66,7 @@ "./PyKAdminIterator.c", "./PyKAdminPrincipalObject.c", "./PyKAdminPolicyObject.c", + "./PyKAdminCommon.c", "./getdate.c" ], define_macros=[('KADMIN_LOCAL', '')] From 1491d67e6535d26bceb695aafc2b19c388d63f3f Mon Sep 17 00:00:00 2001 From: Russell Jancewicz Date: Thu, 3 Jul 2014 14:02:18 -0400 Subject: [PATCH 2/4] massive changes to make fast iteration of fully unpacked objects availible from python. replaces principals(unpack=True) --- PyKAdminCommon.c | 286 ++++++++++++++++++++++++++++++++++++++ PyKAdminCommon.h | 19 +++ PyKAdminIterator.c | 10 +- PyKAdminIterator.h | 7 +- PyKAdminObject.c | 140 +++++++++++-------- PyKAdminObject.h | 2 +- PyKAdminPrincipalObject.c | 111 ++++++++++++++- PyKAdminPrincipalObject.h | 7 +- PyKAdminXDR.c | 172 +++++++++++++++++++++++ PyKAdminXDR.h | 36 +++++ setup.py | 2 + 11 files changed, 717 insertions(+), 75 deletions(-) create mode 100644 PyKAdminCommon.c create mode 100644 PyKAdminCommon.h create mode 100644 PyKAdminXDR.c create mode 100644 PyKAdminXDR.h diff --git a/PyKAdminCommon.c b/PyKAdminCommon.c new file mode 100644 index 0000000..d7fbcde --- /dev/null +++ b/PyKAdminCommon.c @@ -0,0 +1,286 @@ + +/* we are going to reuse the internal get_principal function as the foundation of our + kdb_entry to kadm5_principal_ent_t mapper + + svr_principal.c + kadm5_ret_t +kadm5_get_principal(void *server_handle, krb5_principal principal, + kadm5_principal_ent_t entry, + long in_mask) + + */ + +#include "PyKAdminCommon.h" + +krb5_error_code pykadmin_unpack_xdr_osa_princ_ent_rec(PyKAdminObject *kadmin, krb5_db_entry *kdb, osa_princ_ent_rec *adb) { + + krb5_error_code retval = 0; + + XDR xdrs; + krb5_tl_data tl_data; + + tl_data.tl_data_type = KRB5_TL_KADM_DATA; + + if ((retval = krb5_dbe_lookup_tl_data(kadmin->context, kdb, &tl_data)) || (tl_data.tl_data_length == 0)) { + adb->admin_history_kvno = 0; + } + + xdrmem_create(&xdrs, (caddr_t)tl_data.tl_data_contents, tl_data.tl_data_length, XDR_DECODE); + + if (!pykadmin_xdr_osa_princ_ent_rec(&xdrs, adb)) { + xdr_destroy(&xdrs); + retval = KADM5_XDR_FAILURE; + goto done; + } + + xdr_destroy(&xdrs); + + retval = KADM5_OK; +done: + return retval; +} + + +/* + + The following two functions are taken directly from svr_principal.c + the comment preceeding them indicates that they *may* be released into the public api. + until that point there they will simply be copied here as static versions + +*/ + +static kadm5_ret_t krb5_copy_key_data_contents(context, from, to) + krb5_context context; + krb5_key_data *from, *to; +{ + int i, idx; + + *to = *from; + + idx = (from->key_data_ver == 1 ? 1 : 2); + + for (i = 0; i < idx; i++) { + if ( from->key_data_length[i] ) { + to->key_data_contents[i] = malloc(from->key_data_length[i]); + if (to->key_data_contents[i] == NULL) { + for (i = 0; i < idx; i++) { + if (to->key_data_contents[i]) { + memset(to->key_data_contents[i], 0, + to->key_data_length[i]); + free(to->key_data_contents[i]); + } + } + return ENOMEM; + } + memcpy(to->key_data_contents[i], from->key_data_contents[i], + from->key_data_length[i]); + } + } + return 0; +} + +static krb5_tl_data *dup_tl_data(krb5_tl_data *tl) +{ + krb5_tl_data *n; + + n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)); + if (n == NULL) + return NULL; + n->tl_data_contents = malloc(tl->tl_data_length); + if (n->tl_data_contents == NULL) { + free(n); + return NULL; + } + memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length); + n->tl_data_type = tl->tl_data_type; + n->tl_data_length = tl->tl_data_length; + n->tl_data_next = NULL; + return n; +} + + +krb5_error_code pykadmin_kadm_from_kdb(PyKAdminObject *kadmin, krb5_db_entry *kdb, kadm5_principal_ent_rec *entry, long mask) { + + krb5_error_code retval = 0; + int i; + + osa_princ_ent_rec *adb = NULL; + + memset(entry, 0, sizeof(kadm5_principal_ent_rec)); + adb = calloc(1, sizeof(osa_princ_ent_rec)); + + //memset(adb, 0, sizeof(osa_princ_ent_rec)); + + /* principal */ + + if (mask & KADM5_PRINCIPAL) { + if ((retval = krb5_copy_principal(kadmin->context, kdb->princ, &entry->principal))) + goto done; + } + + /* members with a direct relationship */ + + if (mask & KADM5_PRINC_EXPIRE_TIME) + entry->princ_expire_time = kdb->expiration; + + if (mask & KADM5_PW_EXPIRATION) + entry->pw_expiration = kdb->pw_expiration; + + if (mask & KADM5_MAX_LIFE) + entry->max_life = kdb->max_life; + + if (mask & KADM5_MAX_RLIFE) + entry->max_renewable_life = kdb->max_renewable_life; + + if (mask & KADM5_LAST_SUCCESS) + entry->last_success = kdb->last_success; + + if (mask & KADM5_LAST_FAILED) + entry->last_failed = kdb->last_failed; + + if (mask & KADM5_FAIL_AUTH_COUNT) + entry->fail_auth_count = kdb->fail_auth_count; + + if (mask & KADM5_ATTRIBUTES) + entry->attributes = kdb->attributes; + + /* members with computed values */ + + if (mask & KADM5_LAST_PWD_CHANGE) { + if ((retval = krb5_dbe_lookup_last_pwd_change(kadmin->context, kdb, &entry->last_pwd_change))) + goto done; + } + + if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) { + if ((retval = krb5_dbe_lookup_mod_princ_data(kadmin->context, kdb, &(entry->mod_date), &(entry->mod_name)))); + goto done; + + if (! (mask & KADM5_MOD_TIME)) + entry->mod_date = 0; + + if (! (mask & KADM5_MOD_NAME)) { + krb5_free_principal(kadmin->context, entry->mod_name); + entry->mod_name = NULL; + } + } + + if (mask & KADM5_KVNO) { + for (entry->kvno = 0, i=0; in_key_data; i++) + if ((krb5_kvno) kdb->key_data[i].key_data_kvno > entry->kvno) + entry->kvno = kdb->key_data[i].key_data_kvno; + } + + /* api vs github src differ come back to + TODO + if (mask & KADM5_MKVNO) { + if ((retval = krb5_dbe_get_mkvno(kadmin->context, kdb, &entry->mkvno))) + goto done; + } + */ + + + /* key data */ + + if (mask & KADM5_TL_DATA) { + krb5_tl_data *tl, *tl2; + + entry->tl_data = NULL; + + tl = kdb->tl_data; + while (tl) { + if (tl->tl_data_type > 255) { + if ((tl2 = dup_tl_data(tl)) == NULL) { + goto done; + } + tl2->tl_data_next = entry->tl_data; + entry->tl_data = tl2; + entry->n_tl_data++; + } + + tl = tl->tl_data_next; + } + } + + + if (mask & KADM5_KEY_DATA) { + + entry->n_key_data = kdb->n_key_data; + + if(entry->n_key_data) { + entry->key_data = calloc(entry->n_key_data, sizeof(krb5_key_data)); + if (!entry->key_data) + goto done; + } else + entry->key_data = NULL; + + for (i = 0; i < entry->n_key_data; i++) + retval = krb5_copy_key_data_contents(kadmin->context, &kdb->key_data[i], &entry->key_data[i]); + if (retval) + goto done; + } + + + /* + compute adb value of kadm5_get_principal function using the internal mechanism kdb_get_entry + + krb5/src/lib/kadm5/srv/svr_principal.c + kadm5_get_principal() + + krb5/src/lib/kadm5/srv/server_kdb.c + kdb_get_entry() + + */ + + if ((retval = pykadmin_unpack_xdr_osa_princ_ent_rec(kadmin, kdb, adb))) + goto done; + + /* load data stored into the entry rec */ + + if (mask & KADM5_POLICY) { + if ((adb->aux_attributes & KADM5_POLICY) && adb->policy) { + entry->policy = strdup(adb->policy); + } + } + + if (mask & KADM5_AUX_ATTRIBUTES) + entry->aux_attributes = adb->aux_attributes; + + pykadmin_xdr_osa_free_princ_ent(adb); + + retval = KADM5_OK; + +done: + if (retval && entry->principal) { + krb5_free_principal(kadmin->context, entry->principal); + entry->principal = NULL; + } + + return retval; + +} + + +/* +krb5_error_code pykadmin_copy_kadm_ent_rec(PyKAdminObject *kadmin, kadm5_principal_ent_rec *src, kadm5_principal_ent_rec *dst) { + + krb5_error_code retval = 0; + + memcpy(src, dst, sizeof(kadm5_principal_ent_rec)); + + retval = krb5_copy_principal(kadmin->context, src->principal, &dst->principal); + + if (retval) goto done; + + + + +done: + if (retval && entry->principal) { + krb5_free_principal(kadmin->context, entry->principal); + entry->principal = NULL; + } + return retval; +} +*/ + + diff --git a/PyKAdminCommon.h b/PyKAdminCommon.h new file mode 100644 index 0000000..f5500a5 --- /dev/null +++ b/PyKAdminCommon.h @@ -0,0 +1,19 @@ + +#ifndef PYKADMINCOMMON_H +#define PYKADMINCOMMON_H + +#include +#include +#include +#include + +#include "PyKadminXDR.h" +#include "PyKAdminObject.h" + +krb5_error_code pykadmin_kadm_from_kdb(PyKAdminObject *kadmin, krb5_db_entry *kdb, kadm5_principal_ent_rec *entry, long mask); + +// TODO +//krb5_error_code pykadmin_copy_kadm_ent_rec(PyKAdminObject *kadmin, kadm5_principal_ent_rec *src, kadm5_principal_ent_rec *dst); + + +#endif diff --git a/PyKAdminIterator.c b/PyKAdminIterator.c index 9df79af..b46ae25 100644 --- a/PyKAdminIterator.c +++ b/PyKAdminIterator.c @@ -40,21 +40,21 @@ static PyObject *PyKAdminIterator_next(PyKAdminIterator *self) { char *name = self->names[self->index]; - if (self->mode & iterate_unpack) { + /*if (self->mode & iterate_unpack) { if (self->mode & iterate_principals) { - next = (PyObject *)PyKAdminPrincipalObject_create(self->kadmin, name); + next = (PyObject *)PyKAdminPrincipalObject_principal_with_name(self->kadmin, name); } else if (self->mode & iterate_policies) { next = (PyObject *)PyKAdminPolicyObject_create(self->kadmin, name); // todo need policy constructor - //next = PyKAdminPrincipalObject_create(self->kadmin, name); + //next = PyKAdminPrincipalObject_principal_with_name(self->kadmin, name); // for the time we will use a name string as a placeholder so NULL isn't returned next = Py_BuildValue("s", name); } else { next = Py_BuildValue("s", name); } - } else { + } else {*/ next = Py_BuildValue("s", name); - } + //} self->index++; } diff --git a/PyKAdminIterator.h b/PyKAdminIterator.h index 9e8e663..845769d 100644 --- a/PyKAdminIterator.h +++ b/PyKAdminIterator.h @@ -11,8 +11,8 @@ typedef enum { iterate_principals = 0x1, - iterate_policies = 0x2, - iterate_unpack = 0x4 + iterate_policies = 0x2 +// iterate_unpack = 0x4 } PyKadminIteratorModes; typedef struct { @@ -28,9 +28,6 @@ typedef struct { PyKAdminObject *kadmin; - PyObject *each_principal_func; - PyObject *each_policy_func; - } PyKAdminIterator; PyTypeObject PyKAdminIterator_Type; diff --git a/PyKAdminObject.c b/PyKAdminObject.c index 884b915..6ce18bf 100644 --- a/PyKAdminObject.c +++ b/PyKAdminObject.c @@ -13,6 +13,8 @@ static void PyKAdminObject_dealloc(PyKAdminObject *self) { kadm5_ret_t retval; + krb5_db_unlock(self->context); + if (!IS_NULL(self->server_handle)) { retval = kadm5_destroy(self->server_handle); if (retval) {} @@ -26,6 +28,7 @@ static void PyKAdminObject_dealloc(PyKAdminObject *self) { free(self->realm); } + self->ob_type->tp_free((PyObject*)self); } @@ -138,7 +141,7 @@ static PyKAdminPrincipalObject *PyKAdminObject_get_principal(PyKAdminObject *sel } if (!IS_NULL(self->server_handle)) { - principal = PyKAdminPrincipalObject_create(self, client_name); + principal = PyKAdminPrincipalObject_principal_with_name(self, client_name); } @@ -157,8 +160,10 @@ static PyKAdminIterator *PyKAdminObject_principal_iter(PyKAdminObject *self, PyO if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zO", kwlist, &match, &unpack)) return NULL; + /* if (PyObject_IsTrue(unpack)) mode |= iterate_unpack; + */ return PyKAdminIterator_create(self, mode, match); } @@ -173,109 +178,130 @@ static PyKAdminIterator *PyKAdminObject_policy_iter(PyKAdminObject *self, PyObje if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zO", kwlist, &match, &unpack)) return NULL; - + /* if (PyObject_IsTrue(unpack)) - mode |= iterate_unpack; + mode |= iterate_unpack; + */ return PyKAdminIterator_create(self, mode, match); } -/* -static krb5_error_code -kdb_iter_func(krb5_pointer data, krb5_db_entry *kdb) -{ - iter_data *id = (iter_data *) data; - - (*(id->func))(id->data, kdb->princ); - - return(0); -} - -krb5_error_code -kdb_iter_entry(kadm5_server_handle_t handle, char *match_entry, - void (*iter_fct)(void *, krb5_principal), void *data) -{ - iter_data id; - krb5_error_code ret; - id.func = iter_fct; - id.data = data; +static krb5_error_code kdb_iter_princs(void *data, krb5_db_entry *kdb) { - ret = krb5_db_iterate(handle->context, match_entry, kdb_iter_func, &id); - if (ret) - return(ret); + PyKAdminObject *self = (PyKAdminObject *)data; - return(0); -} -*/ + PyObject *result = NULL; -static krb5_error_code kdb_iter_func(void *data, krb5_db_entry *kdb) { + PyKAdminPrincipalObject *principal = PyKadminPrincipalObject_principal_with_db_entry(self, kdb); - PyKAdminObject *self = (PyKAdminObject *)data; + if (principal) { + PyObject *args = Py_BuildValue("(O)", principal); - //char *name = NULL; - PyObject *result = NULL; + if (self->each_callback) { - if (krb5_unparse_name(self->context, kdb->princ, &name) != 0) - return 1; + result = PyObject_CallObject(self->each_callback, args); + + if (!result) { + // TODO raise exception + //printf("callback failed\n"); + } - //PyKAdminPrincipalObject *principal = PyKAdminPrincipalObject_create(self, NULL); + } + Py_XDECREF(args); + KAdminPrincipal_destroy(principal); + } - //kadm5_principal_ent_rec *entry = malloc(sizeof(kadm5_principal_ent_rec)); + return 0; +} - //PyKadmin_kadm_entry_from_kdb_entry(self, kdb, entry, KADM5_PRINCIPAL_NORMAL_MASK); +static void kdb_iter_pols(void *data, osa_policy_ent_rec *entry) { - //memcpy(&principal->entry, entry, sizeof(kadm5_principal_ent_rec)); + // TODO +/* + PyKAdminObject *self = (PyKAdminObject *)data; - //PyObject *args = Py_BuildValue("(O)", principal); + PyObject *result = NULL; - //principal->entry.principal = kdb->princ; - PyObject *args = Py_BuildValue("(s)", name); + // policy = pol from entry + + if (policy) { + PyObject *args = Py_BuildValue("(O)", principal); if (self->each_callback) { - //result = PyObject_CallFunctionObjArgs(self->each_callback, principal, NULL); + result = PyObject_CallObject(self->each_callback, args); - Py_XDECREF(args); + if (!result) { - printf("callback failed\n"); + // TODO raise exception + //printf("callback failed\n"); } + } - - //KAdminPrincipal_destroy(principal); -// - //printf("%s\n", name); + Py_XDECREF(args); + KAdminPrincipal_destroy(principal); + } + */ - return 0; + //return 0; } + static PyObject *PyKAdminObject_each_principal(PyKAdminObject *self, PyObject *args, PyObject *kwds) { - krb5_error_code ret = 0; + char *match = NULL; + krb5_error_code retval = 0; + + static char *kwlist[] = {"f", "match", NULL}; - if (!PyArg_ParseTuple(args, "O!", &PyFunction_Type, &self->each_callback)) + // not sure why this isn't working. + //if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|z", kwlist, &PyFunction_Type, &self->each_callback, &match)) + if (!PyArg_ParseTuple(args, "O!|z", &PyFunction_Type, &self->each_callback, &match)) return NULL; // we need to hold the refernce to the object while we plan on using it Py_XINCREF(self->each_callback); - // TODO kdb5_lock(excusive) - ret = krb5_db_iterate(self->context, NULL, kdb_iter_func, self); - // TODO kdb5_unlock + krb5_db_lock(self->context, KRB5_DB_LOCKMODE_EXCLUSIVE); + retval = krb5_db_iterate(self->context, match, kdb_iter_princs, self); + krb5_db_unlock(self->context); + Py_XDECREF(self->each_callback); - if (ret) + if (retval) return NULL; Py_RETURN_TRUE; } + static PyObject *PyKAdminObject_each_policy(PyKAdminObject *self, PyObject *args, PyObject *kwds) { - // todo - return NULL; + + char *match = NULL; + krb5_error_code retval = 0; + + static char *kwlist[] = {"match", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|z", kwlist, &self->each_callback, &match)) + return NULL; + + // we need to hold the refernce to the object while we plan on using it + Py_XINCREF(self->each_callback); + krb5_db_lock(self->context, KRB5_DB_LOCKMODE_EXCLUSIVE); + retval = krb5_db_iter_policy(self->context, match, kdb_iter_pols, self); + krb5_db_unlock(self->context); + + Py_XDECREF(self->each_callback); + + if (retval) + return NULL; + + Py_RETURN_TRUE; + } diff --git a/PyKAdminObject.h b/PyKAdminObject.h index f1b906e..54ea66d 100644 --- a/PyKAdminObject.h +++ b/PyKAdminObject.h @@ -15,7 +15,7 @@ typedef struct { krb5_context context; void *server_handle; char *realm; - + PyObject *each_callback; } PyKAdminObject; diff --git a/PyKAdminPrincipalObject.c b/PyKAdminPrincipalObject.c index 829e725..3c83a7b 100644 --- a/PyKAdminPrincipalObject.c +++ b/PyKAdminPrincipalObject.c @@ -5,6 +5,7 @@ #include "PyKAdminPrincipalObject.h" #include "PyKAdminPolicyObject.h" +#include "PyKAdminCommon.h" #define IS_NULL(ptr) (ptr == NULL) @@ -36,13 +37,22 @@ static int KAdminPrincipal_init(PyKAdminPrincipalObject *self, PyObject *args, P static int KAdminPrincipal_print(PyKAdminPrincipalObject *self, FILE *file, int flags){ + krb5_error_code retval = 0; char *client_name = NULL; - - krb5_unparse_name(self->kadmin->context, self->entry.principal, &client_name); - printf(" %s", client_name); + if (self->kadmin) { + + retval = krb5_unparse_name(self->kadmin->context, self->entry.principal, &client_name); + /*if (retval) { + printf("%d\n", retval); + }*/ - free(client_name); + printf(" %s", client_name); + } + + if (client_name) + free(client_name); + return 0; } @@ -50,6 +60,7 @@ static int KAdminPrincipal_print(PyKAdminPrincipalObject *self, FILE *file, int static PyMemberDef KAdminPrincipal_members[] = { + {"last_password_change", T_INT, offsetof(PyKAdminPrincipalObject, entry) + offsetof(kadm5_principal_ent_rec, last_pwd_change), READONLY, ""}, {"expire_time", T_INT, offsetof(PyKAdminPrincipalObject, entry) + offsetof(kadm5_principal_ent_rec, princ_expire_time), READONLY, ""}, {"password_expiration", T_INT, offsetof(PyKAdminPrincipalObject, entry) + offsetof(kadm5_principal_ent_rec, pw_expiration), READONLY, ""}, @@ -64,7 +75,7 @@ static PyMemberDef KAdminPrincipal_members[] = { {"key_version_number", T_INT, offsetof(PyKAdminPrincipalObject, entry) + offsetof(kadm5_principal_ent_rec, kvno), READONLY, ""}, {"master_key_version_number", T_INT, offsetof(PyKAdminPrincipalObject, entry) + offsetof(kadm5_principal_ent_rec, mkvno), READONLY, ""}, - {"policy", T_INT, offsetof(PyKAdminPrincipalObject, entry) + offsetof(kadm5_principal_ent_rec, policy), READONLY, ""}, + {"policy", T_STRING, offsetof(PyKAdminPrincipalObject, entry) + offsetof(kadm5_principal_ent_rec, policy), READONLY, ""}, {NULL} }; @@ -139,7 +150,6 @@ static PyGetSetDef KAdminPrincipal_getters_setters[] = { {NULL} }; - static PyObject *_KAdminPrincipal_load_principal(PyKAdminPrincipalObject *self, char *client_name) { kadm5_ret_t retval; @@ -224,6 +234,23 @@ static PyObject *KAdminPrincipal_randomize_key(PyKAdminPrincipalObject *self, Py return Py_True; } +static PyObject *KAdminPrincipal_get_name(PyKAdminPrincipalObject *self, PyObject *args, PyObject *kwds) { + + krb5_error_code retval = 0; + char *client_name = NULL; + PyObject *name = NULL; + + if (self->kadmin) { + + retval = krb5_unparse_name(self->kadmin->context, self->entry.principal, &client_name); + if (retval) {} + + name = Py_BuildValue("z", client_name); + + } + + return name; +} static PyMethodDef KAdminPrincipal_methods[] = { {"cpw", (PyCFunction)KAdminPrincipal_change_password, METH_VARARGS, ""}, @@ -235,6 +262,8 @@ static PyMethodDef KAdminPrincipal_methods[] = { {"set_policy", (PyCFunction)KAdminPrincipal_set_policy, METH_VARARGS, ""}, {"clear_policy", (PyCFunction)KAdminPrincipal_clear_policy, METH_VARARGS, ""}, + {"name", (PyCFunction)KAdminPrincipal_get_name, METH_VARARGS, ""}, + {NULL, NULL, 0, NULL} }; @@ -282,6 +311,76 @@ PyTypeObject PyKAdminPrincipalObject_Type = { }; +PyKAdminPrincipalObject *PyKAdminPrincipalObject_principal_with_name(PyKAdminObject *kadmin, char *client_name) { + + PyKAdminPrincipalObject *principal = (PyKAdminPrincipalObject *)KAdminPrincipal_new(&PyKAdminPrincipalObject_Type, NULL, NULL); + + if (principal) { + + Py_XINCREF(kadmin); + principal->kadmin = kadmin; + + /* todo : fetch kadmin entry */ + PyObject *result = _KAdminPrincipal_load_principal(principal, client_name); + + if (!result) { + Py_XDECREF(kadmin); + Py_XINCREF(Py_None); + KAdminPrincipal_dealloc(principal); + principal = (PyKAdminPrincipalObject *)Py_None; + } + + } + + return principal; +} + +PyKAdminPrincipalObject *PyKadminPrincipalObject_principal_with_db_entry(PyKAdminObject *kadmin, krb5_db_entry *kdb) { + + krb5_error_code retval; + + PyKAdminPrincipalObject *principal = (PyKAdminPrincipalObject *)KAdminPrincipal_new(&PyKAdminPrincipalObject_Type, NULL, NULL); + + if (kdb) { + + Py_XINCREF(kadmin); + principal->kadmin = kadmin; + + retval = pykadmin_kadm_from_kdb(kadmin, kdb, &principal->entry, KADM5_PRINCIPAL_NORMAL_MASK); + + if (retval) { + + } + } + + return principal; +} + +/* +PyKAdminPrincipalObject *PyKadminPrincipalObject_principal_with_kadm_entry(PyKAdminObject *kadmin, kadm5_principal_ent_rec *entry) { + + krb5_error_code retval; + + PyKAdminPrincipalObject *principal = (PyKAdminPrincipalObject *)KAdminPrincipal_new(&PyKAdminPrincipalObject_Type, NULL, NULL); + + if (entry) { + + Py_XINCREF(kadmin); + principal->kadmin = kadmin; + + //retval = pykadmin_copy_kadm_ent_rec(kadmin, entry, &principal->entry); + + if (retval) { + + } + + + } + + return principal; +} +*/ + PyKAdminPrincipalObject *PyKAdminPrincipalObject_create(PyKAdminObject *kadmin, char *client_name) { PyKAdminPrincipalObject *principal = NULL; diff --git a/PyKAdminPrincipalObject.h b/PyKAdminPrincipalObject.h index 7361344..df172af 100644 --- a/PyKAdminPrincipalObject.h +++ b/PyKAdminPrincipalObject.h @@ -18,8 +18,13 @@ typedef struct { } PyKAdminPrincipalObject; PyTypeObject PyKAdminPrincipalObject_Type; +PyKAdminPrincipalObject *PyKAdminPrincipalObject_principal_with_name(PyKAdminObject *kadmin, char *client_name); +PyKAdminPrincipalObject *PyKadminPrincipalObject_principal_with_db_entry(PyKAdminObject *kadmin, krb5_db_entry *kdb); +PyKAdminPrincipalObject *PyKadminPrincipalObject_principal_with_kadm_entry(PyKAdminObject *kadmin, kadm5_principal_ent_rec *entry); -PyKAdminPrincipalObject *PyKAdminPrincipalObject_create(PyKAdminObject *kadmin, char *client_name); +// create will be replaced with load_princ_w_name +PyKAdminPrincipalObject *PyKAdminPrincipalObject_principal_with_name(PyKAdminObject *kadmin, char *client_name); void KAdminPrincipal_destroy(PyKAdminPrincipalObject *self); + #endif \ No newline at end of file diff --git a/PyKAdminXDR.c b/PyKAdminXDR.c new file mode 100644 index 0000000..10dfc58 --- /dev/null +++ b/PyKAdminXDR.c @@ -0,0 +1,172 @@ + +#include "PyKAdminXDR.h" +#include + +int pykadmin_xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_rec *entry) { + + int result = 0; + + memset(entry, 0, sizeof(osa_princ_ent_rec)); + + switch (xdrs->x_op) { + + case XDR_ENCODE: + entry->version = OSA_ADB_PRINC_VERSION_1; + case XDR_FREE: + if (!xdr_int(xdrs, &entry->version)) + goto done; + case XDR_DECODE: + if (!xdr_int(xdrs, &entry->version) || (entry->version != OSA_ADB_PRINC_VERSION_1)) + goto done; + } + + if (!pykadmin_xdr_nullstring(xdrs, &entry->policy)) + goto done; + + if (!xdr_long(xdrs, &entry->aux_attributes)) + goto done; + + if (!xdr_u_int(xdrs, &entry->old_key_next)) + goto done; + + if (!xdr_u_char(xdrs, (unsigned char *)&entry->admin_history_kvno)) + goto done; + + if (!xdr_array(xdrs, (caddr_t *) &entry->old_keys, (unsigned int *) &entry->old_key_len, ~0, sizeof(osa_pw_hist_ent), pykadmin_xdr_osa_pw_hist_ent)) + goto done; + + result = 1; + +done: + + return result; +} + +int pykadmin_xdr_nullstring(XDR *xdrs, char **string) { + + unsigned int size; + int result = 0; + + if (xdrs->x_op == XDR_ENCODE) + size = (*string) ? strlen(*string) + 1 : 0; + + if (!xdr_u_int(xdrs, &size)) + goto done; + + switch (xdrs->x_op) { + + case XDR_DECODE: + if (size) { + *string = malloc(size); + if (!*string) + goto done; + } else { + *string = NULL; + } + if (!xdr_opaque(xdrs, *string, size)) + goto done; + break; + + case XDR_ENCODE: + if (size) { + if (!xdr_opaque(xdrs, *string, size)) + goto done; + } + break; + case XDR_FREE: + if (*string) { + free(*string); + *string = NULL; + } + break; + } + + result = 1; +done: + return result; +} + +int pykadmin_xdr_int16(XDR *xdrs, int *data) { + + int result = 0; + if (!xdr_int(xdrs, data)) + goto done; + + result = 1; +done: + return result; +} + +int pykadmin_xdr_uint16(XDR *xdrs, unsigned int *data) { + + int result = 0; + if (!xdr_u_int(xdrs, data)) + goto done; + + result = 1; +done: + return result; +} + +int pykadmin_xdr_krb5_key_data(XDR *xdrs, krb5_key_data *key_data) { + + int result = 0; + unsigned int temp; + + if (!pykadmin_xdr_int16(xdrs, (int *)&key_data->key_data_ver)) + goto done; + + if (!pykadmin_xdr_int16(xdrs, (int *)&key_data->key_data_kvno)) + goto done; + + if (!pykadmin_xdr_int16(xdrs, (int *)&key_data->key_data_type[0])) + goto done; + + if (!pykadmin_xdr_int16(xdrs, (int *)&key_data->key_data_type[1])) + goto done; + + if (!pykadmin_xdr_uint16(xdrs, (unsigned int *)&key_data->key_data_length[0])) + goto done; + + if (!pykadmin_xdr_uint16(xdrs, (unsigned int *)&key_data->key_data_length[1])) + goto done; + + temp = (unsigned int) key_data->key_data_length[0]; + if (!xdr_bytes(xdrs, (char **) &key_data->key_data_contents[0], &temp, ~0)) + goto done; + + temp = (unsigned int) key_data->key_data_length[1]; + if (!xdr_bytes(xdrs, (char **) &key_data->key_data_contents[1], &temp, ~0)) + goto done; + + result = 1; +done: + return result; +} + +int pykadmin_xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *pw_hist) { + + int result = 0; + if (!xdr_array(xdrs, (caddr_t *) &pw_hist->key_data, (unsigned int *) &pw_hist->n_key_data, ~0, sizeof(krb5_key_data), pykadmin_xdr_krb5_key_data)) + goto done; + + result = 1; +done: + return result; + +} + +void pykadmin_xdr_osa_free_princ_ent(osa_princ_ent_rec *entry) { + + XDR xdrs; + + xdrmem_create(&xdrs, NULL, 0, XDR_FREE); + + pykadmin_xdr_osa_princ_ent_rec(&xdrs, entry); + + free(entry); +} + +// not exactly sure why this needs to exist, it just appears to cast a bunch of things. +//int pykadmin_xdr_krb5_kvno(XDR *xdrs, krb5_kvno *kvno) {} + diff --git a/PyKAdminXDR.h b/PyKAdminXDR.h new file mode 100644 index 0000000..1b5c2fa --- /dev/null +++ b/PyKAdminXDR.h @@ -0,0 +1,36 @@ + +#ifndef PYKADMINXDR_H +#define PYKADMINXDR_H + +#include +#include +#include + +/* structures from the krb5 source; + these are not exported anywhere so we must custom build them to extract xdr data wihout breaking APIs + */ + +#define OSA_ADB_PRINC_VERSION_1 0x12345C01 + +typedef struct _osa_pw_hist_t { + int n_key_data; + krb5_key_data *key_data; +} osa_pw_hist_ent, *osa_pw_hist_t; + +typedef struct _osa_princ_ent_t { + int version; + char *policy; + long aux_attributes; + unsigned int old_key_len; + unsigned int old_key_next; + krb5_kvno admin_history_kvno; + osa_pw_hist_ent *old_keys; +} osa_princ_ent_rec, *osa_princ_ent_t; + +void pykadmin_xdr_osa_free_princ_ent(osa_princ_ent_rec *entry); +int pykadmin_xdr_nullstring(XDR *xdrs, char **string); +int pykadmin_xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *objp); +int pykadmin_xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_rec *entry); + + +#endif \ No newline at end of file diff --git a/setup.py b/setup.py index fb41ae7..ab53692 100644 --- a/setup.py +++ b/setup.py @@ -28,6 +28,7 @@ "./PyKAdminPrincipalObject.c", "./PyKAdminPolicyObject.c", "./PyKAdminCommon.c", + "./PyKAdminXDR.c", "./getdate.c" ] ) @@ -67,6 +68,7 @@ "./PyKAdminPrincipalObject.c", "./PyKAdminPolicyObject.c", "./PyKAdminCommon.c", + "./PyKAdminXDR.c", "./getdate.c" ], define_macros=[('KADMIN_LOCAL', '')] From add04ecb106d988c6697354c8d82a04a2a4339e1 Mon Sep 17 00:00:00 2001 From: Russell Jancewicz Date: Mon, 7 Jul 2014 16:29:35 -0400 Subject: [PATCH 3/4] local unpacked iteration working, remote iteration more explicit --- PyKAdminIterator.c | 20 +------ PyKAdminObject.c | 143 ++++++++++++++++++--------------------------- PyKAdminObject.h | 8 ++- PyKAdminXDR.h | 2 +- build.sh | 2 +- kadmin.c | 16 +++++ setup.py | 7 ++- test/unittests.py | 43 ++++++++++++-- 8 files changed, 126 insertions(+), 115 deletions(-) diff --git a/PyKAdminIterator.c b/PyKAdminIterator.c index b46ae25..d67175a 100644 --- a/PyKAdminIterator.c +++ b/PyKAdminIterator.c @@ -34,27 +34,13 @@ static int PyKAdminIterator_init(PyKAdminIterator *self, PyObject *args, PyObjec static PyObject *PyKAdminIterator_next(PyKAdminIterator *self) { + char *name = NULL; PyObject *next = NULL; if (self->index < self->count) { - char *name = self->names[self->index]; - - /*if (self->mode & iterate_unpack) { - if (self->mode & iterate_principals) { - next = (PyObject *)PyKAdminPrincipalObject_principal_with_name(self->kadmin, name); - } else if (self->mode & iterate_policies) { - next = (PyObject *)PyKAdminPolicyObject_create(self->kadmin, name); - // todo need policy constructor - //next = PyKAdminPrincipalObject_principal_with_name(self->kadmin, name); - // for the time we will use a name string as a placeholder so NULL isn't returned - next = Py_BuildValue("s", name); - } else { - next = Py_BuildValue("s", name); - } - } else {*/ - next = Py_BuildValue("s", name); - //} + name = self->names[self->index]; + next = Py_BuildValue("s", name); self->index++; } diff --git a/PyKAdminObject.c b/PyKAdminObject.c index 6ce18bf..cd499e5 100644 --- a/PyKAdminObject.c +++ b/PyKAdminObject.c @@ -7,6 +7,7 @@ #include "PyKAdminCommon.h" + #define IS_NULL(ptr) (ptr == NULL) static void PyKAdminObject_dealloc(PyKAdminObject *self) { @@ -34,13 +35,14 @@ static void PyKAdminObject_dealloc(PyKAdminObject *self) { static PyObject *PyKAdminObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - PyKAdminObject *self; + PyKAdminObject *self; kadm5_ret_t retval = 0; self = (PyKAdminObject *)type->tp_alloc(type, 0); if (self) { - retval = krb5_init_context(&self->context); + retval = kadm5_init_krb5_context(&self->context); + // retval = krb5_init_context(&self->context); if (retval) { Py_DECREF(self); @@ -48,11 +50,13 @@ static PyObject *PyKAdminObject_new(PyTypeObject *type, PyObject *args, PyObject return NULL; } + self->server_handle = NULL; + // attempt to load the default realm for this connection - krb5_get_default_realm(self->context, &self->realm); - if (!self->realm) { - // todo : fail - } + //krb5_get_default_realm(self->context, &self->realm); + //if (!self->realm) { + // // todo : fail + //} } return (PyObject *)self; @@ -160,14 +164,10 @@ static PyKAdminIterator *PyKAdminObject_principal_iter(PyKAdminObject *self, PyO if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zO", kwlist, &match, &unpack)) return NULL; - /* - if (PyObject_IsTrue(unpack)) - mode |= iterate_unpack; - */ - return PyKAdminIterator_create(self, mode, match); } + static PyKAdminIterator *PyKAdminObject_policy_iter(PyKAdminObject *self, PyObject *args, PyObject *kwds) { char *match = NULL; @@ -178,16 +178,11 @@ static PyKAdminIterator *PyKAdminObject_policy_iter(PyKAdminObject *self, PyObje if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zO", kwlist, &match, &unpack)) return NULL; - /* - if (PyObject_IsTrue(unpack)) - mode |= iterate_unpack; - */ return PyKAdminIterator_create(self, mode, match); } - -static krb5_error_code kdb_iter_princs(void *data, krb5_db_entry *kdb) { +static int kdb_iter_princs(void *data, krb5_db_entry *kdb) { PyKAdminObject *self = (PyKAdminObject *)data; @@ -196,56 +191,21 @@ static krb5_error_code kdb_iter_princs(void *data, krb5_db_entry *kdb) { PyKAdminPrincipalObject *principal = PyKadminPrincipalObject_principal_with_db_entry(self, kdb); if (principal) { - PyObject *args = Py_BuildValue("(O)", principal); - if (self->each_callback) { - - result = PyObject_CallObject(self->each_callback, args); + if (self->each_principal.callback) { - if (!result) { - // TODO raise exception - //printf("callback failed\n"); - } - - } - Py_XDECREF(args); - KAdminPrincipal_destroy(principal); - } - - return 0; - -} - -static void kdb_iter_pols(void *data, osa_policy_ent_rec *entry) { - - // TODO -/* - PyKAdminObject *self = (PyKAdminObject *)data; - - PyObject *result = NULL; - - - // policy = pol from entry - - if (policy) { - PyObject *args = Py_BuildValue("(O)", principal); - - if (self->each_callback) { - - result = PyObject_CallObject(self->each_callback, args); + result = PyObject_CallFunctionObjArgs(self->each_principal.callback, principal, self->each_principal.arg, NULL); if (!result) { - // TODO raise exception - //printf("callback failed\n"); + // use self to hold exception } } Py_XDECREF(args); KAdminPrincipal_destroy(principal); } - */ - //return 0; + return 0; } @@ -255,53 +215,56 @@ static PyObject *PyKAdminObject_each_principal(PyKAdminObject *self, PyObject *a char *match = NULL; krb5_error_code retval = 0; + kadm5_ret_t lock = 0; - static char *kwlist[] = {"f", "match", NULL}; - // not sure why this isn't working. - //if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|z", kwlist, &PyFunction_Type, &self->each_callback, &match)) - if (!PyArg_ParseTuple(args, "O!|z", &PyFunction_Type, &self->each_callback, &match)) + static char *kwlist[] = {"", "args", "match", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|Oz", kwlist, &PyFunction_Type, &self->each_principal.callback, &self->each_principal.arg, &match)) return NULL; - // we need to hold the refernce to the object while we plan on using it - Py_XINCREF(self->each_callback); - krb5_db_lock(self->context, KRB5_DB_LOCKMODE_EXCLUSIVE); - retval = krb5_db_iterate(self->context, match, kdb_iter_princs, self); - krb5_db_unlock(self->context); + if (!self->each_principal.arg) + self->each_principal.arg = Py_None; - Py_XDECREF(self->each_callback); + Py_XINCREF(self->each_principal.callback); + Py_XINCREF(self->each_principal.arg); + + lock = kadm5_lock(self->server_handle); - if (retval) - return NULL; + if (!lock || (lock == KRB5_PLUGIN_OP_NOTSUPP)) { - Py_RETURN_TRUE; + krb5_clear_error_message(self->context); -} + retval = krb5_db_iterate(self->context, match, kdb_iter_princs, (void *)self); + + if (lock != KRB5_PLUGIN_OP_NOTSUPP) { + lock = kadm5_unlock(self->server_handle); + } + } + Py_XDECREF(self->each_principal.callback); + Py_XDECREF(self->each_principal.arg); -static PyObject *PyKAdminObject_each_policy(PyKAdminObject *self, PyObject *args, PyObject *kwds) { + if (retval) { + // TODO raise proper exception + return NULL; + } - char *match = NULL; - krb5_error_code retval = 0; + Py_RETURN_TRUE; - static char *kwlist[] = {"match", NULL}; +} - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|z", kwlist, &self->each_callback, &match)) - return NULL; - // we need to hold the refernce to the object while we plan on using it - Py_XINCREF(self->each_callback); - krb5_db_lock(self->context, KRB5_DB_LOCKMODE_EXCLUSIVE); - retval = krb5_db_iter_policy(self->context, match, kdb_iter_pols, self); - krb5_db_unlock(self->context); - Py_XDECREF(self->each_callback); +static void kdb_iter_pols(void *data, osa_policy_ent_rec *entry) { - if (retval) - return NULL; + PyKAdminObject *self = (PyKAdminObject *)data; + +} - Py_RETURN_TRUE; +static PyObject *PyKAdminObject_each_policy(PyKAdminObject *self, PyObject *args, PyObject *kwds) { + return NULL; } @@ -324,8 +287,14 @@ static PyMethodDef PyKAdminObject_methods[] = { {"principals", (PyCFunction)PyKAdminObject_principal_iter, (METH_VARARGS | METH_KEYWORDS), ""}, {"policies", (PyCFunction)PyKAdminObject_policy_iter, (METH_VARARGS | METH_KEYWORDS), ""}, - {"each_principal", (PyCFunction)PyKAdminObject_each_principal, METH_VARARGS, ""}, - {"each_policy", (PyCFunction)PyKAdminObject_each_policy, METH_VARARGS, ""}, + #ifdef KADMIN_LOCAL + /* + due to the nature of how the kadm5clnt library interfaces with the kerberos database over the rpc layer + we are unable to (and should not) expose unpacked iteration "each" to the gssapi version of python-kadmin + */ + {"each_principal", (PyCFunction)PyKAdminObject_each_principal, (METH_VARARGS | METH_KEYWORDS), ""}, + {"each_policy", (PyCFunction)PyKAdminObject_each_policy, (METH_VARARGS | METH_KEYWORDS), ""}, + #endif {NULL, NULL, 0, NULL} }; diff --git a/PyKAdminObject.h b/PyKAdminObject.h index 54ea66d..b0c3533 100644 --- a/PyKAdminObject.h +++ b/PyKAdminObject.h @@ -9,6 +9,11 @@ #include #include +typedef struct { + PyObject *callback; + PyObject *arg; +} each_iteration_t; + typedef struct { PyObject_HEAD @@ -16,7 +21,8 @@ typedef struct { void *server_handle; char *realm; - PyObject *each_callback; + each_iteration_t each_principal; + each_iteration_t each_policy; } PyKAdminObject; diff --git a/PyKAdminXDR.h b/PyKAdminXDR.h index 1b5c2fa..e9160c6 100644 --- a/PyKAdminXDR.h +++ b/PyKAdminXDR.h @@ -27,10 +27,10 @@ typedef struct _osa_princ_ent_t { osa_pw_hist_ent *old_keys; } osa_princ_ent_rec, *osa_princ_ent_t; -void pykadmin_xdr_osa_free_princ_ent(osa_princ_ent_rec *entry); int pykadmin_xdr_nullstring(XDR *xdrs, char **string); int pykadmin_xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *objp); int pykadmin_xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_rec *entry); +void pykadmin_xdr_osa_free_princ_ent(osa_princ_ent_rec *entry); #endif \ No newline at end of file diff --git a/build.sh b/build.sh index 697b0f8..673c111 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ target=$1 if [ "$target" == "test" ]; then - python ./setup.py build --build-platlib ./test/ + CFLAGS="-O0" python ./setup.py build --build-platlib ./test/ fi if [ "$target" == "release" ]; then diff --git a/kadmin.c b/kadmin.c index 85bd891..9b71ed1 100644 --- a/kadmin.c +++ b/kadmin.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -191,6 +192,7 @@ static PyKAdminObject *_kadmin_init_with_keytab(PyObject *self, PyObject *args) return NULL; if (keytab_name == NULL) { + keytab_name = "/etc/krb5.keytab"; } @@ -205,6 +207,8 @@ static PyKAdminObject *_kadmin_init_with_keytab(PyObject *self, PyObject *args) krb5_free_principal(kadmin->context, princ); } + + retval = kadm5_init_with_skey( kadmin->context, client_name, @@ -218,6 +222,18 @@ static PyKAdminObject *_kadmin_init_with_keytab(PyObject *self, PyObject *args) if (retval) { PyKAdmin_RaiseKAdminError(retval, "kadm5_init_with_skey"); return NULL; } + + // kadmin->context = kadmin->server_handle->context; + + //retval = krb5_db_setup_lib_handle(kadmin->context); + + // if (retval) { + // printf("retval [%d] %s\n", retval, krb5_get_error_message(kadmin->context, retval)); + // + //} + //if (retval) { PyKAdmin_RaiseKAdminError(retval, "kadm5_init_with_skey"); return NULL; } + + Py_XINCREF(kadmin); return kadmin; } diff --git a/setup.py b/setup.py index ab53692..c752ee6 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ ext_modules=[ Extension( "kadmin", - libraries=["krb5", "kadm5clnt"], + libraries=["krb5", "kadm5clnt", "kdb5"], include_dirs=["/usr/include/", "/usr/include/et/"], sources=[ "./kadmin.c", @@ -30,7 +30,8 @@ "./PyKAdminCommon.c", "./PyKAdminXDR.c", "./getdate.c" - ] + ], + extra_compile_args=["-O0"] ) ], classifiers=[ @@ -58,7 +59,7 @@ ext_modules=[ Extension( "kadmin_local", - libraries=["krb5", "kadm5srv"], + libraries=["krb5", "kadm5srv", "kdb5"], include_dirs=["/usr/include/", "/usr/include/et/"], sources=[ "./kadmin.c", diff --git a/test/unittests.py b/test/unittests.py index 9cb56e7..cb7c5eb 100644 --- a/test/unittests.py +++ b/test/unittests.py @@ -196,6 +196,22 @@ def test_iteration(self): self.assertEqual(count, size) + ''' + def test_each_iteration(self): + + kadm = self.kadm + count = [0] + + size = database_size() + + def fxn(princ): + count[0] += 1 + + kadm.each_principal(lambda princ: fxn(princ)) + + self.assertEqual(count[0], size) + + ''' ''' unpack iteration is SLOW over GSSAPI connections, while still enabled it is advised that this is only used via kadmin.local def test_unpack_iteration(self): @@ -209,7 +225,6 @@ def test_unpack_iteration(self): count += 1 self.assertEqual(count, size) - ''' def test_filter_iteration(self): @@ -220,12 +235,13 @@ def test_filter_iteration(self): create_test_accounts() - for princ in kadm.principals('test[0-9][0-9]', unpack=True): + for princ in kadm.principals('test*', unpack=True): count += 1 self.assertEqual(count, size) delete_test_accounts() + ''' def test_not_exists(self): @@ -378,7 +394,23 @@ def test_iteration(self): count += 1 self.assertEqual(count, size) - + + def test_each_iteration(self): + + kadm = self.kadm + count = [0] + + size = database_size() + + def fxn(princ): + count[0] += 1 + + kadm.each_principal(lambda princ: fxn(princ)) + + self.assertEqual(count[0], size) + + + '''' def test_unpack_iteration(self): kadm = self.kadm @@ -398,7 +430,7 @@ def test_unpack_iteration(self): logging.info("unpacked iteration: {0} principals unpacked in {1} seconds [{2} per second].".format(count, time_d, (count/time_d))) self.assertEqual(count, size) - + def test_filter_iteration(self): kadm = self.kadm @@ -414,7 +446,8 @@ def test_filter_iteration(self): self.assertEqual(count, size) delete_test_accounts() - + ''' + def test_not_exists(self): kadm = self.kadm From a93b3948dbd26236e9b602289fa0a8d40e964b8a Mon Sep 17 00:00:00 2001 From: Russell Jancewicz Date: Mon, 7 Jul 2014 16:42:29 -0400 Subject: [PATCH 4/4] update markdown --- PyKAdminObject.c | 2 +- README.md | 30 +++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/PyKAdminObject.c b/PyKAdminObject.c index cd499e5..e5ec857 100644 --- a/PyKAdminObject.c +++ b/PyKAdminObject.c @@ -218,7 +218,7 @@ static PyObject *PyKAdminObject_each_principal(PyKAdminObject *self, PyObject *a kadm5_ret_t lock = 0; - static char *kwlist[] = {"", "args", "match", NULL}; + static char *kwlist[] = {"", "arg", "match", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|Oz", kwlist, &PyFunction_Type, &self->each_principal.callback, &self->each_principal.arg, &match)) return NULL; diff --git a/README.md b/README.md index 12ff9ae..8301e60 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,31 @@ for princ in kadm.principals('r*@EXAMPLE.COM'): # princ is a string starting with 'r' and ending with '@EXAMPLE.COM' print princ -for princ in kadm.principals('*', unpack=True): - # princ is a kadmin principal object - print princ +# unpacked iteration +# prints each principal, data is optiona + +def callback_a(princ, data): + print(princ) + +def callback_b(princ, data): + print("{0}, {1}".format(data, princ)) + +# invoke callback_a for each principal, equivilent of the above iteration. +kadm.each_principal(callback_a) + +# invoke callback_b for each principal resulting in "Hello, principal@EXAMPLE.COM" +kadm.each_principal(callback_b, "Hello ") + +# +# WARNING: unpack iteration deprecated in favor of "each iteration" with callbacks. +# unless run on the default backend via kadmin_local unpack iteration is *extremely* slow. +# + +# old style unpack iteration [updated] +# replaces: kadm.principals('*', unpack=True) + +for princ in kadm.principals('*'): + principal = kadm.get_princ(princ) + # use principal as needed + ```