X-Git-Url: http://git.samba.org/?p=kamenim%2Fsamba.git;a=blobdiff_plain;f=source4%2Flib%2Fldb%2Fpyldb.c;h=925ea5232aaf833be2475266ac2eabe851d73e5e;hp=2e0f4fdf3606b88576b905d8949aa8417171825e;hb=dbf121e7b5d85df724aea5675b61fc8f53e6e1d9;hpb=f45a9d63e5a1697a7e85b123b535d2dc05f9fd8c diff --git a/source4/lib/ldb/pyldb.c b/source4/lib/ldb/pyldb.c index 2e0f4fdf36..925ea5232a 100644 --- a/source4/lib/ldb/pyldb.c +++ b/source4/lib/ldb/pyldb.c @@ -5,7 +5,8 @@ Copyright (C) 2005,2006 Tim Potter Copyright (C) 2006 Simo Sorce - Copyright (C) 2007-2009 Jelmer Vernooij + Copyright (C) 2007-2010 Jelmer Vernooij + Copyright (C) 2009-2010 Matthias Dieter Wallnöfer ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -25,9 +26,9 @@ License along with this library; if not, see . */ +#include #include "replace.h" #include "ldb_private.h" -#include #include "pyldb.h" /* There's no Py_ssize_t in 2.4, apparently */ @@ -41,6 +42,16 @@ typedef intargfunc ssizeargfunc; #define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None #endif +static void PyErr_SetLdbError(PyObject *error, int ret, struct ldb_context *ldb_ctx) +{ + if (ret == LDB_ERR_PYTHON_EXCEPTION) + return; /* Python exception should already be set, just keep that */ + + PyErr_SetObject(error, + Py_BuildValue(discard_const_p(char, "(i,s)"), ret, + ldb_ctx == NULL?ldb_strerror(ret):ldb_errstring(ldb_ctx))); +} + static PyObject *PyExc_LdbError; PyAPI_DATA(PyTypeObject) PyLdbMessage; @@ -50,6 +61,8 @@ PyAPI_DATA(PyTypeObject) PyLdb; PyAPI_DATA(PyTypeObject) PyLdbMessageElement; PyAPI_DATA(PyTypeObject) PyLdbTree; +static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx); + static PyObject *PyObject_FromLdbValue(struct ldb_context *ldb_ctx, struct ldb_message_element *el, struct ldb_val *val) @@ -67,34 +80,6 @@ static PyObject *PyObject_FromLdbValue(struct ldb_context *ldb_ctx, return ret; } -/** - * Obtain a ldb DN from a Python object. - * - * @param mem_ctx Memory context - * @param object Python object - * @param ldb_ctx LDB context - * @return Whether or not the conversion succeeded - */ -bool PyObject_AsDn(TALLOC_CTX *mem_ctx, PyObject *object, - struct ldb_context *ldb_ctx, struct ldb_dn **dn) -{ - struct ldb_dn *odn; - - if (ldb_ctx != NULL && PyString_Check(object)) { - odn = ldb_dn_new(mem_ctx, ldb_ctx, PyString_AsString(object)); - *dn = odn; - return true; - } - - if (PyLdbDn_Check(object)) { - *dn = PyLdbDn_AsDn(object); - return true; - } - - PyErr_SetString(PyExc_TypeError, "Expected DN"); - return false; -} - /** * Create a Python object from a ldb_result. * @@ -200,7 +185,11 @@ static PyObject *py_ldb_dn_check_special(PyLdbDnObject *self, PyObject *args) static int py_ldb_dn_compare(PyLdbDnObject *dn1, PyLdbDnObject *dn2) { - return ldb_dn_compare(dn1->dn, dn2->dn); + int ret; + ret = ldb_dn_compare(dn1->dn, dn2->dn); + if (ret < 0) ret = -1; + if (ret > 0) ret = 1; + return ret; } static PyObject *py_ldb_dn_get_parent(PyLdbDnObject *self) @@ -393,7 +382,7 @@ static void py_ldb_dn_dealloc(PyLdbDnObject *self) } PyTypeObject PyLdbDn = { - .tp_name = "Dn", + .tp_name = "ldb.Dn", .tp_methods = py_ldb_dn_methods, .tp_str = (reprfunc)py_ldb_dn_get_linearized, .tp_repr = (reprfunc)py_ldb_dn_repr, @@ -462,6 +451,12 @@ static PyObject *py_ldb_transaction_commit(PyLdbObject *self) Py_RETURN_NONE; } +static PyObject *py_ldb_transaction_prepare_commit(PyLdbObject *self) +{ + PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_transaction_prepare_commit(PyLdb_AsLdbContext(self)), PyLdb_AsLdbContext(self)); + Py_RETURN_NONE; +} + static PyObject *py_ldb_transaction_cancel(PyLdbObject *self) { PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_transaction_cancel(PyLdb_AsLdbContext(self)), PyLdb_AsLdbContext(self)); @@ -528,7 +523,8 @@ static const char **PyList_AsStringList(TALLOC_CTX *mem_ctx, PyObject *list, PyErr_Format(PyExc_TypeError, "%s should be strings", paramname); return NULL; } - ret[i] = PyString_AsString(item); + ret[i] = talloc_strndup(ret, PyString_AsString(item), + PyString_Size(item)); } ret[i] = NULL; return ret; @@ -601,7 +597,7 @@ static PyObject *py_ldb_connect(PyLdbObject *self, PyObject *args, PyObject *kwa const char **options; const char * const kwnames[] = { "url", "flags", "options", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|iO", + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ziO", discard_const_p(char *, kwnames), &url, &flags, &py_options)) return NULL; @@ -625,21 +621,85 @@ static PyObject *py_ldb_connect(PyLdbObject *self, PyObject *args, PyObject *kwa static PyObject *py_ldb_modify(PyLdbObject *self, PyObject *args) { PyObject *py_msg; + PyObject *py_controls = Py_None; + struct ldb_context *ldb_ctx; + struct ldb_request *req; + struct ldb_control **parsed_controls; + struct ldb_message *msg; int ret; - if (!PyArg_ParseTuple(args, "O", &py_msg)) + TALLOC_CTX *mem_ctx; + + if (!PyArg_ParseTuple(args, "O|O", &py_msg, &py_controls)) return NULL; + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + ldb_ctx = PyLdb_AsLdbContext(self); + + if (py_controls == Py_None) { + parsed_controls = NULL; + } else { + const char **controls = PyList_AsStringList(mem_ctx, py_controls, "controls"); + parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls); + talloc_free(controls); + } + if (!PyLdbMessage_Check(py_msg)) { PyErr_SetString(PyExc_TypeError, "Expected Ldb Message"); + talloc_free(mem_ctx); return NULL; } + msg = PyLdbMessage_AsMessage(py_msg); - ret = ldb_modify(PyLdb_AsLdbContext(self), PyLdbMessage_AsMessage(py_msg)); - PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, PyLdb_AsLdbContext(self)); + ret = ldb_msg_sanity_check(ldb_ctx, msg); + if (ret != LDB_SUCCESS) { + PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx); + talloc_free(mem_ctx); + return NULL; + } + + ret = ldb_build_mod_req(&req, ldb_ctx, mem_ctx, msg, parsed_controls, + NULL, ldb_op_default_callback, NULL); + if (ret != LDB_SUCCESS) { + PyErr_SetString(PyExc_TypeError, "failed to build request"); + talloc_free(mem_ctx); + return NULL; + } + + /* do request and autostart a transaction */ + /* Then let's LDB handle the message error in case of pb as they are meaningful */ + + ret = ldb_transaction_start(ldb_ctx); + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx); + } + + ret = ldb_request(ldb_ctx, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + if (ret == LDB_SUCCESS) { + ret = ldb_transaction_commit(ldb_ctx); + } else { + ldb_transaction_cancel(ldb_ctx); + if (ldb_ctx->err_string == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb_ctx, "%s (%d)", ldb_strerror(ret), ret); + } + } + + talloc_free(mem_ctx); + PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx); Py_RETURN_NONE; } + static PyObject *py_ldb_add(PyLdbObject *self, PyObject *args) { PyObject *py_msg; @@ -647,21 +707,37 @@ static PyObject *py_ldb_add(PyLdbObject *self, PyObject *args) Py_ssize_t dict_pos, msg_pos; struct ldb_message_element *msgel; struct ldb_message *msg; + struct ldb_context *ldb_ctx; + struct ldb_request *req; PyObject *key, *value; + PyObject *py_controls = Py_None; TALLOC_CTX *mem_ctx; + struct ldb_control **parsed_controls; - if (!PyArg_ParseTuple(args, "O", &py_msg)) + if (!PyArg_ParseTuple(args, "O|O", &py_msg, &py_controls )) return NULL; mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + ldb_ctx = PyLdb_AsLdbContext(self); + if (py_controls == Py_None) { + parsed_controls = NULL; + } else { + const char **controls = PyList_AsStringList(mem_ctx, py_controls, "controls"); + parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls); + talloc_free(controls); + } if (PyDict_Check(py_msg)) { PyObject *dn_value = PyDict_GetItemString(py_msg, "dn"); msg = ldb_msg_new(mem_ctx); msg->elements = talloc_zero_array(msg, struct ldb_message_element, PyDict_Size(py_msg)); msg_pos = dict_pos = 0; if (dn_value) { - if (!PyObject_AsDn(msg, dn_value, PyLdb_AsLdbContext(self), &msg->dn)) { + if (!PyObject_AsDn(msg, dn_value, ldb_ctx, &msg->dn)) { PyErr_SetString(PyExc_TypeError, "unable to import dn object"); talloc_free(mem_ctx); return NULL; @@ -697,10 +773,48 @@ static PyObject *py_ldb_add(PyLdbObject *self, PyObject *args) } else { msg = PyLdbMessage_AsMessage(py_msg); } + + ret = ldb_msg_sanity_check(ldb_ctx, msg); + if (ret != LDB_SUCCESS) { + PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx); + talloc_free(mem_ctx); + return NULL; + } + + ret = ldb_build_add_req(&req, ldb_ctx, mem_ctx, msg, parsed_controls, + NULL, ldb_op_default_callback, NULL); + if (ret != LDB_SUCCESS) { + PyErr_SetString(PyExc_TypeError, "failed to build request"); + talloc_free(mem_ctx); + return NULL; + } + + /* do request and autostart a transaction */ + /* Then let's LDB handle the message error in case of pb as they are meaningful */ + + ret = ldb_transaction_start(ldb_ctx); + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx); + } + + ret = ldb_request(ldb_ctx, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + if (ret == LDB_SUCCESS) { + ret = ldb_transaction_commit(ldb_ctx); + } else { + ldb_transaction_cancel(ldb_ctx); + if (ldb_ctx->err_string == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb_ctx, "%s (%d)", ldb_strerror(ret), ret); + } + } - ret = ldb_add(PyLdb_AsLdbContext(self), msg); talloc_free(mem_ctx); - PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, PyLdb_AsLdbContext(self)); + PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx); Py_RETURN_NONE; } @@ -710,17 +824,69 @@ static PyObject *py_ldb_delete(PyLdbObject *self, PyObject *args) PyObject *py_dn; struct ldb_dn *dn; int ret; - struct ldb_context *ldb; - if (!PyArg_ParseTuple(args, "O", &py_dn)) + struct ldb_context *ldb_ctx; + struct ldb_request *req; + PyObject *py_controls = Py_None; + TALLOC_CTX *mem_ctx; + struct ldb_control **parsed_controls; + + if (!PyArg_ParseTuple(args, "O|O", &py_dn, &py_controls)) return NULL; - ldb = PyLdb_AsLdbContext(self); + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + ldb_ctx = PyLdb_AsLdbContext(self); + + if (py_controls == Py_None) { + parsed_controls = NULL; + } else { + const char **controls = PyList_AsStringList(mem_ctx, py_controls, "controls"); + parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls); + talloc_free(controls); + } - if (!PyObject_AsDn(NULL, py_dn, ldb, &dn)) + if (!PyObject_AsDn(mem_ctx, py_dn, ldb_ctx, &dn)) { + talloc_free(mem_ctx); return NULL; + } - ret = ldb_delete(ldb, dn); - PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb); + ret = ldb_build_del_req(&req, ldb_ctx, mem_ctx, dn, parsed_controls, + NULL, ldb_op_default_callback, NULL); + if (ret != LDB_SUCCESS) { + PyErr_SetString(PyExc_TypeError, "failed to build request"); + talloc_free(mem_ctx); + return NULL; + } + + /* do request and autostart a transaction */ + /* Then let's LDB handle the message error in case of pb as they are meaningful */ + + ret = ldb_transaction_start(ldb_ctx); + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx); + } + + ret = ldb_request(ldb_ctx, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + if (ret == LDB_SUCCESS) { + ret = ldb_transaction_commit(ldb_ctx); + } else { + ldb_transaction_cancel(ldb_ctx); + if (ldb_ctx->err_string == NULL) { + /* no error string was setup by the backend */ + ldb_asprintf_errstring(ldb_ctx, "%s (%d)", ldb_strerror(ret), ret); + } + } + + talloc_free(mem_ctx); + PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx); Py_RETURN_NONE; } @@ -732,6 +898,7 @@ static PyObject *py_ldb_rename(PyLdbObject *self, PyObject *args) int ret; struct ldb_context *ldb; TALLOC_CTX *mem_ctx; + if (!PyArg_ParseTuple(args, "OO", &py_dn1, &py_dn2)) return NULL; @@ -740,7 +907,9 @@ static PyObject *py_ldb_rename(PyLdbObject *self, PyObject *args) PyErr_NoMemory(); return NULL; } + ldb = PyLdb_AsLdbContext(self); + if (!PyObject_AsDn(mem_ctx, py_dn1, ldb, &dn1)) { talloc_free(mem_ctx); return NULL; @@ -797,6 +966,41 @@ static PyObject *ldb_ldif_to_pyobject(struct ldb_ldif *ldif) } +static PyObject *py_ldb_write_ldif(PyLdbMessageObject *self, PyObject *args) +{ + int changetype; + PyObject *py_msg; + struct ldb_ldif ldif; + PyObject *ret; + char *string; + TALLOC_CTX *mem_ctx; + + if (!PyArg_ParseTuple(args, "Oi", &py_msg, &changetype)) + return NULL; + + if (!PyLdbMessage_Check(py_msg)) { + PyErr_SetString(PyExc_TypeError, "Expected Ldb Message for msg"); + return NULL; + } + + ldif.msg = PyLdbMessage_AsMessage(py_msg); + ldif.changetype = changetype; + + mem_ctx = talloc_new(NULL); + + string = ldb_ldif_write_string(PyLdb_AsLdbContext(self), mem_ctx, &ldif); + if (!string) { + PyErr_SetString(PyExc_KeyError, "Failed to generate LDIF"); + return NULL; + } + + ret = PyString_FromString(string); + + talloc_free(mem_ctx); + + return ret; +} + static PyObject *py_ldb_parse_ldif(PyLdbObject *self, PyObject *args) { PyObject *list; @@ -829,6 +1033,45 @@ static PyObject *py_ldb_parse_ldif(PyLdbObject *self, PyObject *args) return PyObject_GetIter(list); } +static PyObject *py_ldb_msg_diff(PyLdbObject *self, PyObject *args) +{ + int ldb_ret; + PyObject *py_msg_old; + PyObject *py_msg_new; + struct ldb_message *diff; + struct ldb_context *ldb; + PyObject *py_ret; + + if (!PyArg_ParseTuple(args, "OO", &py_msg_old, &py_msg_new)) + return NULL; + + if (!PyLdbMessage_Check(py_msg_old)) { + PyErr_SetString(PyExc_TypeError, "Expected Ldb Message for old message"); + return NULL; + } + + if (!PyLdbMessage_Check(py_msg_new)) { + PyErr_SetString(PyExc_TypeError, "Expected Ldb Message for new message"); + return NULL; + } + + ldb = PyLdb_AsLdbContext(self); + ldb_ret = ldb_msg_diff_ex(ldb, + PyLdbMessage_AsMessage(py_msg_old), + PyLdbMessage_AsMessage(py_msg_new), + (TALLOC_CTX*)ldb, &diff); + if (ldb_ret != LDB_SUCCESS) { + PyErr_SetString(PyExc_RuntimeError, "Failed to generate the Ldb Message diff"); + return NULL; + } + + py_ret = PyLdbMessage_FromMessage(diff); + + talloc_unlink(ldb, diff); + + return py_ret; +} + static PyObject *py_ldb_schema_format_value(PyLdbObject *self, PyObject *args) { const struct ldb_schema_attribute *a; @@ -868,7 +1111,7 @@ static PyObject *py_ldb_schema_format_value(PyLdbObject *self, PyObject *args) static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwargs) { PyObject *py_base = Py_None; - enum ldb_scope scope = LDB_SCOPE_DEFAULT; + int scope = LDB_SCOPE_DEFAULT; char *expr = NULL; PyObject *py_attrs = Py_None; PyObject *py_controls = Py_None; @@ -881,20 +1124,30 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar struct ldb_control **parsed_controls; struct ldb_dn *base; PyObject *py_ret; + TALLOC_CTX *mem_ctx; + /* type "int" rather than "enum" for "scope" is intentional */ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OizOO", discard_const_p(char *, kwnames), &py_base, &scope, &expr, &py_attrs, &py_controls)) return NULL; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } ldb_ctx = PyLdb_AsLdbContext(self); if (py_attrs == Py_None) { attrs = NULL; } else { - attrs = PyList_AsStringList(NULL, py_attrs, "attrs"); - if (attrs == NULL) + attrs = PyList_AsStringList(mem_ctx, py_attrs, "attrs"); + if (attrs == NULL) { + talloc_free(mem_ctx); return NULL; + } } if (py_base == Py_None) { @@ -909,19 +1162,19 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar if (py_controls == Py_None) { parsed_controls = NULL; } else { - const char **controls = PyList_AsStringList(ldb_ctx, py_controls, "controls"); - parsed_controls = ldb_parse_control_strings(ldb_ctx, ldb_ctx, controls); + const char **controls = PyList_AsStringList(mem_ctx, py_controls, "controls"); + parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls); talloc_free(controls); } - res = talloc_zero(ldb_ctx, struct ldb_result); + res = talloc_zero(mem_ctx, struct ldb_result); if (res == NULL) { PyErr_NoMemory(); - talloc_free(attrs); + talloc_free(mem_ctx); return NULL; } - ret = ldb_build_search_req(&req, ldb_ctx, ldb_ctx, + ret = ldb_build_search_req(&req, ldb_ctx, mem_ctx, base, scope, expr, @@ -934,7 +1187,7 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar talloc_steal(req, attrs); if (ret != LDB_SUCCESS) { - talloc_free(res); + talloc_free(mem_ctx); PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx); return NULL; } @@ -945,17 +1198,15 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar ret = ldb_wait(req->handle, LDB_WAIT_ALL); } - talloc_free(req); - if (ret != LDB_SUCCESS) { - talloc_free(res); + talloc_free(mem_ctx); PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx); return NULL; } py_ret = PyLdbResult_FromResult(res); - talloc_free(res); + talloc_free(mem_ctx); return py_ret; } @@ -1020,6 +1271,9 @@ static PyMethodDef py_ldb_methods[] = { { "transaction_start", (PyCFunction)py_ldb_transaction_start, METH_NOARGS, "S.transaction_start() -> None\n" "Start a new transaction." }, + { "transaction_prepare_commit", (PyCFunction)py_ldb_transaction_prepare_commit, METH_NOARGS, + "S.transaction_prepare_commit() -> None\n" + "prepare to commit a new transaction (2-stage commit)." }, { "transaction_commit", (PyCFunction)py_ldb_transaction_commit, METH_NOARGS, "S.transaction_commit() -> None\n" "commit a new transaction." }, @@ -1071,6 +1325,12 @@ static PyMethodDef py_ldb_methods[] = { { "parse_ldif", (PyCFunction)py_ldb_parse_ldif, METH_VARARGS, "S.parse_ldif(ldif) -> iter(messages)\n" "Parse a string formatted using LDIF." }, + { "write_ldif", (PyCFunction)py_ldb_write_ldif, METH_VARARGS, + "S.write_ldif(message, changetype) -> ldif\n" + "Print the message as a string formatted using LDIF." }, + { "msg_diff", (PyCFunction)py_ldb_msg_diff, METH_VARARGS, + "S.msg_diff(Message) -> Message\n" + "Return an LDB Message of the difference between two Message objects." }, { "get_opaque", (PyCFunction)py_ldb_get_opaque, METH_VARARGS, "S.get_opaque(name) -> value\n" "Get an opaque value set on this LDB connection. \n" @@ -1138,7 +1398,7 @@ static PySequenceMethods py_ldb_seq = { .sq_contains = (objobjproc)py_ldb_contains, }; -PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx) +static PyObject *PyLdb_FromLdbContext(struct ldb_context *ldb_ctx) { PyLdbObject *ret; @@ -1159,7 +1419,7 @@ static void py_ldb_dealloc(PyLdbObject *self) } PyTypeObject PyLdb = { - .tp_name = "Ldb", + .tp_name = "ldb.Ldb", .tp_methods = py_ldb_methods, .tp_repr = (reprfunc)py_ldb_repr, .tp_new = py_ldb_new, @@ -1210,6 +1470,7 @@ static PyObject *py_ldb_module_search(PyLdbModuleObject *self, PyObject *args, P struct ldb_module *mod; const char * const*attrs; + /* type "int" rather than "enum" for "scope" is intentional */ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OiOO", discard_const_p(char *, kwnames), &py_base, &scope, &py_tree, &py_attrs)) @@ -1352,7 +1613,7 @@ static void py_ldb_module_dealloc(PyLdbModuleObject *self) } PyTypeObject PyLdbModule = { - .tp_name = "LdbModule", + .tp_name = "ldb.LdbModule", .tp_methods = py_ldb_module_methods, .tp_repr = (reprfunc)py_ldb_module_repr, .tp_str = (reprfunc)py_ldb_module_str, @@ -1383,17 +1644,19 @@ struct ldb_message_element *PyObject_AsMessageElement(TALLOC_CTX *mem_ctx, struct ldb_message_element *me; if (PyLdbMessageElement_Check(set_obj)) - return PyLdbMessageElement_AsMessageElement(set_obj); + return talloc_reference(mem_ctx, + PyLdbMessageElement_AsMessageElement(set_obj)); me = talloc(mem_ctx, struct ldb_message_element); - me->name = attr_name; + me->name = talloc_strdup(me, attr_name); me->flags = flags; if (PyString_Check(set_obj)) { me->num_values = 1; me->values = talloc_array(me, struct ldb_val, me->num_values); me->values[0].length = PyString_Size(set_obj); - me->values[0].data = (uint8_t *)PyString_AsString(set_obj); + me->values[0].data = talloc_memdup(me, + (uint8_t *)PyString_AsString(set_obj), me->values[0].length+1); } else if (PySequence_Check(set_obj)) { int i; me->num_values = PySequence_Size(set_obj); @@ -1402,7 +1665,8 @@ struct ldb_message_element *PyObject_AsMessageElement(TALLOC_CTX *mem_ctx, PyObject *obj = PySequence_GetItem(set_obj, i); me->values[i].length = PyString_Size(obj); - me->values[i].data = (uint8_t *)PyString_AsString(obj); + me->values[i].data = talloc_memdup(me, + (uint8_t *)PyString_AsString(obj), me->values[i].length+1); } } else { talloc_free(me); @@ -1442,8 +1706,30 @@ static PyObject *py_ldb_msg_element_get(PyLdbMessageElementObject *self, PyObjec &(PyLdbMessageElement_AsMessageElement(self)->values[i])); } +static PyObject *py_ldb_msg_element_flags(PyLdbMessageElementObject *self, PyObject *args) +{ + struct ldb_message_element *el; + + el = PyLdbMessageElement_AsMessageElement(self); + return PyInt_FromLong(el->flags); +} + +static PyObject *py_ldb_msg_element_set_flags(PyLdbMessageElementObject *self, PyObject *args) +{ + int flags; + struct ldb_message_element *el; + if (!PyArg_ParseTuple(args, "i", &flags)) + return NULL; + + el = PyLdbMessageElement_AsMessageElement(self); + el->flags = flags; + Py_RETURN_NONE; +} + static PyMethodDef py_ldb_msg_element_methods[] = { { "get", (PyCFunction)py_ldb_msg_element_get, METH_VARARGS, NULL }, + { "set_flags", (PyCFunction)py_ldb_msg_element_set_flags, METH_VARARGS, NULL }, + { "flags", (PyCFunction)py_ldb_msg_element_flags, METH_NOARGS, NULL }, { NULL }, }; @@ -1523,15 +1809,24 @@ static PyObject *py_ldb_msg_element_new(PyTypeObject *type, PyObject *args, PyOb if (PyString_Check(py_elements)) { el->num_values = 1; el->values = talloc_array(el, struct ldb_val, 1); - el->values[0].data = (uint8_t *)PyString_AsString(py_elements); el->values[0].length = PyString_Size(py_elements); + el->values[0].data = talloc_memdup(el, + (uint8_t *)PyString_AsString(py_elements), el->values[0].length+1); } else if (PySequence_Check(py_elements)) { el->num_values = PySequence_Size(py_elements); el->values = talloc_array(el, struct ldb_val, el->num_values); for (i = 0; i < el->num_values; i++) { PyObject *item = PySequence_GetItem(py_elements, i); - el->values[i].data = (uint8_t *)PyString_AsString(item); + if (!PyString_Check(item)) { + PyErr_Format(PyExc_TypeError, + "Expected string as element %d in list", + i); + talloc_free(mem_ctx); + return NULL; + } el->values[i].length = PyString_Size(item); + el->values[i].data = talloc_memdup(el, + (uint8_t *)PyString_AsString(item), el->values[i].length+1); } } else { PyErr_SetString(PyExc_TypeError, @@ -1571,9 +1866,12 @@ static PyObject *py_ldb_msg_element_repr(PyLdbMessageElementObject *self) element_str = talloc_asprintf_append(element_str, ",%s", PyObject_REPR(o)); } - ret = PyString_FromFormat("MessageElement([%s])", element_str); - - talloc_free(element_str); + if (element_str != NULL) { + ret = PyString_FromFormat("MessageElement([%s])", element_str); + talloc_free(element_str); + } else { + ret = PyString_FromString("MessageElement([])"); + } return ret; } @@ -1595,7 +1893,7 @@ static void py_ldb_msg_element_dealloc(PyLdbMessageElementObject *self) } PyTypeObject PyLdbMessageElement = { - .tp_name = "MessageElement", + .tp_name = "ldb.MessageElement", .tp_basicsize = sizeof(PyLdbMessageElementObject), .tp_dealloc = (destructor)py_ldb_msg_element_dealloc, .tp_repr = (reprfunc)py_ldb_msg_element_repr, @@ -1638,8 +1936,13 @@ static PyObject *py_ldb_msg_keys(PyLdbMessageObject *self) static PyObject *py_ldb_msg_getitem_helper(PyLdbMessageObject *self, PyObject *py_name) { struct ldb_message_element *el; - char *name = PyString_AsString(py_name); + char *name; struct ldb_message *msg = PyLdbMessage_AsMessage(self); + if (!PyString_Check(py_name)) { + PyErr_SetNone(PyExc_TypeError); + return NULL; + } + name = PyString_AsString(py_name); if (!strcmp(name, "dn")) return PyLdbDn_FromDn(msg->dn); el = ldb_msg_find_element(msg, name); @@ -1666,8 +1969,11 @@ static PyObject *py_ldb_msg_get(PyLdbMessageObject *self, PyObject *args) return NULL; ret = py_ldb_msg_getitem_helper(self, name); - if (ret == NULL) + if (ret == NULL) { + if (PyErr_Occurred()) + return NULL; Py_RETURN_NONE; + } return ret; } @@ -1707,15 +2013,22 @@ static PyObject *py_ldb_msg_iter(PyLdbMessageObject *self) static int py_ldb_msg_setitem(PyLdbMessageObject *self, PyObject *name, PyObject *value) { - char *attr_name = PyString_AsString(name); + char *attr_name; + + if (!PyString_Check(name)) { + PyErr_SetNone(PyExc_TypeError); + return -1; + } + + attr_name = PyString_AsString(name); if (value == NULL) { + /* delitem */ ldb_msg_remove_attr(self->msg, attr_name); } else { - struct ldb_message_element *el = PyObject_AsMessageElement(NULL, + struct ldb_message_element *el = PyObject_AsMessageElement(self->msg, value, 0, attr_name); if (el == NULL) return -1; - talloc_steal(self->msg, el); ldb_msg_remove_attr(PyLdbMessage_AsMessage(self), attr_name); ldb_msg_add(PyLdbMessage_AsMessage(self), el, el->flags); } @@ -1737,6 +2050,7 @@ static PyObject *py_ldb_msg_new(PyTypeObject *type, PyObject *args, PyObject *kw { const char * const kwnames[] = { "dn", NULL }; struct ldb_message *ret; + TALLOC_CTX *mem_ctx; PyObject *pydn = NULL; PyLdbMessageObject *py_ret; @@ -1745,8 +2059,15 @@ static PyObject *py_ldb_msg_new(PyTypeObject *type, PyObject *args, PyObject *kw &pydn)) return NULL; - ret = ldb_msg_new(NULL); + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + + ret = ldb_msg_new(mem_ctx); if (ret == NULL) { + talloc_free(mem_ctx); PyErr_NoMemory(); return NULL; } @@ -1754,7 +2075,7 @@ static PyObject *py_ldb_msg_new(PyTypeObject *type, PyObject *args, PyObject *kw if (pydn != NULL) { struct ldb_dn *dn; if (!PyObject_AsDn(NULL, pydn, NULL, &dn)) { - talloc_free(ret); + talloc_free(mem_ctx); return NULL; } ret->dn = talloc_reference(ret, dn); @@ -1763,12 +2084,12 @@ static PyObject *py_ldb_msg_new(PyTypeObject *type, PyObject *args, PyObject *kw py_ret = (PyLdbMessageObject *)type->tp_alloc(type, 0); if (py_ret == NULL) { PyErr_NoMemory(); - talloc_free(ret); + talloc_free(mem_ctx); return NULL; } - py_ret->mem_ctx = talloc_new(NULL); - py_ret->msg = talloc_steal(py_ret->mem_ctx, ret); + py_ret->mem_ctx = mem_ctx; + py_ret->msg = ret; return (PyObject *)py_ret; } @@ -1795,6 +2116,11 @@ static PyObject *py_ldb_msg_get_dn(PyLdbMessageObject *self, void *closure) static int py_ldb_msg_set_dn(PyLdbMessageObject *self, PyObject *value, void *closure) { struct ldb_message *msg = PyLdbMessage_AsMessage(self); + if (!PyLdbDn_Check(value)) { + PyErr_SetNone(PyExc_TypeError); + return -1; + } + msg->dn = talloc_reference(msg, PyLdbDn_AsDn(value)); return 0; } @@ -1820,8 +2146,45 @@ static void py_ldb_msg_dealloc(PyLdbMessageObject *self) self->ob_type->tp_free(self); } +static int py_ldb_msg_compare(PyLdbMessageObject *py_msg1, + PyLdbMessageObject *py_msg2) +{ + struct ldb_message *msg1 = PyLdbMessage_AsMessage(py_msg1), + *msg2 = PyLdbMessage_AsMessage(py_msg2); + unsigned int i; + int ret; + + if ((msg1->dn != NULL) || (msg2->dn != NULL)) { + ret = ldb_dn_compare(msg1->dn, msg2->dn); + if (ret != 0) { + return ret; + } + } + + ret = msg1->num_elements - msg2->num_elements; + if (ret != 0) { + return ret; + } + + for (i = 0; i < msg1->num_elements; i++) { + ret = ldb_msg_element_compare_name(&msg1->elements[i], + &msg2->elements[i]); + if (ret != 0) { + return ret; + } + + ret = ldb_msg_element_compare(&msg1->elements[i], + &msg2->elements[i]); + if (ret != 0) { + return ret; + } + } + + return 0; +} + PyTypeObject PyLdbMessage = { - .tp_name = "Message", + .tp_name = "ldb.Message", .tp_methods = py_ldb_msg_methods, .tp_getset = py_ldb_msg_getset, .tp_as_mapping = &py_ldb_msg_mapping, @@ -1831,6 +2194,7 @@ PyTypeObject PyLdbMessage = { .tp_repr = (reprfunc)py_ldb_msg_repr, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_iter = (getiterfunc)py_ldb_msg_iter, + .tp_compare = (cmpfunc)py_ldb_msg_compare, }; PyObject *PyLdbTree_FromTree(struct ldb_parse_tree *tree) @@ -1855,7 +2219,7 @@ static void py_ldb_tree_dealloc(PyLdbTreeObject *self) } PyTypeObject PyLdbTree = { - .tp_name = "Tree", + .tp_name = "ldb.Tree", .tp_basicsize = sizeof(PyLdbTreeObject), .tp_dealloc = (destructor)py_ldb_tree_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, @@ -2164,10 +2528,12 @@ static PyObject *py_register_module(PyObject *module, PyObject *args) static PyObject *py_timestring(PyObject *module, PyObject *args) { time_t t; + unsigned long val; char *tresult; PyObject *ret; - if (!PyArg_ParseTuple(args, "L", &t)) + if (!PyArg_ParseTuple(args, "l", &val)) return NULL; + t = (time_t)val; tresult = ldb_timestring(NULL, t); ret = PyString_FromString(tresult); talloc_free(tresult); @@ -2246,6 +2612,10 @@ void initldb(void) PyModule_AddObject(m, "CHANGETYPE_DELETE", PyInt_FromLong(LDB_CHANGETYPE_DELETE)); PyModule_AddObject(m, "CHANGETYPE_MODIFY", PyInt_FromLong(LDB_CHANGETYPE_MODIFY)); + PyModule_AddObject(m, "FLAG_MOD_ADD", PyInt_FromLong(LDB_FLAG_MOD_ADD)); + PyModule_AddObject(m, "FLAG_MOD_REPLACE", PyInt_FromLong(LDB_FLAG_MOD_REPLACE)); + PyModule_AddObject(m, "FLAG_MOD_DELETE", PyInt_FromLong(LDB_FLAG_MOD_DELETE)); + PyModule_AddObject(m, "SUCCESS", PyInt_FromLong(LDB_SUCCESS)); PyModule_AddObject(m, "ERR_OPERATIONS_ERROR", PyInt_FromLong(LDB_ERR_OPERATIONS_ERROR)); PyModule_AddObject(m, "ERR_PROTOCOL_ERROR", PyInt_FromLong(LDB_ERR_PROTOCOL_ERROR)); @@ -2284,9 +2654,13 @@ void initldb(void) PyModule_AddObject(m, "ERR_ENTRY_ALREADY_EXISTS", PyInt_FromLong(LDB_ERR_ENTRY_ALREADY_EXISTS)); PyModule_AddObject(m, "ERR_OBJECT_CLASS_MODS_PROHIBITED", PyInt_FromLong(LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED)); PyModule_AddObject(m, "ERR_AFFECTS_MULTIPLE_DSAS", PyInt_FromLong(LDB_ERR_AFFECTS_MULTIPLE_DSAS)); - PyModule_AddObject(m, "ERR_OTHER", PyInt_FromLong(LDB_ERR_OTHER)); + PyModule_AddObject(m, "FLG_RDONLY", PyInt_FromLong(LDB_FLG_RDONLY)); + PyModule_AddObject(m, "FLG_NOSYNC", PyInt_FromLong(LDB_FLG_NOSYNC)); + PyModule_AddObject(m, "FLG_RECONNECT", PyInt_FromLong(LDB_FLG_RECONNECT)); + PyModule_AddObject(m, "FLG_NOMMAP", PyInt_FromLong(LDB_FLG_NOMMAP)); + PyModule_AddObject(m, "__docformat__", PyString_FromString("restructuredText")); PyExc_LdbError = PyErr_NewException(discard_const_p(char, "_ldb.LdbError"), NULL, NULL);