s4-pyldb: fixed 64 bit issues
[ira/wip.git] / source4 / lib / ldb / pyldb.c
index a05aab5b8396c9d433ed4aed0ac5f49d5a644b79..35508c828aa52a58ed075793b21302a67925d337 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
@@ -210,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)
@@ -612,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;
@@ -651,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;
@@ -658,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;
@@ -708,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);
 
-       ret = ldb_add(PyLdb_AsLdbContext(self), msg);
+        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);
+        } 
+
+       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));
 
@@ -808,6 +869,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;
@@ -840,6 +936,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;
@@ -879,7 +1006,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;
@@ -1082,6 +1209,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"
@@ -1394,7 +1527,8 @@ 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);
 
@@ -1455,8 +1589,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 },
 };
 
@@ -1544,9 +1700,16 @@ static PyObject *py_ldb_msg_element_new(PyTypeObject *type, PyObject *args, PyOb
                        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);
+                               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);
-                               el->values[i].length = PyString_Size(item);
                        }
                } else {
                        PyErr_SetString(PyExc_TypeError, 
@@ -1653,8 +1816,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);
@@ -1681,8 +1849,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;
 }
 
@@ -2199,10 +2370,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);
@@ -2281,6 +2454,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));
@@ -2319,9 +2496,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);