ldb:python bindings - add a context on "py_ldb_delete"
[ira/wip.git] / source4 / lib / ldb / pyldb.c
index 2e0f4fdf3606b88576b905d8949aa8417171825e..1f1dcf8e316bca3ddd1ba2f1fb8fd57850ad1fab 100644 (file)
@@ -6,6 +6,7 @@
    Copyright (C) 2005,2006 Tim Potter <tpot@samba.org>
    Copyright (C) 2006 Simo Sorce <idra@samba.org>
    Copyright (C) 2007-2009 Jelmer Vernooij <jelmer@samba.org>
+   Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
 */
 
+#include <Python.h>
 #include "replace.h"
 #include "ldb_private.h"
-#include <Python.h>
 #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;
@@ -200,7 +211,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)
@@ -528,7 +543,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 +617,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;
@@ -640,6 +656,7 @@ static PyObject *py_ldb_modify(PyLdbObject *self, PyObject *args)
        Py_RETURN_NONE;
 }
 
+
 static PyObject *py_ldb_add(PyLdbObject *self, PyObject *args)
 {
        PyObject *py_msg;
@@ -647,21 +664,32 @@ 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;
+       ldb_ctx = PyLdb_AsLdbContext(self);
 
        mem_ctx = talloc_new(NULL);
-
+       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);
+               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,8 +725,52 @@ 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, PyLdb_AsLdbContext(self));
+               talloc_free(mem_ctx);
+               return NULL;
+        }
+
+        ret = ldb_build_add_req(&req, ldb_ctx, ldb_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(req);
+               talloc_free(mem_ctx);
+               PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, PyLdb_AsLdbContext(self));
+        }
+
+        ret = ldb_request(ldb_ctx, req);
+        if (ret == LDB_SUCCESS) {
+                ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+        } 
 
-       ret = ldb_add(PyLdb_AsLdbContext(self), msg);
+       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(req);
        talloc_free(mem_ctx);
        PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, PyLdb_AsLdbContext(self));
 
@@ -711,15 +783,23 @@ static PyObject *py_ldb_delete(PyLdbObject *self, PyObject *args)
        struct ldb_dn *dn;
        int ret;
        struct ldb_context *ldb;
+       TALLOC_CTX *mem_ctx;
        if (!PyArg_ParseTuple(args, "O", &py_dn))
                return NULL;
 
+       mem_ctx = talloc_new(NULL);
+       if (mem_ctx == NULL) {
+               PyErr_NoMemory();
+               return NULL;
+       }
        ldb = PyLdb_AsLdbContext(self);
-
-       if (!PyObject_AsDn(NULL, py_dn, ldb, &dn))
+       if (!PyObject_AsDn(mem_ctx, py_dn, ldb, &dn)) {
+               talloc_free(mem_ctx);
                return NULL;
+       }
 
        ret = ldb_delete(ldb, dn);
+       talloc_free(mem_ctx);
        PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb);
 
        Py_RETURN_NONE;
@@ -797,6 +877,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 +944,37 @@ static PyObject *py_ldb_parse_ldif(PyLdbObject *self, PyObject *args)
        return PyObject_GetIter(list);
 }
 
+static PyObject *py_ldb_msg_diff(PyLdbObject *self, PyObject *args)
+{
+       PyObject *py_msg_old;
+       PyObject *py_msg_new;
+       struct ldb_message *diff;
+       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;
+       }
+
+       diff = ldb_msg_diff(PyLdb_AsLdbContext(self), PyLdbMessage_AsMessage(py_msg_old), PyLdbMessage_AsMessage(py_msg_new));
+       if (!diff) {
+               PyErr_SetString(PyExc_RuntimeError, "Failed to generate the Ldb Message diff");
+               return NULL;
+       }
+
+       py_ret = PyLdbMessage_FromMessage(diff);
+
+       return py_ret;
+}
+
 static PyObject *py_ldb_schema_format_value(PyLdbObject *self, PyObject *args)
 {
        const struct ldb_schema_attribute *a;
@@ -868,7 +1014,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;
@@ -882,6 +1028,7 @@ static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwar
        struct ldb_dn *base;
        PyObject *py_ret;
 
+       /* 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))
@@ -1071,6 +1218,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"
@@ -1210,6 +1363,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))
@@ -1383,17 +1537,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);
        } else if (PySequence_Check(set_obj)) {
                int i;
                me->num_values = PySequence_Size(set_obj);
@@ -1402,7 +1558,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);
                }
        } else {
                talloc_free(me);
@@ -1442,8 +1599,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 +1702,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);
                } 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);
                        }
                } else {
                        PyErr_SetString(PyExc_TypeError, 
@@ -1638,8 +1826,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 +1859,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 +1903,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 +1940,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 +1949,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 +1965,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 +1974,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 +2006,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;
 }
@@ -2164,10 +2380,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 +2464,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 +2506,14 @@ 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);