From f8c417d0a344331267f2bdef180d163fe9405bd6 Mon Sep 17 00:00:00 2001 From: Denys Duchier Date: Thu, 23 Oct 2014 14:41:44 +0200 Subject: [PATCH 1/2] add support for database options in create_principal --- PyKAdminObject.c | 117 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 110 insertions(+), 7 deletions(-) diff --git a/PyKAdminObject.c b/PyKAdminObject.c index f2809f0..17bea9a 100644 --- a/PyKAdminObject.c +++ b/PyKAdminObject.c @@ -126,6 +126,94 @@ static PyObject *PyKAdminObject_delete_principal(PyKAdminObject *self, PyObject } +/****************************************************************************** + add_tl_data + free_tl_data + these functions come from the KRB5 code base + ******************************************************************************/ + +static void +free_tl_data(krb5_int16 *n_tl_datap, krb5_tl_data **tl_datap) +{ + krb5_tl_data *tl_data = *tl_datap, *next; + int n_tl_data = *n_tl_datap; + int i; + + *n_tl_datap = 0; + *tl_datap = NULL; + + for (i = 0; tl_data && (i < n_tl_data); i++) { + next = tl_data->tl_data_next; + free(tl_data->tl_data_contents); + free(tl_data); + tl_data = next; + } +} + +/* Construct a tl_data element and add it to the tail of *tl_datap. */ +static int +add_tl_data(krb5_int16 *n_tl_datap, krb5_tl_data **tl_datap, + krb5_int16 tl_type, krb5_ui_2 len, krb5_octet *contents) +{ + krb5_tl_data *tl_data; + krb5_octet *copy; + + copy = malloc(len); + tl_data = calloc(1, sizeof(*tl_data)); + if (copy == NULL || tl_data == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Not enough memory"); + return 1; + } + memcpy(copy, contents, len); + + tl_data->tl_data_type = tl_type; + tl_data->tl_data_length = len; + tl_data->tl_data_contents = copy; + tl_data->tl_data_next = NULL; + + for (; *tl_datap != NULL; tl_datap = &(*tl_datap)->tl_data_next); + *tl_datap = tl_data; + (*n_tl_datap)++; + return 0; +} + +static int +process_principal_x_arg(kadm5_principal_ent_rec *entry, PyObject *arg, long *mask) +{ + if (PyUnicode_Check(arg)) { + const char* data = PyUnicode_AS_DATA(arg); + add_tl_data(&entry->n_tl_data, &entry->tl_data, + KRB5_TL_DB_ARGS, strlen(data)+1, + (krb5_octet*) data); + *mask |= KADM5_TL_DATA; + } + else if (PyString_Check(arg)) { + char* data = PyString_AS_STRING(arg); + add_tl_data(&entry->n_tl_data, &entry->tl_data, + KRB5_TL_DB_ARGS, strlen(data)+1, + (krb5_octet*) data); + *mask |= KADM5_TL_DATA; + } + else if (PySequence_Check(arg)) { + int n = PySequence_Length(arg); + int i; + for (i=0; iserver_handle) { code = krb5_parse_name(self->context, princ_name, &entry.principal); - if (code) { PyKAdmin_RETURN_ERROR(retval, "krb5_parse_name"); } - - retval = kadm5_create_principal(self->server_handle, &entry, KADM5_PRINCIPAL, princ_pass); - if (retval != KADM5_OK) { PyKAdmin_RETURN_ERROR(retval, "kadm5_create_principal"); } + if (code) { + PyKAdminError_raise_error((long)retval, "krb5_parse_name"); + has_error = 1; + goto epilog; + } + + retval = kadm5_create_principal(self->server_handle, &entry, mask, princ_pass); + if (retval != KADM5_OK) { + PyKAdminError_raise_error((long)retval, "kadm5_create_principal"); + has_error = 1; + goto epilog; + } } + epilog: kadm5_free_principal_ent(self->server_handle, &entry); + free_tl_data(&entry.n_tl_data, &entry.tl_data); + if (has_error) return NULL; Py_RETURN_TRUE; } @@ -395,9 +498,9 @@ static PyObject *PyKAdminObject_each_policy(PyKAdminObject *self, PyObject *args static PyMethodDef PyKAdminObject_methods[] = { - {"ank", (PyCFunction)PyKAdminObject_create_principal, METH_VARARGS, ""}, - {"addprinc", (PyCFunction)PyKAdminObject_create_principal, METH_VARARGS, ""}, - {"add_principal", (PyCFunction)PyKAdminObject_create_principal, METH_VARARGS, ""}, + {"ank", (PyCFunction)PyKAdminObject_create_principal, (METH_VARARGS | METH_KEYWORDS), ""}, + {"addprinc", (PyCFunction)PyKAdminObject_create_principal, (METH_VARARGS | METH_KEYWORDS), ""}, + {"add_principal", (PyCFunction)PyKAdminObject_create_principal, (METH_VARARGS | METH_KEYWORDS), ""}, {"delprinc", (PyCFunction)PyKAdminObject_delete_principal, METH_VARARGS, ""}, {"delete_principal", (PyCFunction)PyKAdminObject_delete_principal, METH_VARARGS, ""}, From f3990be419829e2500b64312428527f603676f51 Mon Sep 17 00:00:00 2001 From: Denys Duchier Date: Thu, 23 Oct 2014 16:25:38 +0200 Subject: [PATCH 2/2] changed PyKAdmin_RETURN_ERROR to not leak memory --- PyKAdminErrors.h | 2 +- PyKAdminIterator.c | 8 ++++++-- PyKAdminObject.c | 51 ++++++++++++++++++++++------------------------ kadmin.c | 46 ++++++++++++++++++++++++++++++++--------- 4 files changed, 67 insertions(+), 40 deletions(-) diff --git a/PyKAdminErrors.h b/PyKAdminErrors.h index ffaeb6d..c650bf4 100644 --- a/PyKAdminErrors.h +++ b/PyKAdminErrors.h @@ -12,7 +12,7 @@ #include "pykadmin.h" -#define PyKAdmin_RETURN_ERROR(value, caller) { PyKAdminError_raise_error((long)value, caller); return NULL; } +#define PyKAdmin_RETURN_ERROR(value, caller) { PyKAdminError_raise_error((long)value, caller); has_error=1; goto epilog; } //#define PyKAdmin_RETURN_KADM5_ERROR(retval, caller) { PyKAdminError_raise_kadm_error(retval, caller); return NULL; } //#define PyKAdmin_RETURN_KRB5_ERROR(code, caller) { PyKAdminError_raise_krb5_error(code, caller); return NULL; } diff --git a/PyKAdminIterator.c b/PyKAdminIterator.c index 23efd6e..60833ef 100644 --- a/PyKAdminIterator.c +++ b/PyKAdminIterator.c @@ -82,6 +82,7 @@ PyKAdminIterator *PyKAdminIterator_principal_iterator(PyKAdminObject *kadmin, ch kadm5_ret_t retval = KADM5_OK; PyKAdminIterator *iter = PyObject_New(PyKAdminIterator, &PyKAdminIterator_Type); + int has_error = 0; if (iter) { @@ -94,7 +95,8 @@ PyKAdminIterator *PyKAdminIterator_principal_iterator(PyKAdminObject *kadmin, ch retval = kadm5_get_principals(kadmin->server_handle, match, &iter->names, &iter->count); if (retval != KADM5_OK) { PyKAdmin_RETURN_ERROR(retval, "kadm5_get_principals"); } } - + epilog: + if (has_error) return NULL; Py_XINCREF(iter); return iter; } @@ -104,6 +106,7 @@ PyKAdminIterator *PyKAdminIterator_policy_iterator(PyKAdminObject *kadmin, char kadm5_ret_t retval = KADM5_OK; PyKAdminIterator *iter = PyObject_New(PyKAdminIterator, &PyKAdminIterator_Type); + int has_error = 0; if (iter) { @@ -116,7 +119,8 @@ PyKAdminIterator *PyKAdminIterator_policy_iterator(PyKAdminObject *kadmin, char retval = kadm5_get_policies(kadmin->server_handle, match, &iter->names, &iter->count); if (retval != KADM5_OK) { PyKAdmin_RETURN_ERROR(retval, "kadm5_get_policies"); } } - + epilog: + if (has_error) return NULL; Py_XINCREF(iter); return iter; } diff --git a/PyKAdminObject.c b/PyKAdminObject.c index 17bea9a..7e169a8 100644 --- a/PyKAdminObject.c +++ b/PyKAdminObject.c @@ -39,6 +39,7 @@ static PyObject *PyKAdminObject_new(PyTypeObject *type, PyObject *args, PyObject PyKAdminObject *self = NULL; kadm5_ret_t retval = KADM5_OK; krb5_error_code code = 0; + int has_error = 0; self = (PyKAdminObject *)type->tp_alloc(type, 0); @@ -55,9 +56,9 @@ static PyObject *PyKAdminObject_new(PyTypeObject *type, PyObject *args, PyObject self->_storage = PyDict_New(); } - + epilog: + if (has_error) return NULL; return (PyObject *)self; - } static int PyKAdminObject_init(PyKAdminObject *self, PyObject *args, PyObject *kwds) { @@ -75,6 +76,9 @@ static PyObject *PyKAdminObject_principal_exists(PyKAdminObject *self, PyObject PyObject *result = NULL; kadm5_principal_ent_rec entry; + int has_error = 0; + + memset(&entry, 0, sizeof(entry)); if (!PyArg_ParseTuple(args, "s", &client_name)) return NULL; @@ -89,10 +93,10 @@ static PyObject *PyKAdminObject_principal_exists(PyKAdminObject *self, PyObject else if (retval == KADM5_UNK_PRINC) { result = Py_False; } else { PyKAdmin_RETURN_ERROR(retval, "kadm5_delete_principal"); } } - - krb5_free_principal(self->context, princ); + epilog: + if (princ) krb5_free_principal(self->context, princ); kadm5_free_principal_ent(self->server_handle, &entry); - + if (has_error) return NULL; Py_XINCREF(result); return result; @@ -104,6 +108,7 @@ static PyObject *PyKAdminObject_delete_principal(PyKAdminObject *self, PyObject kadm5_ret_t retval = KADM5_OK; krb5_error_code code = 0; krb5_principal princ = NULL; + int has_error = 0; char *client_name = NULL; @@ -116,14 +121,12 @@ static PyObject *PyKAdminObject_delete_principal(PyKAdminObject *self, PyObject if (code) { PyKAdmin_RETURN_ERROR(retval, "krb5_parse_name"); } retval = kadm5_delete_principal(self->server_handle, princ); - if (retval != KADM5_OK) { PyKAdmin_RETURN_ERROR(retval, "kadm5_delete_principal"); } - + if (retval != KADM5_OK) { PyKAdmin_RETURN_ERROR(retval, "kadm5_create_principal"); } } - + epilog: krb5_free_principal(self->context, princ); - + if (has_error) return NULL; Py_RETURN_TRUE; - } /****************************************************************************** @@ -239,25 +242,15 @@ static PyObject *PyKAdminObject_create_principal(PyKAdminObject *self, PyObject if (self->server_handle) { code = krb5_parse_name(self->context, princ_name, &entry.principal); - if (code) { - PyKAdminError_raise_error((long)retval, "krb5_parse_name"); - has_error = 1; - goto epilog; - } + if (code) { PyKAdmin_RETURN_ERROR(retval, "krb5_parse_name"); } retval = kadm5_create_principal(self->server_handle, &entry, mask, princ_pass); - if (retval != KADM5_OK) { - PyKAdminError_raise_error((long)retval, "kadm5_create_principal"); - has_error = 1; - goto epilog; - } - + if (retval != KADM5_OK) { PyKAdmin_RETURN_ERROR(retval, "kadm5_create_principal"); } } epilog: kadm5_free_principal_ent(self->server_handle, &entry); free_tl_data(&entry.n_tl_data, &entry.tl_data); - if (has_error) return NULL; Py_RETURN_TRUE; } @@ -383,7 +376,8 @@ static PyObject *PyKAdminObject_each_principal(PyKAdminObject *self, PyObject *a char *match = NULL; krb5_error_code code = 0; - kadm5_ret_t lock = KADM5_OK; + kadm5_ret_t lock = KADM5_OK; + int has_error = 0; static char *kwlist[] = {"callback", "data", "match", NULL}; @@ -404,7 +398,7 @@ static PyObject *PyKAdminObject_each_principal(PyKAdminObject *self, PyObject *a krb5_clear_error_message(self->context); - code = krb5_db_iterate(self->context, match, kdb_iter_princs, (void *)self); + code = krb5_db_iterate(self->context, match, kdb_iter_princs, (void *)self, 0); if (lock != KRB5_PLUGIN_OP_NOTSUPP) lock = kadm5_unlock(self->server_handle); @@ -420,7 +414,8 @@ static PyObject *PyKAdminObject_each_principal(PyKAdminObject *self, PyObject *a return NULL; } - + epilog: + if (has_error) return NULL; Py_RETURN_TRUE; } @@ -456,7 +451,8 @@ static PyObject *PyKAdminObject_each_policy(PyKAdminObject *self, PyObject *args char *match = NULL; krb5_error_code code = 0; - kadm5_ret_t lock = KADM5_OK; + kadm5_ret_t lock = KADM5_OK; + int has_error = 0; static char *kwlist[] = {"", "data", "match", NULL}; @@ -490,7 +486,8 @@ static PyObject *PyKAdminObject_each_policy(PyKAdminObject *self, PyObject *args _pykadmin_each_restore_error(self->each_policy.error); return NULL; } - + epilog: + if (has_error) return NULL; Py_RETURN_TRUE; } diff --git a/kadmin.c b/kadmin.c index 4c85c78..4867410 100644 --- a/kadmin.c +++ b/kadmin.c @@ -252,6 +252,7 @@ static PyKAdminObject *_kadmin_local(PyObject *self, PyObject *args) { int result = 0; char **db_args = NULL; char *client_name = NULL; + int has_error = 0; if (!PyArg_ParseTuple(args, "|O!", &PyDict_Type, &db_args_dict)) return NULL; @@ -278,13 +279,17 @@ static PyKAdminObject *_kadmin_local(PyObject *self, PyObject *args) { db_args, &kadmin->server_handle); - if (db_args) + if (db_args) { _kadmin_free_db_args(db_args); + db_args = NULL; + } if (retval != KADM5_OK) { PyKAdmin_RETURN_ERROR(retval, "kadm5_init_with_password.local"); } + epilog: + if (db_args) _kadmin_free_db_args(db_args); + if (has_error) return NULL; return kadmin; - } #endif @@ -301,7 +306,8 @@ static PyKAdminObject *_kadmin_init_with_ccache(PyObject *self, PyObject *args) char *client_name = NULL; char **db_args = NULL; - krb5_ccache cc; + krb5_ccache cc; + int has_error = 0; kadm5_config_params *params = calloc(0x1, sizeof(kadm5_config_params)); @@ -329,6 +335,7 @@ static PyKAdminObject *_kadmin_init_with_ccache(PyObject *self, PyObject *args) if (code) { PyKAdmin_RETURN_ERROR(code, "krb5_unparse_name"); } krb5_free_principal(kadmin->context, princ); + princ = NULL; } retval = kadm5_init_with_creds( @@ -342,11 +349,17 @@ static PyKAdminObject *_kadmin_init_with_ccache(PyObject *self, PyObject *args) db_args, &kadmin->server_handle); - if (db_args) + if (db_args) { _kadmin_free_db_args(db_args); + db_args = NULL; + } if (retval != KADM5_OK) { PyKAdmin_RETURN_ERROR(retval, "kadm5_init_with_creds"); } + epilog: + if (princ) krb5_free_principal(kadmin->context, princ); + if (db_args) _kadmin_free_db_args(db_args); + if (has_error) return NULL; Py_XINCREF(kadmin); return kadmin; } @@ -364,6 +377,7 @@ static PyKAdminObject *_kadmin_init_with_keytab(PyObject *self, PyObject *args) char *client_name = NULL; char *keytab_name = NULL; char **db_args = NULL; + int has_error = 0; kadm5_config_params *params = calloc(0x1, sizeof(kadm5_config_params)); @@ -385,6 +399,7 @@ static PyKAdminObject *_kadmin_init_with_keytab(PyObject *self, PyObject *args) if (code) { PyKAdmin_RETURN_ERROR(code, "krb5_unparse_name"); } krb5_free_principal(kadmin->context, princ); + princ = NULL; } @@ -399,13 +414,17 @@ static PyKAdminObject *_kadmin_init_with_keytab(PyObject *self, PyObject *args) db_args, &kadmin->server_handle); - if (db_args) + if (db_args) { _kadmin_free_db_args(db_args); + db_args = NULL; + } if (retval != KADM5_OK) { PyKAdmin_RETURN_ERROR(retval, "kadm5_init_with_skey"); } - - + epilog: + if (princ) krb5_free_principal(kadmin->context, princ); + if (db_args) _kadmin_free_db_args(db_args); + if (has_error) return NULL; Py_XINCREF(kadmin); return kadmin; } @@ -420,8 +439,10 @@ static PyKAdminObject *_kadmin_init_with_password(PyObject *self, PyObject *args char *client_name = NULL; char *password = NULL; char **db_args = NULL; + int has_error = 0; - kadm5_config_params *params = calloc(0x1, sizeof(kadm5_config_params)); + kadm5_config_params params; + memset(¶ms, 0, sizeof(params)); if (!PyArg_ParseTuple(args, "zz|O!", &client_name, &password, &PyDict_Type, &db_args_dict)) return NULL; @@ -433,17 +454,22 @@ static PyKAdminObject *_kadmin_init_with_password(PyObject *self, PyObject *args client_name, password, service_name, - params, + ¶ms, struct_version, api_version, db_args, &kadmin->server_handle); - if (db_args) + if (db_args) { _kadmin_free_db_args(db_args); + db_args = NULL; + } if (retval != KADM5_OK) { PyKAdmin_RETURN_ERROR(retval, "kadm5_init_with_password"); } + epilog: + if (db_args) _kadmin_free_db_args(db_args); + if (has_error) return NULL; Py_XINCREF(kadmin); return kadmin;