The branch, master has been updated
       via  60df2a09a43 selftest: move some more expected failures to 
expectedfail.d
       via  bda4e1233a1 ldb: Add more segfault tests DN handling
       via  8ac18495ba2 pyldb: don't allow py_ldb_dn_copy() with the wrong pyldb
       via  d38a9e93cf3 python:upgrade/upgradeprovision: use dn.copy to align 
ldbs
       via  345eb854c3b pyldb: add dn.copy() python method.
       via  fa9a32139ff s4:samba_upgradeprovision: align DN ownership
       via  ed6d151c1b7 pyldb: add Message.ldb accessor
       via  8b6df2d0bca pyldb: add Dn.ldb accessor
       via  a95e6aa5667 pyldb: add PyErr_internal_LDB_DN_OR_RAISE
       via  d712c8d2edd pyldb: normalise name of pyldb_Message_Check
       via  72ad126ab74 ldb:pyldb: reorder structs for possible type-punning
       via  c39021a494f pyldb: py_ldb_msg_set_dn checks dn ldb equality
       via  61ba0cc17df pyldb: py_ldb_msg_elements uses 
PyErr_LDB_MESSAGE_OR_RAISE
       via  9cadc61cd4c pyldb: py_ldb_msg_items checks for more errors
       via  6a2e6139ad0 pldb: py_ldb_msg_items uses PyErr_LDB_MESSAGE_OR_RAISE
       via  b5fcc55b5ec pyldb: py_ldb_msg_contains() checks ldb equality
       via  acba42b126c pyldb: py_ldb_msg_keys() uses PyErr_LDB_MESSAGE_OR_RAISE
       via  d05ae6872b1 pyldb: py_ldb_msg_richcmp() uses 
PyErr_LDB_MESSAGE_OR_RAISE()
       via  bc45a258d2a pyldb: use PyErr_LDB_MESSAGE_OR_RAISE() in various 
functions
       via  f0e665f4a9a pyldb: add PyErr_LDB_MESSAGE_OR_RAISE() macro
       via  b81b2578ad1 pyldb: catch up with README.Coding for some 
`PyArg_ParseTuple`s
       via  13545ed1390 pyldb: py_ldb_dn_concat() uses PyErr_LDB_DN_OR_RAISE
       via  1bbca1e3b42 pyldb: py_ldb_dn_len checks dn and ldb validity
       via  f8b92e52811 pyldb: make py_ldb_dn_add_base() a bit less leaky
       via  b83ea997e75 pyldb: py_ldb_dn_add_base() uses PyErr_LDB_DN_OR_RAISE
       via  67a9e573b00 pyldb: make py_ldb_dn_add_child() a bit less leaky
       via  310624ead50 pyldb: py_ldb_dn_add_child() uses PyErr_LDB_DN_OR_RAISE
       via  1eeb0e36516 pyldb: py_ldb_dn_get_parent() uses PyErr_LDB_DN_OR_RAISE
       via  8830149ef96 pyldb: py_ldb_dn_richcmp() uses PyErr_LDB_DN_OR_RAISE
       via  982a87cedfc pyldb: py_ldb_dn_get_extended_component() uses 
PyErr_LDB_DN_OR_RAISE
       via  5154c8c996f pyldb: py_ldb_dn_extended_str() uses 
PyErr_LDB_DN_OR_RAISE()
       via  0ce3f355022 pyldb: py_ldb_dn_get_casefold() uses 
PyErr_LDB_DN_OR_RAISE()
       via  85ba5d2c8f2 pyldb: py_ldb_dn_get_extended_component uses 
PyErr_LDB_DN_OR_RAISE()
       via  087d43ac615 pyldb: adapt some simple dn methods to use 
LDB_DN_OR_RAISE()
       via  f98035a2a31 ldb:pyldb: PyErr_LDB_DN_OR_RAISE makes more rigourous 
checks
       via  8bb6287c3ba pytest:segfault: some more ldb crashes
       via  0bf80c10ca5 samba-tool domain backup: Use new ldb.disconnect() 
method to force-close files during backup
       via  8612b3e38b3 ldb:pytests: test ldb.connect() works after 
.disconnect()
       via  fdc3212275b pyldb: Add ldb.disconnect() method to ensure DB handles 
are closed
       via  784ee21616a pyldb: Include a reference to the Ldb in objects that 
use
       via  ffbe623963a selftest: Add tests that demonstrate the issues with 
ldb use after free
       via  3ffc6c139b0 pytest:krb5/lockout: associate user DN with the ldb it 
is used with
      from  dbba6c22a41 auth/credentials: Read 
managed_password.passwords.query_interval only after parsing

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 60df2a09a4394d2b494224ad3d33314079e73066
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Fri Mar 22 16:20:18 2024 +1300

    selftest: move some more expected failures to expectedfail.d
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>
    
    Autobuild-User(master): Andrew Bartlett <abart...@samba.org>
    Autobuild-Date(master): Wed Apr 10 06:15:46 UTC 2024 on atb-devel-224

commit bda4e1233a145f11aa92b89a5658d94cd9252267
Author: Andrew Bartlett <abart...@samba.org>
Date:   Mon Mar 25 22:21:19 2024 +1300

    ldb: Add more segfault tests DN handling
    
    - from_dict DN use-after-free
    - check for the same directly creating the ldb.Message
    
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 8ac18495ba238985a82dbe5a3c95c78c3c51f4b6
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Mon Mar 18 12:24:53 2024 +1300

    pyldb: don't allow py_ldb_dn_copy() with the wrong pyldb
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit d38a9e93cf3444d7fe3939728673a637a03eb819
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Sun Mar 17 18:07:44 2024 +1300

    python:upgrade/upgradeprovision: use dn.copy to align ldbs
    
    We need to do this when the dn is on a message from another ldb.
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 345eb854c3b03a3c8e0e19fba0edb9eafd055ab9
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Sun Mar 17 17:56:09 2024 +1300

    pyldb: add dn.copy() python method.
    
    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.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit fa9a32139fff4e8d49ee3f5331e6f8ce6fb47ae1
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Sun Mar 17 14:44:32 2024 +1300

    s4:samba_upgradeprovision: align DN ownership
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit ed6d151c1b73985e3cf81ea4561fab843dd62142
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Sun Mar 17 14:25:18 2024 +1300

    pyldb: add Message.ldb accessor
    
    See the last commit for comments about how this is useful for
    debugging.
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 8b6df2d0bca12fc33b60c5702b4afe36597cc775
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Sun Mar 17 14:24:03 2024 +1300

    pyldb: add Dn.ldb accessor
    
    This, and the next commit, might help in debugging when you see a
    traceback that ends like this:
    
      File "/data/samba/samba/bin/samba_upgradeprovision", line 664, in 
add_missing_object
          delta.dn = dn
      RuntimeError: DN is from the wrong LDB
    
    in this case you could force a solution with something like:
    
     delta.dn = ldb.dn(delta.ldb, str(dn))
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit a95e6aa56677dfcff1c15925aa8c042a1f3db9a1
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Wed Mar 13 17:28:57 2024 +1300

    pyldb: add PyErr_internal_LDB_DN_OR_RAISE
    
    This might be faster than the circuitous route.
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit d712c8d2edd168a45c558a7fe26459a41823e53d
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Wed Mar 13 17:28:07 2024 +1300

    pyldb: normalise name of pyldb_Message_Check
    
    c.f. pyldb_MessageElement_Check, pyldb_Dn_Check.
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 72ad126ab74b247460ccf4bdb590efc28cbd2be8
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Fri Mar 8 10:42:06 2024 +1300

    ldb:pyldb: reorder structs for possible type-punning
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit c39021a494f81ea90e03d63e7f5d09098e9438e1
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Fri Mar 15 17:17:25 2024 +1300

    pyldb: py_ldb_msg_set_dn checks dn ldb equality
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 61ba0cc17df6a0ecf59b61c7d6da3bb7c0bdeea3
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Fri Mar 15 17:16:34 2024 +1300

    pyldb: py_ldb_msg_elements uses PyErr_LDB_MESSAGE_OR_RAISE
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 9cadc61cd4c5dd2632b120ce37969f25743e0fbc
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Sat Mar 16 11:15:31 2024 +1300

    pyldb: py_ldb_msg_items checks for more errors
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 6a2e6139ad00de95eaf89ff44939f2d680f07f03
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Fri Mar 15 17:15:28 2024 +1300

    pldb: py_ldb_msg_items uses PyErr_LDB_MESSAGE_OR_RAISE
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit b5fcc55b5ec0bae2782ca29c1e868712129cfe8d
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Fri Mar 15 17:09:53 2024 +1300

    pyldb: py_ldb_msg_contains() checks ldb equality
    
    We can't use PyErr_LDB_MESSAGE_OR_RAISE() here, because the return type
    is int, not PyObject*.
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit acba42b126cdc4b6c165a0075bc3986a72bfe5eb
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Fri Mar 15 13:50:40 2024 +1300

    pyldb: py_ldb_msg_keys() uses PyErr_LDB_MESSAGE_OR_RAISE
    
    We change the [unused, because it always cast] signature of
    py_ldb_msg_iter() in the same commit, because that is just a wrapper
    around _keys() and this maintains bisectability with the least fuss.
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit d05ae6872b17ec0df5343d38c5638064a676f6db
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Fri Mar 15 17:04:59 2024 +1300

    pyldb: py_ldb_msg_richcmp() uses PyErr_LDB_MESSAGE_OR_RAISE()
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit bc45a258d2a4442ff7294cd6cdadd6f780a06cd4
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Fri Mar 15 13:08:03 2024 +1300

    pyldb: use PyErr_LDB_MESSAGE_OR_RAISE() in various functions
    
    In these simple cases, we are:
    
    1. replacing the first argument `PyObject *` with `PyLdbMessageObject *`.
    2. adding a `struct ldb_message *msg = NULL;` variable.
    3. `PyErr_LDB_MESSAGE_OR_RAISE(self, msg);`.
    4. changing the `self->msg` to `msg`.
    5. adding { } to the `if (!PyArg_ParseTuple() return NULL;`.
    6. replacing `self->pyldb` with `pyldb_Message_get_pyldb(self)`
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit f0e665f4a9accad5b8814e27553010645b9feddb
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 16:41:43 2024 +1300

    pyldb: add PyErr_LDB_MESSAGE_OR_RAISE() macro
    
    The Python level message has a reference to an LDB, which should be NULL,
    or the same as the dn's LDB, lest one of them is freed early.
    
    The message LDB will be NULL until a DN is set, and if the DN is replaced,
    the LDB is also be replaced (see py_ldb_msg_set_dn), so it is *unlikely*
    for these to get out of sync. In addition, fetching msg.dn via python
    compares the LDBs at that point (py_ldb_msg_get_dn).
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit b81b2578ad14992c388fc1b3a8055f5d8c0f2dee
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 17:32:51 2024 +1300

    pyldb: catch up with README.Coding for some `PyArg_ParseTuple`s
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 13545ed139034d0ca9543445e3303c08620d5d57
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 17:27:58 2024 +1300

    pyldb: py_ldb_dn_concat() uses PyErr_LDB_DN_OR_RAISE
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 1bbca1e3b42bb87b65b89129b42cf01dc4937345
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 17:26:38 2024 +1300

    pyldb: py_ldb_dn_len checks dn and ldb validity
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit f8b92e52811a87193ed326a97ff8ac2f440dcf7b
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Fri Mar 15 12:38:00 2024 +1300

    pyldb: make py_ldb_dn_add_base() a bit less leaky
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit b83ea997e759c494847c2f12b1fb667b07e22bc8
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 17:24:48 2024 +1300

    pyldb: py_ldb_dn_add_base() uses PyErr_LDB_DN_OR_RAISE
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 67a9e573b009443990b426c3f136862c2b3a5705
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Fri Mar 15 12:11:18 2024 +1300

    pyldb: make py_ldb_dn_add_child() a bit less leaky
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 310624ead5078d38bca7abaac35e06b49b129568
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Wed Apr 10 14:41:09 2024 +1200

    pyldb: py_ldb_dn_add_child() uses PyErr_LDB_DN_OR_RAISE
    
    for self->dn only. The other dn is a different story, next commit.
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 1eeb0e36516cbc52a4adc80c391d35afcf39de7c
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 17:21:34 2024 +1300

    pyldb: py_ldb_dn_get_parent() uses PyErr_LDB_DN_OR_RAISE
    
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 8830149ef9648a6f1af33a120ac82930c5306404
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 17:19:21 2024 +1300

    pyldb: py_ldb_dn_richcmp() uses PyErr_LDB_DN_OR_RAISE
    
    The `if (!pyldb_Dn_Check(pydn2))` might seem redundant, but we
    need it to return Py_NotImplemented before the _OR_RAISE macro
    raises TypeError.
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 982a87cedfcf71dd22a89cfa36285a333e6dcec8
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 17:10:17 2024 +1300

    pyldb: py_ldb_dn_get_extended_component() uses PyErr_LDB_DN_OR_RAISE
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 5154c8c996f16531743e40cb839de49ddc66b2c6
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 17:07:52 2024 +1300

    pyldb: py_ldb_dn_extended_str() uses PyErr_LDB_DN_OR_RAISE()
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 0ce3f35502243847201e99fa7fa0312667d00e11
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Wed Apr 10 14:40:42 2024 +1200

    pyldb: py_ldb_dn_get_casefold() uses PyErr_LDB_DN_OR_RAISE()
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>
    
    # Conflicts:
    #   selftest/knownfail.d/ldb-use-after-free-segfault

commit 85ba5d2c8f2708d284a973bb6b372faea542a393
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Fri Mar 15 11:00:50 2024 +1300

    pyldb: py_ldb_dn_get_extended_component uses PyErr_LDB_DN_OR_RAISE()
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 087d43ac615e12665538cb0bc858113e797ebcba
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 16:38:14 2024 +1300

    pyldb: adapt some simple dn methods to use LDB_DN_OR_RAISE()
    
    We treat self as PyObject, and only trust its DN once it has been
    laundered by PyErr_LDB_DN_OR_RAISE().
    
    There are more of these to come in the next few commits, but these are
    the simplest ones (on a textual level -- the others are simple too, but
    look different).
    
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit f98035a2a3147f7d935a356d2a273e0bfd0796f2
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 15:10:07 2024 +1300

    ldb:pyldb: PyErr_LDB_DN_OR_RAISE makes more rigourous checks
    
    This changes what happens all over the place
    (lib/ldb/pyldb.c, source4/dns_server/pydns.c, source4/dsdb/pydsdb.c),
    but causes no problems because it just checks what we always assumed.
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 8bb6287c3ba20209c5d8352f3b2d90275561fb56
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 09:32:47 2024 +1300

    pytest:segfault: some more ldb crashes
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 0bf80c10ca50515fc64561db68d3c3283945252a
Author: Andrew Bartlett <abart...@samba.org>
Date:   Wed Dec 6 12:38:54 2023 +1300

    samba-tool domain backup: Use new ldb.disconnect() method to force-close 
files during backup
    
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 8612b3e38b3c64a6645c460ccdca52d059eeb75b
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Wed Mar 20 11:31:23 2024 +1300

    ldb:pytests: test ldb.connect() works after .disconnect()
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit fdc3212275bc08f4a016e10923e689192ea7697f
Author: Andrew Bartlett <abart...@samba.org>
Date:   Wed Dec 6 11:18:27 2023 +1300

    pyldb: Add ldb.disconnect() method to ensure DB handles are closed
    
    This is vital in our backup code, which needs to actually close the
    LMDB at the correct point.
    
    The Python ldb object itself is left in more or less the same state as
    one that has not connected to a server or database (it is a very
    simple wrapper in itself), and can be reconnected using the .connect()
    method.
    
    Pair-programmed-with: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 784ee21616a60993ecc0979f83fbb04467d57af9
Author: Andrew Bartlett <abart...@samba.org>
Date:   Wed Nov 8 10:43:38 2023 +1300

    pyldb: Include a reference to the Ldb in objects that use
    
    This will help avoid use-after-free of the internally cached ldb within
    struct ldb_dn by ensuring that it lives as long.
    
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit ffbe623963a9b495e70f767512e1b147ebebba1f
Author: Andrew Bartlett <abart...@samba.org>
Date:   Mon Dec 4 12:00:12 2023 +1300

    selftest: Add tests that demonstrate the issues with ldb use after free
    
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 3ffc6c139b03d51b0e30ed2e3a4d512ba5ca2dc1
Author: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
Date:   Thu Mar 14 13:25:48 2024 +1300

    pytest:krb5/lockout: associate user DN with the ldb it is used with
    
    LDB is soon going to object strongly to Python DNs that don't come from
    the ldb that they are being used with, for memory safety reasons.
    
    Signed-off-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

-----------------------------------------------------------------------

Summary of changes:
 lib/ldb/ABI/pyldb-util-2.9.0.sigs                  |   2 +-
 lib/ldb/pyldb.c                                    | 701 +++++++++++++++++----
 lib/ldb/pyldb.h                                    |  80 ++-
 lib/ldb/pyldb_util.c                               |   5 +-
 lib/ldb/tests/python/api.py                        |   9 +
 python/samba/netcmd/domain/backup.py               |   2 +
 python/samba/tests/krb5/lockout_tests.py           |  13 +-
 python/samba/tests/segfault.py                     | 346 ++++++++++
 python/samba/upgrade.py                            |   2 +-
 python/samba/upgradehelpers.py                     |   8 +-
 selftest/expectedfail.d/ldap-tlsverifypeer         |  10 +
 selftest/knownfail                                 |  10 -
 .../knownfail.d/pyldb-segfaults                    |   0
 source4/dns_server/pydns.c                         |   2 +-
 source4/dsdb/pydsdb.c                              |   9 +-
 source4/scripting/bin/samba_upgradeprovision       |   9 +-
 16 files changed, 1034 insertions(+), 174 deletions(-)
 create mode 100644 selftest/expectedfail.d/ldap-tlsverifypeer
 copy buildtools/wafsamba/__init__.py => selftest/knownfail.d/pyldb-segfaults 
(100%)


Changeset truncated at 500 lines:

diff --git a/lib/ldb/ABI/pyldb-util-2.9.0.sigs 
b/lib/ldb/ABI/pyldb-util-2.9.0.sigs
index 164a806b2ff..218d2161cd8 100644
--- a/lib/ldb/ABI/pyldb-util-2.9.0.sigs
+++ b/lib/ldb/ABI/pyldb-util-2.9.0.sigs
@@ -1,3 +1,3 @@
-pyldb_Dn_FromDn: PyObject *(struct ldb_dn *)
+pyldb_Dn_FromDn: PyObject *(struct ldb_dn *, PyLdbObject *)
 pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, 
struct ldb_dn **)
 pyldb_check_type: bool (PyObject *, const char *)
diff --git a/lib/ldb/pyldb.c b/lib/ldb/pyldb.c
index cd4268a9a74..f416bfe6d5d 100644
--- a/lib/ldb/pyldb.c
+++ b/lib/ldb/pyldb.c
@@ -58,14 +58,14 @@ struct py_ldb_search_iterator_reply {
 };
 
 void initldb(void);
-static PyObject *PyLdbMessage_FromMessage(struct ldb_message *msg);
+static PyObject *PyLdbMessage_FromMessage(struct ldb_message *msg, PyLdbObject 
*pyldb);
 static PyObject *PyExc_LdbError;
 
 static PyTypeObject PyLdbControl;
 static PyTypeObject PyLdbResult;
 static PyTypeObject PyLdbSearchIterator;
 static PyTypeObject PyLdbMessage;
-#define PyLdbMessage_Check(ob) PyObject_TypeCheck(ob, &PyLdbMessage)
+#define pyldb_Message_Check(ob) PyObject_TypeCheck(ob, &PyLdbMessage)
 static PyTypeObject PyLdbDn;
 #define pyldb_Dn_Check(ob) PyObject_TypeCheck(ob, &PyLdbDn)
 static PyTypeObject PyLdb;
@@ -332,7 +332,7 @@ static PyObject *PyLdbControl_FromControl(struct 
ldb_control *control)
  * @param result LDB result to convert
  * @return Python object with converted result (a list object)
  */
-static PyObject *PyLdbResult_FromResult(struct ldb_result *result)
+static PyObject *PyLdbResult_FromResult(struct ldb_result *result, PyLdbObject 
*pyldb)
 {
        PyLdbResultObject *ret;
        PyObject *list, *controls, *referals;
@@ -348,6 +348,9 @@ static PyObject *PyLdbResult_FromResult(struct ldb_result 
*result)
                return NULL;
        }
 
+       ret->pyldb = pyldb;
+       Py_INCREF(ret->pyldb);
+
        list = PyList_New(result->count);
        if (list == NULL) {
                PyErr_NoMemory();
@@ -356,7 +359,7 @@ static PyObject *PyLdbResult_FromResult(struct ldb_result 
*result)
        }
 
        for (i = 0; i < result->count; i++) {
-               PyObject *pymessage = PyLdbMessage_FromMessage(result->msgs[i]);
+               PyObject *pymessage = PyLdbMessage_FromMessage(result->msgs[i], 
pyldb);
                if (pymessage == NULL) {
                        Py_DECREF(ret);
                        Py_DECREF(list);
@@ -434,10 +437,36 @@ static PyObject *PyLdbResult_FromResult(struct ldb_result 
*result)
        return (PyObject *)ret;
 }
 
-static PyObject *py_ldb_dn_validate(PyLdbDnObject *self,
+
+/*
+ * PyErr_interal_LDB_DN_OR_RAISE does exactly what
+ * PyErr__LDB_DN_OR_RAISE does, but rather than going through the
+ * Python layer to import the Dn object, it directly uses the the
+ * address of the PyTypeObject. This is faster, but can only be done
+ * in pyldb.c.
+ */
+#define PyErr_internal_LDB_DN_OR_RAISE(_py_obj, dn) do {               \
+               PyLdbDnObject *_py_dn = NULL;                           \
+       if (_py_obj == NULL || !pyldb_Dn_Check(_py_obj)) {              \
+               PyErr_SetString(PyExc_TypeError, "ldb Dn object required"); \
+               return NULL;                                            \
+       }                                                               \
+       _py_dn = (PyLdbDnObject *)_py_obj;                              \
+       dn = pyldb_Dn_AS_DN(_py_dn);                                    \
+       if (_py_dn->pyldb->ldb_ctx != ldb_dn_get_ldb_context(dn)) {     \
+               PyErr_SetString(PyExc_RuntimeError,                     \
+                               "Dn has a stale LDB connection");       \
+               return NULL;                                           \
+       }                                                              \
+} while(0)
+
+
+static PyObject *py_ldb_dn_validate(PyObject *self,
                PyObject *Py_UNUSED(ignored))
 {
-       return PyBool_FromLong(ldb_dn_validate(self->dn));
+       struct ldb_dn *dn = NULL;
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
+       return PyBool_FromLong(ldb_dn_validate(dn));
 }
 
 static PyObject *py_ldb_dn_is_valid(PyLdbDnObject *self,
@@ -452,16 +481,21 @@ static PyObject *py_ldb_dn_is_special(PyLdbDnObject *self,
        return PyBool_FromLong(ldb_dn_is_special(self->dn));
 }
 
-static PyObject *py_ldb_dn_is_null(PyLdbDnObject *self,
+static PyObject *py_ldb_dn_is_null(PyObject *self,
                PyObject *Py_UNUSED(ignored))
 {
-       return PyBool_FromLong(ldb_dn_is_null(self->dn));
+       struct ldb_dn *dn = NULL;
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
+       return PyBool_FromLong(ldb_dn_is_null(dn));
 }
 
-static PyObject *py_ldb_dn_get_casefold(PyLdbDnObject *self,
+static PyObject *py_ldb_dn_get_casefold(PyObject *self,
                PyObject *Py_UNUSED(ignored))
 {
-       const char *s = ldb_dn_get_casefold(self->dn);
+       const char *s = NULL;
+       struct ldb_dn *dn = NULL;
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
+       s = ldb_dn_get_casefold(dn);
        if (s == NULL) {
                PyErr_NoMemory();
                return NULL;
@@ -469,43 +503,55 @@ static PyObject *py_ldb_dn_get_casefold(PyLdbDnObject 
*self,
        return PyUnicode_FromString(s);
 }
 
-static PyObject *py_ldb_dn_get_linearized(PyLdbDnObject *self,
+static PyObject *py_ldb_dn_get_linearized(PyObject *self,
                PyObject *Py_UNUSED(ignored))
 {
-       return PyUnicode_FromString(ldb_dn_get_linearized(self->dn));
+       struct ldb_dn *dn = NULL;
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
+       return PyUnicode_FromString(ldb_dn_get_linearized(dn));
 }
 
-static PyObject *py_ldb_dn_canonical_str(PyLdbDnObject *self,
+static PyObject *py_ldb_dn_canonical_str(PyObject *self,
                PyObject *Py_UNUSED(ignored))
 {
-       return PyUnicode_FromString(ldb_dn_canonical_string(self->dn, 
self->dn));
+       struct ldb_dn *dn = NULL;
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
+       return PyUnicode_FromString(ldb_dn_canonical_string(dn, dn));
 }
 
-static PyObject *py_ldb_dn_canonical_ex_str(PyLdbDnObject *self,
+static PyObject *py_ldb_dn_canonical_ex_str(PyObject *self,
                PyObject *Py_UNUSED(ignored))
 {
-       return PyUnicode_FromString(ldb_dn_canonical_ex_string(self->dn, 
self->dn));
+       struct ldb_dn *dn = NULL;
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
+       return PyUnicode_FromString(ldb_dn_canonical_ex_string(dn, dn));
 }
 
-static PyObject *py_ldb_dn_extended_str(PyLdbDnObject *self, PyObject *args, 
PyObject *kwargs)
+static PyObject *py_ldb_dn_extended_str(PyObject *self, PyObject *args, 
PyObject *kwargs)
 {
        const char * const kwnames[] = { "mode", NULL };
        int mode = 1;
+       struct ldb_dn *dn = NULL;
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
        if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i",
                                         discard_const_p(char *, kwnames),
-                                        &mode))
+                                        &mode)) {
                return NULL;
-       return PyUnicode_FromString(ldb_dn_get_extended_linearized(self->dn, 
self->dn, mode));
+       }
+       return PyUnicode_FromString(ldb_dn_get_extended_linearized(dn, dn, 
mode));
 }
 
-static PyObject *py_ldb_dn_get_extended_component(PyLdbDnObject *self, 
PyObject *args)
+static PyObject *py_ldb_dn_get_extended_component(PyObject *self, PyObject 
*args)
 {
        char *name;
-       const struct ldb_val *val;
+       const struct ldb_val *val = NULL;
+       struct ldb_dn *dn = NULL;
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
 
-       if (!PyArg_ParseTuple(args, "s", &name))
+       if (!PyArg_ParseTuple(args, "s", &name)) {
                return NULL;
-       val = ldb_dn_get_extended_component(self->dn, name);
+       }
+       val = ldb_dn_get_extended_component(dn, name);
        if (val == NULL) {
                Py_RETURN_NONE;
        }
@@ -513,23 +559,25 @@ static PyObject 
*py_ldb_dn_get_extended_component(PyLdbDnObject *self, PyObject
        return PyBytes_FromStringAndSize((const char *)val->data, val->length);
 }
 
-static PyObject *py_ldb_dn_set_extended_component(PyLdbDnObject *self, 
PyObject *args)
+static PyObject *py_ldb_dn_set_extended_component(PyObject *self, PyObject 
*args)
 {
        char *name;
        int err;
        uint8_t *value = NULL;
        Py_ssize_t size = 0;
+       struct ldb_dn *dn = NULL;
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
 
        if (!PyArg_ParseTuple(args, "sz#", &name, (char **)&value, &size))
                return NULL;
 
        if (value == NULL) {
-               err = ldb_dn_set_extended_component(self->dn, name, NULL);
+               err = ldb_dn_set_extended_component(dn, name, NULL);
        } else {
                struct ldb_val val;
                val.data = (uint8_t *)value;
                val.length = size;
-               err = ldb_dn_set_extended_component(self->dn, name, &val);
+               err = ldb_dn_set_extended_component(dn, name, &val);
        }
 
        if (err != LDB_SUCCESS) {
@@ -567,25 +615,33 @@ static PyObject *py_ldb_dn_check_special(PyLdbDnObject 
*self, PyObject *args)
        return PyBool_FromLong(ldb_dn_check_special(self->dn, name));
 }
 
-static PyObject *py_ldb_dn_richcmp(PyObject *dn1, PyObject *dn2, int op)
+static PyObject *py_ldb_dn_richcmp(PyObject *pydn1, PyObject *pydn2, int op)
 {
        int ret;
-       if (!pyldb_Dn_Check(dn2)) {
+       struct ldb_dn *dn1 = NULL;
+       struct ldb_dn *dn2 = NULL;
+       if (!pyldb_Dn_Check(pydn2)) {
                Py_INCREF(Py_NotImplemented);
                return Py_NotImplemented;
        }
-       ret = ldb_dn_compare(pyldb_Dn_AS_DN(dn1), pyldb_Dn_AS_DN(dn2));
+       PyErr_internal_LDB_DN_OR_RAISE(pydn1, dn1);
+       PyErr_internal_LDB_DN_OR_RAISE(pydn2, dn2);
+
+       ret = ldb_dn_compare(dn1, dn2);
        return richcmp(ret, op);
 }
 
-static PyObject *py_ldb_dn_get_parent(PyLdbDnObject *self,
+static PyObject *py_ldb_dn_get_parent(PyObject *self,
                PyObject *Py_UNUSED(ignored))
 {
-       struct ldb_dn *dn = pyldb_Dn_AS_DN((PyObject *)self);
+       struct ldb_dn *dn = NULL;
        struct ldb_dn *parent;
-       PyLdbDnObject *py_ret;
+       PyLdbDnObject *py_ret = NULL;
+       PyLdbDnObject *dn_self = NULL;
        TALLOC_CTX *mem_ctx = NULL;
 
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
+
        if (ldb_dn_get_comp_num(dn) < 1) {
                Py_RETURN_NONE;
        }
@@ -609,64 +665,180 @@ static PyObject *py_ldb_dn_get_parent(PyLdbDnObject 
*self,
                talloc_free(mem_ctx);
                return NULL;
        }
+       dn_self = (PyLdbDnObject *)self;
+
        py_ret->mem_ctx = mem_ctx;
        py_ret->dn = parent;
+       py_ret->pyldb = dn_self->pyldb;
+       Py_INCREF(py_ret->pyldb);
        return (PyObject *)py_ret;
 }
 
-static PyObject *py_ldb_dn_add_child(PyLdbDnObject *self, PyObject *args)
+static PyObject *py_ldb_dn_add_child(PyObject *self, PyObject *args)
 {
-       PyObject *py_other;
-       struct ldb_dn *dn, *other;
+       PyObject *py_other = NULL;
+       struct ldb_dn *dn = NULL;
+       struct ldb_dn *other = NULL;
+       TALLOC_CTX *tmp_ctx = NULL;
        bool ok;
-       if (!PyArg_ParseTuple(args, "O", &py_other))
+
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
+
+       if (!PyArg_ParseTuple(args, "O", &py_other)) {
                return NULL;
+       }
 
-       dn = pyldb_Dn_AS_DN((PyObject *)self);
+       /*
+        * pyldb_Object_AsDn only uses tmp_ctx if py_other is str/bytes, in
+        * which case it allocates a struct ldb_dn. If py_other is a PyLdbDn,
+        * tmp_ctx is unused and the underlying dn is borrowed.
+        *
+        * The pieces of other are reassembled onto dn using dn itself as a
+        * talloc context (ldb_dn_add_child assumes all dns are talloc
+        * contexts), after which we don't need any temporary DN we made.
+        */
+       tmp_ctx = talloc_new(NULL);
+       if (tmp_ctx == NULL) {
+               PyErr_NoMemory();
+               return NULL;
+       }
 
-       if (!pyldb_Object_AsDn(NULL, py_other, ldb_dn_get_ldb_context(dn), 
&other))
+       ok = pyldb_Object_AsDn(tmp_ctx,
+                              py_other,
+                              ldb_dn_get_ldb_context(dn),
+                              &other);
+       if (!ok) {
+               TALLOC_FREE(tmp_ctx);
                return NULL;
+       }
 
        ok = ldb_dn_add_child(dn, other);
+       TALLOC_FREE(tmp_ctx);
        if (!ok) {
                PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, 
NULL);
                return NULL;
        }
-
        Py_RETURN_TRUE;
 }
 
-static PyObject *py_ldb_dn_add_base(PyLdbDnObject *self, PyObject *args)
+static PyObject *py_ldb_dn_add_base(PyObject *self, PyObject *args)
 {
-       PyObject *py_other;
-       struct ldb_dn *other, *dn;
+       PyObject *py_other = NULL;
+       struct ldb_dn *other = NULL;
+       struct ldb_dn *dn = NULL;
+       TALLOC_CTX *tmp_ctx = NULL;
        bool ok;
-       if (!PyArg_ParseTuple(args, "O", &py_other))
-               return NULL;
 
-       dn = pyldb_Dn_AS_DN((PyObject *)self);
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
 
-       if (!pyldb_Object_AsDn(NULL, py_other, ldb_dn_get_ldb_context(dn), 
&other))
+       if (!PyArg_ParseTuple(args, "O", &py_other)) {
                return NULL;
+       }
+
+       /*
+        * As noted in py_ldb_dn_add_child() comments, if py_other is a
+        * string, other is an ephemeral struct ldb_dn, but if py_other is a
+        * python DN, other points to the corresponding long-lived DN.
+        */
+       tmp_ctx = talloc_new(NULL);
+       if (tmp_ctx == NULL) {
+               PyErr_NoMemory();
+               return NULL;
+       }
+       ok = pyldb_Object_AsDn(tmp_ctx,
+                              py_other,
+                              ldb_dn_get_ldb_context(dn),
+                              &other);
+       if (!ok) {
+               TALLOC_FREE(tmp_ctx);
+               return NULL;
+       }
 
        ok = ldb_dn_add_base(dn, other);
+       TALLOC_FREE(tmp_ctx);
        if (!ok) {
                PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, 
NULL);
                return NULL;
        }
-
        Py_RETURN_TRUE;
 }
 
-static PyObject *py_ldb_dn_remove_base_components(PyLdbDnObject *self, 
PyObject *args)
+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;
+       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;
        int i;
        bool ok;
-       if (!PyArg_ParseTuple(args, "i", &i))
+       if (!PyArg_ParseTuple(args, "i", &i)) {
                return NULL;
+       }
 
-       dn = pyldb_Dn_AS_DN((PyObject *)self);
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
 
        ok = ldb_dn_remove_base_components(dn, i);
        if (!ok) {
@@ -677,14 +849,15 @@ static PyObject 
*py_ldb_dn_remove_base_components(PyLdbDnObject *self, PyObject
        Py_RETURN_TRUE;
 }
 
-static PyObject *py_ldb_dn_is_child_of(PyLdbDnObject *self, PyObject *args)
+static PyObject *py_ldb_dn_is_child_of(PyObject *self, PyObject *args)
 {
        PyObject *py_base;
        struct ldb_dn *dn, *base;
-       if (!PyArg_ParseTuple(args, "O", &py_base))
+       if (!PyArg_ParseTuple(args, "O", &py_base)) {
                return NULL;
+       }
 
-       dn = pyldb_Dn_AS_DN((PyObject *)self);
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
 
        if (!pyldb_Object_AsDn(NULL, py_base, ldb_dn_get_ldb_context(dn), 
&base))
                return NULL;
@@ -692,16 +865,17 @@ static PyObject *py_ldb_dn_is_child_of(PyLdbDnObject 
*self, PyObject *args)
        return PyBool_FromLong(ldb_dn_compare_base(base, dn) == 0);
 }
 
-static PyObject *py_ldb_dn_get_component_name(PyLdbDnObject *self, PyObject 
*args)
+static PyObject *py_ldb_dn_get_component_name(PyObject *self, PyObject *args)
 {
-       struct ldb_dn *dn;
+       struct ldb_dn *dn = NULL;
        const char *name;
        unsigned int num = 0;
 
-       if (!PyArg_ParseTuple(args, "I", &num))
+       if (!PyArg_ParseTuple(args, "I", &num)) {
                return NULL;
+       }
 
-       dn = pyldb_Dn_AS_DN((PyObject *)self);
+       PyErr_internal_LDB_DN_OR_RAISE(self, dn);
 


-- 
Samba Shared Repository


Reply via email to