]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
pyldb: add dn.copy() python method.
authorDouglas Bagnall <douglas.bagnall@catalyst.net.nz>
Sun, 17 Mar 2024 04:56:09 +0000 (17:56 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 10 Apr 2024 05:13:32 +0000 (05:13 +0000)
Sometimes you want to use a Dn object from one LDB with another LDB,
but this no longer works.

One way to do it is:

  new_dn = ldb.Dn(samdb, str(old_dn))

but with this, you can just:

  new_dn = old_dn.copy(samdb)

or, if you are putting it on a message which has a DN:

  msg.dn = old_dn.copy(msg.ldb)

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
lib/ldb/pyldb.c

index d19f0d06a4399b0a581d1006bb2733b76660efac..081501da40d0f510575bd353db852493600a5283 100644 (file)
@@ -763,6 +763,72 @@ static PyObject *py_ldb_dn_add_base(PyObject *self, PyObject *args)
        Py_RETURN_TRUE;
 }
 
+static PyObject *py_ldb_dn_copy(struct ldb_dn *dn, PyLdbObject *pyldb);
+
+static PyObject *py_ldb_dn_copy_method(PyObject *self, PyObject *args)
+{
+       struct ldb_dn *dn = NULL;
+       PyLdbObject *pyldb = NULL;
+       PyObject *obj = Py_None;
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
+
+       if (!PyArg_ParseTuple(args, "|O", &obj)) {
+               return NULL;
+       }
+
+       if (obj == Py_None) {
+               /*
+                * With no argument, or None, dn.copy() uses its own ldb.
+                *
+                * There is not much reason to do this, other than as a
+                * convenience in this situation:
+                *
+                * >>> msg.dn = dn.copy(msg.ldb)
+                *
+                * when you don't know whether msg has a dn or not (if msg.ldb
+                * is None, msg will now belong to this dn's ldb).
+                */
+               pyldb = ((PyLdbDnObject *)self)->pyldb;
+       } else if (PyObject_TypeCheck(obj, &PyLdb)) {
+               pyldb = (PyLdbObject *)obj;
+       } else {
+               PyErr_Format(PyExc_TypeError,
+                            "Expected Ldb or None");
+               return NULL;
+       }
+       if (pyldb != ((PyLdbDnObject *)self)->pyldb) {
+               /*
+                * This is unfortunate, but we can't make a copy of the dn directly,
+                * since the opaque struct ldb_dn has a pointer to the ldb it knows,
+                * and it is the WRONG ONE.
+                *
+                * Instead we go via string serialisation.
+                */
+               char *dn_str = NULL;
+               struct ldb_dn *new_dn = NULL;
+               dn_str = ldb_dn_get_extended_linearized(pyldb->mem_ctx, dn, 1);
+               if (dn_str == NULL) {
+                       PyErr_Format(PyExc_RuntimeError,
+                                    "Could not linearize DN");
+                       return NULL;
+               }
+               new_dn = ldb_dn_new(pyldb->mem_ctx,
+                                   pyldb->ldb_ctx,
+                                   dn_str);
+
+               if (new_dn == NULL) {
+                       PyErr_Format(PyExc_RuntimeError,
+                                    "Could not re-parse DN '%s'",
+                               dn_str);
+                       TALLOC_FREE(dn_str);
+                       return NULL;
+               }
+               TALLOC_FREE(dn_str);
+               dn = new_dn;
+       }
+       return py_ldb_dn_copy(dn, pyldb);
+}
+
 static PyObject *py_ldb_dn_remove_base_components(PyObject *self, PyObject *args)
 {
        struct ldb_dn *dn = NULL;
@@ -937,6 +1003,9 @@ static PyMethodDef py_ldb_dn_methods[] = {
        { "add_base", (PyCFunction)py_ldb_dn_add_base, METH_VARARGS,
                "S.add_base(dn) -> bool\n"
                "Add a base DN to this DN." },
+       { "copy", (PyCFunction)py_ldb_dn_copy_method, METH_VARARGS,
+               "dn.copy(ldb) -> dn\n"
+               "Make a copy of this DN, attached to the given ldb object." },
        { "remove_base_components", (PyCFunction)py_ldb_dn_remove_base_components, METH_VARARGS,
                "S.remove_base_components(int) -> bool\n"
                "Remove a number of DN components from the base of this DN." },