LCOV - code coverage report
Current view: top level - lib/ldb - pyldb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 1837 2496 73.6 %
Date: 2024-04-21 15:09:00 Functions: 138 145 95.2 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Python interface to ldb.
       5             : 
       6             :    Copyright (C) 2005,2006 Tim Potter <tpot@samba.org>
       7             :    Copyright (C) 2006 Simo Sorce <idra@samba.org>
       8             :    Copyright (C) 2007-2010 Jelmer Vernooij <jelmer@samba.org>
       9             :    Copyright (C) 2009-2010 Matthias Dieter Wallnöfer
      10             :    Copyright (C) 2009-2011 Andrew Tridgell
      11             :    Copyright (C) 2009-2011 Andrew Bartlett
      12             : 
      13             :     ** NOTE! The following LGPL license applies to the ldb
      14             :     ** library. This does NOT imply that all of Samba is released
      15             :     ** under the LGPL
      16             : 
      17             :    This library is free software; you can redistribute it and/or
      18             :    modify it under the terms of the GNU Lesser General Public
      19             :    License as published by the Free Software Foundation; either
      20             :    version 3 of the License, or (at your option) any later version.
      21             : 
      22             :    This library is distributed in the hope that it will be useful,
      23             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      24             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      25             :    Lesser General Public License for more details.
      26             : 
      27             :    You should have received a copy of the GNU Lesser General Public
      28             :    License along with this library; if not, see <http://www.gnu.org/licenses/>.
      29             : */
      30             : 
      31             : #include "lib/replace/system/python.h"
      32             : #include "ldb_private.h"
      33             : #include "ldb_handlers.h"
      34             : #include "pyldb.h"
      35             : #include "dlinklist.h"
      36             : 
      37             : /* discard signature of 'func' in favour of 'target_sig' */
      38             : #define PY_DISCARD_FUNC_SIG(target_sig, func) (target_sig)(void(*)(void))func
      39             : 
      40             : struct py_ldb_search_iterator_reply;
      41             : 
      42             : typedef struct {
      43             :         PyObject_HEAD
      44             :         TALLOC_CTX *mem_ctx;
      45             :         PyLdbObject *ldb;
      46             :         struct {
      47             :                 struct ldb_request *req;
      48             :                 struct py_ldb_search_iterator_reply *next;
      49             :                 struct py_ldb_search_iterator_reply *result;
      50             :                 PyObject *exception;
      51             :         } state;
      52             : } PyLdbSearchIteratorObject;
      53             : 
      54             : struct py_ldb_search_iterator_reply {
      55             :         struct py_ldb_search_iterator_reply *prev, *next;
      56             :         PyLdbSearchIteratorObject *py_iter;
      57             :         PyObject *obj;
      58             : };
      59             : 
      60             : void initldb(void);
      61             : static PyObject *PyLdbMessage_FromMessage(struct ldb_message *msg, PyLdbObject *pyldb);
      62             : static PyObject *PyExc_LdbError;
      63             : 
      64             : static PyTypeObject PyLdbControl;
      65             : static PyTypeObject PyLdbResult;
      66             : static PyTypeObject PyLdbSearchIterator;
      67             : static PyTypeObject PyLdbMessage;
      68             : #define pyldb_Message_Check(ob) PyObject_TypeCheck(ob, &PyLdbMessage)
      69             : static PyTypeObject PyLdbDn;
      70             : #define pyldb_Dn_Check(ob) PyObject_TypeCheck(ob, &PyLdbDn)
      71             : static PyTypeObject PyLdb;
      72             : static PyTypeObject PyLdbMessageElement;
      73             : #define pyldb_MessageElement_Check(ob) PyObject_TypeCheck(ob, &PyLdbMessageElement)
      74             : 
      75             : static PyTypeObject PyLdbTree;
      76             : static struct ldb_message_element *PyObject_AsMessageElement(
      77             :                                                       TALLOC_CTX *mem_ctx,
      78             :                                                       PyObject *set_obj,
      79             :                                                       unsigned int flags,
      80             :                                                       const char *attr_name);
      81             : static PyTypeObject PyLdbBytesType;
      82             : 
      83             : #define PYARG_STR_UNI "es"
      84             : 
      85    53650166 : static PyObject *PyLdbBytes_FromStringAndSize(const char *msg, int size)
      86             : {
      87    53650166 :         PyObject* result = NULL;
      88    53650166 :         PyObject* args = NULL;
      89    53650166 :         args = Py_BuildValue("(y#)", msg, size);
      90    53650166 :         if (args == NULL) {
      91           0 :                 return NULL;
      92             :         }
      93    53650166 :         result = PyLdbBytesType.tp_new(&PyLdbBytesType, args, NULL);
      94    47235932 :         Py_DECREF(args);
      95    46981384 :         return result;
      96             : }
      97             : 
      98    24691637 : static PyObject *richcmp(int cmp_val, int op)
      99             : {
     100     2851660 :         int ret;
     101    24691637 :         switch (op) {
     102        4189 :                 case Py_LT: ret = cmp_val < 0;  break;
     103           0 :                 case Py_LE: ret = cmp_val <= 0; break;
     104    22900040 :                 case Py_EQ: ret = cmp_val == 0; break;
     105     1787408 :                 case Py_NE: ret = cmp_val != 0; break;
     106           0 :                 case Py_GT: ret = cmp_val > 0;  break;
     107           0 :                 case Py_GE: ret = cmp_val >= 0; break;
     108           0 :                 default:
     109           0 :                         Py_INCREF(Py_NotImplemented);
     110           0 :                         return Py_NotImplemented;
     111             :         }
     112    24691637 :         return PyBool_FromLong(ret);
     113             : }
     114             : 
     115             : 
     116       54791 : static PyObject *py_ldb_control_str(PyLdbControlObject *self)
     117             : {
     118       54791 :         if (self->data != NULL) {
     119       54791 :                 char* control = ldb_control_to_string(self->mem_ctx, self->data);
     120       54791 :                 if (control == NULL) {
     121           0 :                         PyErr_NoMemory();
     122           0 :                         return NULL;
     123             :                 }
     124       54791 :                 return PyUnicode_FromString(control);
     125             :         } else {
     126           0 :                 return PyUnicode_FromString("ldb control");
     127             :         }
     128             : }
     129             : 
     130      105738 : static void py_ldb_control_dealloc(PyLdbControlObject *self)
     131             : {
     132      105738 :         if (self->mem_ctx != NULL) {
     133      105738 :                 talloc_free(self->mem_ctx);
     134             :         }
     135      105738 :         self->data = NULL;
     136      105738 :         Py_TYPE(self)->tp_free(self);
     137      105738 : }
     138             : 
     139             : /* Create a text (rather than bytes) interface for a LDB result object */
     140         108 : static PyObject *wrap_text(const char *type, PyObject *wrapped)
     141             : {
     142           0 :         PyObject *mod, *cls, *constructor, *inst;
     143         108 :         mod = PyImport_ImportModule("_ldb_text");
     144         108 :         if (mod == NULL)
     145           0 :                 return NULL;
     146         108 :         cls = PyObject_GetAttrString(mod, type);
     147         108 :         Py_DECREF(mod);
     148         108 :         if (cls == NULL) {
     149           0 :                 Py_DECREF(mod);
     150           0 :                 return NULL;
     151             :         }
     152         108 :         constructor = PyObject_GetAttrString(cls, "_wrap");
     153         108 :         Py_DECREF(cls);
     154         108 :         if (constructor == NULL) {
     155           0 :                 return NULL;
     156             :         }
     157         108 :         inst = PyObject_CallFunction(constructor, discard_const_p(char, "O"), wrapped);
     158         108 :         Py_DECREF(constructor);
     159         108 :         return inst;
     160             : }
     161             : 
     162        9259 : static PyObject *py_ldb_control_get_oid(PyLdbControlObject *self,
     163             :                 PyObject *Py_UNUSED(ignored))
     164             : {
     165        9259 :         return PyUnicode_FromString(self->data->oid);
     166             : }
     167             : 
     168           4 : static PyObject *py_ldb_control_get_critical(PyLdbControlObject *self,
     169             :                 PyObject *Py_UNUSED(ignored))
     170             : {
     171           4 :         return PyBool_FromLong(self->data->critical);
     172             : }
     173             : 
     174         130 : static int py_ldb_control_set_critical(PyLdbControlObject *self, PyObject *value, void *closure)
     175             : {
     176         130 :         if (value == NULL) {
     177           0 :                 PyErr_SetString(PyExc_AttributeError, "cannot delete critical flag");
     178           0 :                 return -1;
     179             :         }
     180         130 :         if (PyObject_IsTrue(value)) {
     181         130 :                 self->data->critical = true;
     182             :         } else {
     183           0 :                 self->data->critical = false;
     184             :         }
     185         130 :         return 0;
     186             : }
     187             : 
     188          12 : static PyObject *py_ldb_control_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
     189             : {
     190          12 :         char *data = NULL;
     191          12 :         const char * const kwnames[] = { "ldb", "data", NULL };
     192           0 :         struct ldb_control *parsed_controls;
     193           0 :         PyLdbControlObject *ret;
     194           0 :         PyObject *py_ldb;
     195           0 :         TALLOC_CTX *mem_ctx;
     196           0 :         struct ldb_context *ldb_ctx;
     197             : 
     198          12 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!s",
     199             :                                          discard_const_p(char *, kwnames),
     200             :                                          &PyLdb, &py_ldb, &data))
     201           4 :                 return NULL;
     202             : 
     203           8 :         mem_ctx = talloc_new(NULL);
     204           8 :         if (mem_ctx == NULL) {
     205           0 :                 PyErr_NoMemory();
     206           0 :                 return NULL;
     207             :         }
     208             : 
     209           8 :         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(py_ldb);
     210           8 :         parsed_controls = ldb_parse_control_from_string(ldb_ctx, mem_ctx, data);
     211             : 
     212           8 :         if (!parsed_controls) {
     213           4 :                 talloc_free(mem_ctx);
     214           4 :                 PyErr_SetString(PyExc_ValueError, "unable to parse control string");
     215           4 :                 return NULL;
     216             :         }
     217             : 
     218           4 :         ret = PyObject_New(PyLdbControlObject, type);
     219           4 :         if (ret == NULL) {
     220           0 :                 PyErr_NoMemory();
     221           0 :                 talloc_free(mem_ctx);
     222           0 :                 return NULL;
     223             :         }
     224             : 
     225           4 :         ret->mem_ctx = mem_ctx;
     226             : 
     227           4 :         ret->data = talloc_move(mem_ctx, &parsed_controls);
     228           4 :         if (ret->data == NULL) {
     229           0 :                 Py_DECREF(ret);
     230           0 :                 PyErr_NoMemory();
     231           0 :                 talloc_free(mem_ctx);
     232           0 :                 return NULL;
     233             :         }
     234             : 
     235           4 :         return (PyObject *)ret;
     236             : }
     237             : 
     238             : static PyGetSetDef py_ldb_control_getset[] = {
     239             :         {
     240             :                 .name = discard_const_p(char, "oid"),
     241             :                 .get  = (getter)py_ldb_control_get_oid,
     242             :         },
     243             :         {
     244             :                 .name = discard_const_p(char, "critical"),
     245             :                 .get  = (getter)py_ldb_control_get_critical,
     246             :                 .set  = (setter)py_ldb_control_set_critical,
     247             :         },
     248             :         { .name = NULL },
     249             : };
     250             : 
     251             : static PyTypeObject PyLdbControl = {
     252             :         .tp_name = "ldb.control",
     253             :         .tp_dealloc = (destructor)py_ldb_control_dealloc,
     254             :         .tp_getattro = PyObject_GenericGetAttr,
     255             :         .tp_basicsize = sizeof(PyLdbControlObject),
     256             :         .tp_getset = py_ldb_control_getset,
     257             :         .tp_doc = "LDB control.",
     258             :         .tp_str = (reprfunc)py_ldb_control_str,
     259             :         .tp_new = py_ldb_control_new,
     260             :         .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
     261             : };
     262             : 
     263     4148429 : static PyObject *py_ldb_bytes_str(PyBytesObject *self)
     264             : {
     265     4148429 :         char *msg = NULL;
     266      482758 :         Py_ssize_t size;
     267     4148429 :         int result = 0;
     268     4148429 :         if (!PyBytes_Check(self)) {
     269           0 :                 PyErr_Format(PyExc_TypeError,"Unexpected type");
     270           0 :                 return NULL;
     271             :         }
     272     4148429 :         result = PyBytes_AsStringAndSize((PyObject *)self, &msg, &size);
     273     4148429 :         if (result != 0) {
     274           0 :                 PyErr_Format(PyExc_TypeError, "Failed to extract bytes");
     275           0 :                 return NULL;
     276             :         }
     277     4148429 :         return PyUnicode_FromStringAndSize(msg, size);
     278             : }
     279             : 
     280             : static PyTypeObject PyLdbBytesType = {
     281             :         PyVarObject_HEAD_INIT(NULL, 0)
     282             :         .tp_name = "ldb.bytes",
     283             :         .tp_doc = "str/bytes (with custom str)",
     284             :         .tp_str = (reprfunc)py_ldb_bytes_str,
     285             :         .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
     286             : };
     287             : 
     288    33613209 : static PyObject *PyObject_FromLdbValue(const struct ldb_val *val)
     289             : {
     290    33613209 :         return PyLdbBytes_FromStringAndSize((const char *)val->data, val->length);
     291             : }
     292             : 
     293      525741 : static PyObject *PyStr_FromLdbValue(const struct ldb_val *val)
     294             : {
     295      525741 :         return PyUnicode_FromStringAndSize((const char *)val->data, val->length);
     296             : }
     297             : 
     298             : /**
     299             :  * Create a Python object from a ldb_result.
     300             :  *
     301             :  * @param result LDB result to convert
     302             :  * @return Python object with converted result (a list object)
     303             :  */
     304      105734 : static PyObject *PyLdbControl_FromControl(struct ldb_control *control)
     305             : {
     306      105734 :         TALLOC_CTX *ctl_ctx = talloc_new(NULL);
     307          22 :         PyLdbControlObject *ctrl;
     308      105734 :         if (ctl_ctx == NULL) {
     309           0 :                 PyErr_NoMemory();
     310           0 :                 return NULL;
     311             :         }
     312             : 
     313      105734 :         ctrl = (PyLdbControlObject *)PyLdbControl.tp_alloc(&PyLdbControl, 0);
     314      105734 :         if (ctrl == NULL) {
     315           0 :                 talloc_free(ctl_ctx);
     316           0 :                 PyErr_NoMemory();
     317           0 :                 return NULL;
     318             :         }
     319      105734 :         ctrl->mem_ctx = ctl_ctx;
     320      105734 :         ctrl->data = talloc_steal(ctrl->mem_ctx, control);
     321      105734 :         if (ctrl->data == NULL) {
     322           0 :                 Py_DECREF(ctrl);
     323           0 :                 PyErr_NoMemory();
     324           0 :                 return NULL;
     325             :         }
     326      105712 :         return (PyObject*) ctrl;
     327             : }
     328             : 
     329             : /**
     330             :  * Create a Python object from a ldb_result.
     331             :  *
     332             :  * @param result LDB result to convert
     333             :  * @return Python object with converted result (a list object)
     334             :  */
     335     3258245 : static PyObject *PyLdbResult_FromResult(struct ldb_result *result, PyLdbObject *pyldb)
     336             : {
     337      264730 :         PyLdbResultObject *ret;
     338      264730 :         PyObject *list, *controls, *referals;
     339      264730 :         Py_ssize_t i;
     340             : 
     341     3258245 :         if (result == NULL) {
     342           0 :                 Py_RETURN_NONE;
     343             :         }
     344             : 
     345     3258245 :         ret = (PyLdbResultObject *)PyLdbResult.tp_alloc(&PyLdbResult, 0);
     346     3258245 :         if (ret == NULL) {
     347           0 :                 PyErr_NoMemory();
     348           0 :                 return NULL;
     349             :         }
     350             : 
     351     3258245 :         ret->pyldb = pyldb;
     352     3258245 :         Py_INCREF(ret->pyldb);
     353             : 
     354     3258245 :         list = PyList_New(result->count);
     355     3258245 :         if (list == NULL) {
     356           0 :                 PyErr_NoMemory();
     357           0 :                 Py_DECREF(ret);
     358           0 :                 return NULL;
     359             :         }
     360             : 
     361     8456246 :         for (i = 0; i < result->count; i++) {
     362     5198001 :                 PyObject *pymessage = PyLdbMessage_FromMessage(result->msgs[i], pyldb);
     363     5198001 :                 if (pymessage == NULL) {
     364           0 :                         Py_DECREF(ret);
     365           0 :                         Py_DECREF(list);
     366           0 :                         return NULL;
     367             :                 }
     368     5198001 :                 PyList_SetItem(list, i, pymessage);
     369             :         }
     370             : 
     371     3258245 :         ret->mem_ctx = talloc_new(NULL);
     372     3258245 :         if (ret->mem_ctx == NULL) {
     373           0 :                 Py_DECREF(list);
     374           0 :                 Py_DECREF(ret);
     375           0 :                 PyErr_NoMemory();
     376           0 :                 return NULL;
     377             :         }
     378             : 
     379     3258245 :         ret->msgs = list;
     380             : 
     381     3258245 :         if (result->controls) {
     382      105710 :                 i = 0;
     383      211466 :                 while (result->controls[i]) {
     384      105734 :                         i++;
     385             :                 }
     386      105732 :                 controls = PyList_New(i);
     387      105732 :                 if (controls == NULL) {
     388           0 :                         Py_DECREF(ret);
     389           0 :                         Py_DECREF(list);
     390           0 :                         PyErr_NoMemory();
     391           0 :                         return NULL;
     392             :                 }
     393      211466 :                 for (i=0; result->controls[i]; i++) {
     394      105734 :                         PyObject *ctrl = (PyObject*) PyLdbControl_FromControl(result->controls[i]);
     395      105734 :                         if (ctrl == NULL) {
     396           0 :                                 Py_DECREF(ret);
     397           0 :                                 Py_DECREF(list);
     398           0 :                                 Py_DECREF(controls);
     399           0 :                                 PyErr_NoMemory();
     400           0 :                                 return NULL;
     401             :                         }
     402      105734 :                         PyList_SetItem(controls, i, ctrl);
     403             :                 }
     404             :         } else {
     405             :                 /*
     406             :                  * No controls so we keep an empty list
     407             :                  */
     408     3152513 :                 controls = PyList_New(0);
     409     3152513 :                 if (controls == NULL) {
     410           0 :                         Py_DECREF(ret);
     411           0 :                         Py_DECREF(list);
     412           0 :                         PyErr_NoMemory();
     413           0 :                         return NULL;
     414             :                 }
     415             :         }
     416             : 
     417     3258245 :         ret->controls = controls;
     418             : 
     419     3258245 :         i = 0;
     420             : 
     421     3409320 :         while (result->refs && result->refs[i]) {
     422      151075 :                 i++;
     423             :         }
     424             : 
     425     3258245 :         referals = PyList_New(i);
     426     3258245 :         if (referals == NULL) {
     427           0 :                 Py_DECREF(ret);
     428           0 :                 Py_DECREF(list);
     429           0 :                 PyErr_NoMemory();
     430           0 :                 return NULL;
     431             :         }
     432             : 
     433     3409320 :         for (i = 0;result->refs && result->refs[i]; i++) {
     434      151075 :                 PyList_SetItem(referals, i, PyUnicode_FromString(result->refs[i]));
     435             :         }
     436     3258245 :         ret->referals = referals;
     437     3258245 :         return (PyObject *)ret;
     438             : }
     439             : 
     440             : 
     441             : /*
     442             :  * PyErr_interal_LDB_DN_OR_RAISE does exactly what
     443             :  * PyErr__LDB_DN_OR_RAISE does, but rather than going through the
     444             :  * Python layer to import the Dn object, it directly uses the the
     445             :  * address of the PyTypeObject. This is faster, but can only be done
     446             :  * in pyldb.c.
     447             :  */
     448             : #define PyErr_internal_LDB_DN_OR_RAISE(_py_obj, dn) do {                \
     449             :                 PyLdbDnObject *_py_dn = NULL;                           \
     450             :         if (_py_obj == NULL || !pyldb_Dn_Check(_py_obj)) {              \
     451             :                 PyErr_SetString(PyExc_TypeError, "ldb Dn object required"); \
     452             :                 return NULL;                                            \
     453             :         }                                                               \
     454             :         _py_dn = (PyLdbDnObject *)_py_obj;                              \
     455             :         dn = pyldb_Dn_AS_DN(_py_dn);                                    \
     456             :         if (_py_dn->pyldb->ldb_ctx != ldb_dn_get_ldb_context(dn)) {       \
     457             :                 PyErr_SetString(PyExc_RuntimeError,                     \
     458             :                                 "Dn has a stale LDB connection");     \
     459             :                 return NULL;                                           \
     460             :         }                                                              \
     461             : } while(0)
     462             : 
     463             : 
     464           2 : static PyObject *py_ldb_dn_validate(PyObject *self,
     465             :                 PyObject *Py_UNUSED(ignored))
     466             : {
     467           2 :         struct ldb_dn *dn = NULL;
     468           2 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     469           2 :         return PyBool_FromLong(ldb_dn_validate(dn));
     470             : }
     471             : 
     472           4 : static PyObject *py_ldb_dn_is_valid(PyLdbDnObject *self,
     473             :                 PyObject *Py_UNUSED(ignored))
     474             : {
     475           4 :         return PyBool_FromLong(ldb_dn_is_valid(self->dn));
     476             : }
     477             : 
     478           4 : static PyObject *py_ldb_dn_is_special(PyLdbDnObject *self,
     479             :                 PyObject *Py_UNUSED(ignored))
     480             : {
     481           4 :         return PyBool_FromLong(ldb_dn_is_special(self->dn));
     482             : }
     483             : 
     484           4 : static PyObject *py_ldb_dn_is_null(PyObject *self,
     485             :                 PyObject *Py_UNUSED(ignored))
     486             : {
     487           4 :         struct ldb_dn *dn = NULL;
     488           4 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     489           4 :         return PyBool_FromLong(ldb_dn_is_null(dn));
     490             : }
     491             : 
     492        2040 : static PyObject *py_ldb_dn_get_casefold(PyObject *self,
     493             :                 PyObject *Py_UNUSED(ignored))
     494             : {
     495        2040 :         const char *s = NULL;
     496        2040 :         struct ldb_dn *dn = NULL;
     497        2062 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     498        2040 :         s = ldb_dn_get_casefold(dn);
     499        2040 :         if (s == NULL) {
     500           0 :                 PyErr_NoMemory();
     501           0 :                 return NULL;
     502             :         }
     503        2040 :         return PyUnicode_FromString(s);
     504             : }
     505             : 
     506     7877627 : static PyObject *py_ldb_dn_get_linearized(PyObject *self,
     507             :                 PyObject *Py_UNUSED(ignored))
     508             : {
     509     7877627 :         struct ldb_dn *dn = NULL;
     510     8756831 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     511     7877627 :         return PyUnicode_FromString(ldb_dn_get_linearized(dn));
     512             : }
     513             : 
     514       28756 : static PyObject *py_ldb_dn_canonical_str(PyObject *self,
     515             :                 PyObject *Py_UNUSED(ignored))
     516             : {
     517       28756 :         struct ldb_dn *dn = NULL;
     518       28848 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     519       28756 :         return PyUnicode_FromString(ldb_dn_canonical_string(dn, dn));
     520             : }
     521             : 
     522         232 : static PyObject *py_ldb_dn_canonical_ex_str(PyObject *self,
     523             :                 PyObject *Py_UNUSED(ignored))
     524             : {
     525         232 :         struct ldb_dn *dn = NULL;
     526         274 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     527         232 :         return PyUnicode_FromString(ldb_dn_canonical_ex_string(dn, dn));
     528             : }
     529             : 
     530      216055 : static PyObject *py_ldb_dn_extended_str(PyObject *self, PyObject *args, PyObject *kwargs)
     531             : {
     532      216055 :         const char * const kwnames[] = { "mode", NULL };
     533      216055 :         int mode = 1;
     534      216055 :         struct ldb_dn *dn = NULL;
     535      221352 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     536      216055 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i",
     537             :                                          discard_const_p(char *, kwnames),
     538             :                                          &mode)) {
     539           0 :                 return NULL;
     540             :         }
     541      216055 :         return PyUnicode_FromString(ldb_dn_get_extended_linearized(dn, dn, mode));
     542             : }
     543             : 
     544     3939113 : static PyObject *py_ldb_dn_get_extended_component(PyObject *self, PyObject *args)
     545             : {
     546      496416 :         char *name;
     547     3939113 :         const struct ldb_val *val = NULL;
     548     3939113 :         struct ldb_dn *dn = NULL;
     549     4435529 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     550             : 
     551     3939113 :         if (!PyArg_ParseTuple(args, "s", &name)) {
     552           0 :                 return NULL;
     553             :         }
     554     3939113 :         val = ldb_dn_get_extended_component(dn, name);
     555     3939113 :         if (val == NULL) {
     556     1851242 :                 Py_RETURN_NONE;
     557             :         }
     558             : 
     559     2087871 :         return PyBytes_FromStringAndSize((const char *)val->data, val->length);
     560             : }
     561             : 
     562          17 : static PyObject *py_ldb_dn_set_extended_component(PyObject *self, PyObject *args)
     563             : {
     564           0 :         char *name;
     565           0 :         int err;
     566          17 :         uint8_t *value = NULL;
     567          17 :         Py_ssize_t size = 0;
     568          17 :         struct ldb_dn *dn = NULL;
     569          17 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     570             : 
     571          17 :         if (!PyArg_ParseTuple(args, "sz#", &name, (char **)&value, &size))
     572           0 :                 return NULL;
     573             : 
     574          17 :         if (value == NULL) {
     575           0 :                 err = ldb_dn_set_extended_component(dn, name, NULL);
     576             :         } else {
     577           0 :                 struct ldb_val val;
     578          17 :                 val.data = (uint8_t *)value;
     579          17 :                 val.length = size;
     580          17 :                 err = ldb_dn_set_extended_component(dn, name, &val);
     581             :         }
     582             : 
     583          17 :         if (err != LDB_SUCCESS) {
     584           0 :                 PyErr_SetString(PyExc_TypeError, "Failed to set extended component");
     585           0 :                 return NULL;
     586             :         }
     587             : 
     588          17 :         Py_RETURN_NONE;
     589             : }
     590             : 
     591       64754 : static PyObject *py_ldb_dn_repr(PyLdbDnObject *self)
     592             : {
     593       64754 :         PyObject *str = PyUnicode_FromString(ldb_dn_get_linearized(self->dn));
     594           0 :         PyObject *repr, *result;
     595       64754 :         if (str == NULL)
     596           0 :                 return NULL;
     597       64754 :         repr = PyObject_Repr(str);
     598       64754 :         if (repr == NULL) {
     599           0 :                 Py_DECREF(str);
     600           0 :                 return NULL;
     601             :         }
     602       64754 :         result = PyUnicode_FromFormat("Dn(%s)", PyUnicode_AsUTF8(repr));
     603       36251 :         Py_DECREF(str);
     604       36251 :         Py_DECREF(repr);
     605       64754 :         return result;
     606             : }
     607             : 
     608           4 : static PyObject *py_ldb_dn_check_special(PyLdbDnObject *self, PyObject *args)
     609             : {
     610           0 :         char *name;
     611             : 
     612           4 :         if (!PyArg_ParseTuple(args, "s", &name))
     613           0 :                 return NULL;
     614             : 
     615           4 :         return PyBool_FromLong(ldb_dn_check_special(self->dn, name));
     616             : }
     617             : 
     618    26623338 : static PyObject *py_ldb_dn_richcmp(PyObject *pydn1, PyObject *pydn2, int op)
     619             : {
     620     3074082 :         int ret;
     621    26623338 :         struct ldb_dn *dn1 = NULL;
     622    26623338 :         struct ldb_dn *dn2 = NULL;
     623    26623338 :         if (!pyldb_Dn_Check(pydn2)) {
     624     1640550 :                 Py_INCREF(Py_NotImplemented);
     625     1932691 :                 return Py_NotImplemented;
     626             :         }
     627    27542306 :         PyErr_internal_LDB_DN_OR_RAISE(pydn1, dn1);
     628    24690647 :         PyErr_internal_LDB_DN_OR_RAISE(pydn2, dn2);
     629             : 
     630    24690647 :         ret = ldb_dn_compare(dn1, dn2);
     631    24690647 :         return richcmp(ret, op);
     632             : }
     633             : 
     634     2366147 : static PyObject *py_ldb_dn_get_parent(PyObject *self,
     635             :                 PyObject *Py_UNUSED(ignored))
     636             : {
     637     2366147 :         struct ldb_dn *dn = NULL;
     638      251111 :         struct ldb_dn *parent;
     639     2366147 :         PyLdbDnObject *py_ret = NULL;
     640     2366147 :         PyLdbDnObject *dn_self = NULL;
     641     2366147 :         TALLOC_CTX *mem_ctx = NULL;
     642             : 
     643     2617258 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     644             : 
     645     2366147 :         if (ldb_dn_get_comp_num(dn) < 1) {
     646           2 :                 Py_RETURN_NONE;
     647             :         }
     648             : 
     649     2366145 :         mem_ctx = talloc_new(NULL);
     650     2366145 :         if (mem_ctx == NULL) {
     651           0 :                 PyErr_NoMemory();
     652           0 :                 return NULL;
     653             :         }
     654             : 
     655     2366145 :         parent = ldb_dn_get_parent(mem_ctx, dn);
     656     2366145 :         if (parent == NULL) {
     657           0 :                 PyErr_NoMemory();
     658           0 :                 talloc_free(mem_ctx);
     659           0 :                 return NULL;
     660             :         }
     661             : 
     662     2366145 :         py_ret = (PyLdbDnObject *)PyLdbDn.tp_alloc(&PyLdbDn, 0);
     663     2366145 :         if (py_ret == NULL) {
     664           0 :                 PyErr_NoMemory();
     665           0 :                 talloc_free(mem_ctx);
     666           0 :                 return NULL;
     667             :         }
     668     2366145 :         dn_self = (PyLdbDnObject *)self;
     669             : 
     670     2366145 :         py_ret->mem_ctx = mem_ctx;
     671     2366145 :         py_ret->dn = parent;
     672     2366145 :         py_ret->pyldb = dn_self->pyldb;
     673     2366145 :         Py_INCREF(py_ret->pyldb);
     674     2366145 :         return (PyObject *)py_ret;
     675             : }
     676             : 
     677        6204 : static PyObject *py_ldb_dn_add_child(PyObject *self, PyObject *args)
     678             : {
     679        6204 :         PyObject *py_other = NULL;
     680        6204 :         struct ldb_dn *dn = NULL;
     681        6204 :         struct ldb_dn *other = NULL;
     682        6204 :         TALLOC_CTX *tmp_ctx = NULL;
     683         102 :         bool ok;
     684             : 
     685        6306 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     686             : 
     687        6204 :         if (!PyArg_ParseTuple(args, "O", &py_other)) {
     688           0 :                 return NULL;
     689             :         }
     690             : 
     691             :         /*
     692             :          * pyldb_Object_AsDn only uses tmp_ctx if py_other is str/bytes, in
     693             :          * which case it allocates a struct ldb_dn. If py_other is a PyLdbDn,
     694             :          * tmp_ctx is unused and the underlying dn is borrowed.
     695             :          *
     696             :          * The pieces of other are reassembled onto dn using dn itself as a
     697             :          * talloc context (ldb_dn_add_child assumes all dns are talloc
     698             :          * contexts), after which we don't need any temporary DN we made.
     699             :          */
     700        6204 :         tmp_ctx = talloc_new(NULL);
     701        6204 :         if (tmp_ctx == NULL) {
     702           0 :                 PyErr_NoMemory();
     703           0 :                 return NULL;
     704             :         }
     705             : 
     706        6204 :         ok = pyldb_Object_AsDn(tmp_ctx,
     707             :                                py_other,
     708             :                                ldb_dn_get_ldb_context(dn),
     709             :                                &other);
     710        6204 :         if (!ok) {
     711           0 :                 TALLOC_FREE(tmp_ctx);
     712           0 :                 return NULL;
     713             :         }
     714             : 
     715        6204 :         ok = ldb_dn_add_child(dn, other);
     716        6204 :         TALLOC_FREE(tmp_ctx);
     717        6204 :         if (!ok) {
     718           0 :                 PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, NULL);
     719           0 :                 return NULL;
     720             :         }
     721        6204 :         Py_RETURN_TRUE;
     722             : }
     723             : 
     724        2726 : static PyObject *py_ldb_dn_add_base(PyObject *self, PyObject *args)
     725             : {
     726        2726 :         PyObject *py_other = NULL;
     727        2726 :         struct ldb_dn *other = NULL;
     728        2726 :         struct ldb_dn *dn = NULL;
     729        2726 :         TALLOC_CTX *tmp_ctx = NULL;
     730          19 :         bool ok;
     731             : 
     732        2745 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     733             : 
     734        2726 :         if (!PyArg_ParseTuple(args, "O", &py_other)) {
     735           0 :                 return NULL;
     736             :         }
     737             : 
     738             :         /*
     739             :          * As noted in py_ldb_dn_add_child() comments, if py_other is a
     740             :          * string, other is an ephemeral struct ldb_dn, but if py_other is a
     741             :          * python DN, other points to the corresponding long-lived DN.
     742             :          */
     743        2726 :         tmp_ctx = talloc_new(NULL);
     744        2726 :         if (tmp_ctx == NULL) {
     745           0 :                 PyErr_NoMemory();
     746           0 :                 return NULL;
     747             :         }
     748        2726 :         ok = pyldb_Object_AsDn(tmp_ctx,
     749             :                                py_other,
     750             :                                ldb_dn_get_ldb_context(dn),
     751             :                                &other);
     752        2726 :         if (!ok) {
     753           0 :                 TALLOC_FREE(tmp_ctx);
     754           0 :                 return NULL;
     755             :         }
     756             : 
     757        2726 :         ok = ldb_dn_add_base(dn, other);
     758        2726 :         TALLOC_FREE(tmp_ctx);
     759        2726 :         if (!ok) {
     760           0 :                 PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, NULL);
     761           0 :                 return NULL;
     762             :         }
     763        2726 :         Py_RETURN_TRUE;
     764             : }
     765             : 
     766             : static PyObject *py_ldb_dn_copy(struct ldb_dn *dn, PyLdbObject *pyldb);
     767             : 
     768       13530 : static PyObject *py_ldb_dn_copy_method(PyObject *self, PyObject *args)
     769             : {
     770       13530 :         struct ldb_dn *dn = NULL;
     771       13530 :         PyLdbObject *pyldb = NULL;
     772       13530 :         PyObject *obj = Py_None;
     773       13533 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     774             : 
     775       13530 :         if (!PyArg_ParseTuple(args, "|O", &obj)) {
     776           0 :                 return NULL;
     777             :         }
     778             : 
     779       13530 :         if (obj == Py_None) {
     780             :                 /*
     781             :                  * With no argument, or None, dn.copy() uses its own ldb.
     782             :                  *
     783             :                  * There is not much reason to do this, other than as a
     784             :                  * convenience in this situation:
     785             :                  *
     786             :                  * >>> msg.dn = dn.copy(msg.ldb)
     787             :                  *
     788             :                  * when you don't know whether msg has a dn or not (if msg.ldb
     789             :                  * is None, msg will now belong to this dn's ldb).
     790             :                  */
     791           0 :                 pyldb = ((PyLdbDnObject *)self)->pyldb;
     792       13530 :         } else if (PyObject_TypeCheck(obj, &PyLdb)) {
     793       13530 :                 pyldb = (PyLdbObject *)obj;
     794             :         } else {
     795           0 :                 PyErr_Format(PyExc_TypeError,
     796             :                              "Expected Ldb or None");
     797           0 :                 return NULL;
     798             :         }
     799       13530 :         if (pyldb != ((PyLdbDnObject *)self)->pyldb) {
     800             :                 /*
     801             :                  * This is unfortunate, but we can't make a copy of the dn directly,
     802             :                  * since the opaque struct ldb_dn has a pointer to the ldb it knows,
     803             :                  * and it is the WRONG ONE.
     804             :                  *
     805             :                  * Instead we go via string serialisation.
     806             :                  */
     807        6797 :                 char *dn_str = NULL;
     808        6797 :                 struct ldb_dn *new_dn = NULL;
     809        6797 :                 dn_str = ldb_dn_get_extended_linearized(pyldb->mem_ctx, dn, 1);
     810        6797 :                 if (dn_str == NULL) {
     811           0 :                         PyErr_Format(PyExc_RuntimeError,
     812             :                                      "Could not linearize DN");
     813           0 :                         return NULL;
     814             :                 }
     815        6797 :                 new_dn = ldb_dn_new(pyldb->mem_ctx,
     816             :                                     pyldb->ldb_ctx,
     817             :                                     dn_str);
     818             : 
     819        6797 :                 if (new_dn == NULL) {
     820           0 :                         PyErr_Format(PyExc_RuntimeError,
     821             :                                      "Could not re-parse DN '%s'",
     822             :                                 dn_str);
     823           0 :                         TALLOC_FREE(dn_str);
     824           0 :                         return NULL;
     825             :                 }
     826        6797 :                 TALLOC_FREE(dn_str);
     827        6797 :                 dn = new_dn;
     828             :         }
     829       13530 :         return py_ldb_dn_copy(dn, pyldb);
     830             : }
     831             : 
     832         187 : static PyObject *py_ldb_dn_remove_base_components(PyObject *self, PyObject *args)
     833             : {
     834         187 :         struct ldb_dn *dn = NULL;
     835           0 :         int i;
     836           0 :         bool ok;
     837         187 :         if (!PyArg_ParseTuple(args, "i", &i)) {
     838           0 :                 return NULL;
     839             :         }
     840             : 
     841         187 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     842             : 
     843         187 :         ok = ldb_dn_remove_base_components(dn, i);
     844         187 :         if (!ok) {
     845           0 :                 PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, NULL);
     846           0 :                 return NULL;
     847             :         }
     848             : 
     849         187 :         Py_RETURN_TRUE;
     850             : }
     851             : 
     852      909527 : static PyObject *py_ldb_dn_is_child_of(PyObject *self, PyObject *args)
     853             : {
     854       86056 :         PyObject *py_base;
     855       86056 :         struct ldb_dn *dn, *base;
     856      909527 :         if (!PyArg_ParseTuple(args, "O", &py_base)) {
     857           0 :                 return NULL;
     858             :         }
     859             : 
     860      995583 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     861             : 
     862      909527 :         if (!pyldb_Object_AsDn(NULL, py_base, ldb_dn_get_ldb_context(dn), &base))
     863           0 :                 return NULL;
     864             : 
     865      909527 :         return PyBool_FromLong(ldb_dn_compare_base(base, dn) == 0);
     866             : }
     867             : 
     868         628 : static PyObject *py_ldb_dn_get_component_name(PyObject *self, PyObject *args)
     869             : {
     870         628 :         struct ldb_dn *dn = NULL;
     871           0 :         const char *name;
     872         628 :         unsigned int num = 0;
     873             : 
     874         628 :         if (!PyArg_ParseTuple(args, "I", &num)) {
     875           0 :                 return NULL;
     876             :         }
     877             : 
     878         628 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     879             : 
     880         628 :         name = ldb_dn_get_component_name(dn, num);
     881         628 :         if (name == NULL) {
     882           8 :                 Py_RETURN_NONE;
     883             :         }
     884             : 
     885         620 :         return PyUnicode_FromString(name);
     886             : }
     887             : 
     888         282 : static PyObject *py_ldb_dn_get_component_value(PyObject *self, PyObject *args)
     889             : {
     890         282 :         struct ldb_dn *dn = NULL;
     891           0 :         const struct ldb_val *val;
     892         282 :         unsigned int num = 0;
     893             : 
     894         282 :         if (!PyArg_ParseTuple(args, "I", &num)) {
     895           0 :                 return NULL;
     896             :         }
     897             : 
     898         282 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     899             : 
     900         282 :         val = ldb_dn_get_component_val(dn, num);
     901         282 :         if (val == NULL) {
     902           0 :                 Py_RETURN_NONE;
     903             :         }
     904             : 
     905         282 :         return PyStr_FromLdbValue(val);
     906             : }
     907             : 
     908      525250 : static PyObject *py_ldb_dn_set_component(PyObject *self, PyObject *args)
     909             : {
     910      525250 :         unsigned int num = 0;
     911      525250 :         char *name = NULL, *value = NULL;
     912      525250 :         struct ldb_val val = { 0 };
     913       72190 :         int err;
     914      525250 :         Py_ssize_t size = 0;
     915      525250 :         struct ldb_dn *dn = NULL;
     916             : 
     917      597440 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     918             : 
     919      525250 :         if (!PyArg_ParseTuple(args, "Iss#", &num, &name, &value, &size)) {
     920           2 :                 return NULL;
     921             :         }
     922             : 
     923      525248 :         val.data = (unsigned char*) value;
     924      525248 :         val.length = size;
     925             : 
     926      525248 :         err = ldb_dn_set_component(dn, num, name, val);
     927      525248 :         if (err != LDB_SUCCESS) {
     928           2 :                 PyErr_SetString(PyExc_TypeError, "Failed to set component");
     929           2 :                 return NULL;
     930             :         }
     931             : 
     932      525246 :         Py_RETURN_NONE;
     933             : }
     934             : 
     935    13171074 : static PyObject *py_ldb_dn_get_rdn_name(PyObject *self,
     936             :                 PyObject *Py_UNUSED(ignored))
     937             : {
     938    13171074 :         struct ldb_dn *dn = NULL;
     939     1794990 :         const char *name;
     940             : 
     941    14966064 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     942             : 
     943    13171074 :         name = ldb_dn_get_rdn_name(dn);
     944    13171074 :         if (name == NULL) {
     945           0 :                 Py_RETURN_NONE;
     946             :         }
     947             : 
     948    13171074 :         return PyUnicode_FromString(name);
     949             : }
     950             : 
     951      525459 : static PyObject *py_ldb_dn_get_rdn_value(PyObject *self,
     952             :                 PyObject *Py_UNUSED(ignored))
     953             : {
     954      525459 :         struct ldb_dn *dn = NULL;
     955       72198 :         const struct ldb_val *val;
     956             : 
     957      597657 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
     958             : 
     959      525459 :         val = ldb_dn_get_rdn_val(dn);
     960      525459 :         if (val == NULL) {
     961           0 :                 Py_RETURN_NONE;
     962             :         }
     963             : 
     964      525459 :         return PyStr_FromLdbValue(val);
     965             : }
     966             : 
     967             : static PyMethodDef py_ldb_dn_methods[] = {
     968             :         { "validate", (PyCFunction)py_ldb_dn_validate, METH_NOARGS,
     969             :                 "S.validate() -> bool\n"
     970             :                 "Validate DN is correct." },
     971             :         { "is_valid", (PyCFunction)py_ldb_dn_is_valid, METH_NOARGS,
     972             :                 "S.is_valid() -> bool\n" },
     973             :         { "is_special", (PyCFunction)py_ldb_dn_is_special, METH_NOARGS,
     974             :                 "S.is_special() -> bool\n"
     975             :                 "Check whether this is a special LDB DN." },
     976             :         { "is_null", (PyCFunction)py_ldb_dn_is_null, METH_NOARGS,
     977             :                 "Check whether this is a null DN." },
     978             :         { "get_casefold", (PyCFunction)py_ldb_dn_get_casefold, METH_NOARGS,
     979             :                 NULL },
     980             :         { "get_linearized", PY_DISCARD_FUNC_SIG(PyCFunction,
     981             :                                                 py_ldb_dn_get_linearized),
     982             :                 METH_NOARGS,
     983             :                 NULL },
     984             :         { "canonical_str", (PyCFunction)py_ldb_dn_canonical_str, METH_NOARGS,
     985             :                 "S.canonical_str() -> string\n"
     986             :                 "Canonical version of this DN (like a posix path)." },
     987             :         { "is_child_of", (PyCFunction)py_ldb_dn_is_child_of, METH_VARARGS,
     988             :                 "S.is_child_of(basedn) -> int\nReturns True if this DN is a child of basedn\n"},
     989             :         { "canonical_ex_str", (PyCFunction)py_ldb_dn_canonical_ex_str, METH_NOARGS,
     990             :                 "S.canonical_ex_str() -> string\n"
     991             :                 "Canonical version of this DN (like a posix path, with terminating newline)." },
     992             :         { "extended_str", PY_DISCARD_FUNC_SIG(PyCFunction,
     993             :                                               py_ldb_dn_extended_str),
     994             :                 METH_VARARGS | METH_KEYWORDS,
     995             :                 "S.extended_str(mode=1) -> string\n"
     996             :                 "Extended version of this DN" },
     997             :         { "parent", (PyCFunction)py_ldb_dn_get_parent, METH_NOARGS,
     998             :                 "S.parent() -> dn\n"
     999             :                 "Get the parent for this DN." },
    1000             :         { "add_child", (PyCFunction)py_ldb_dn_add_child, METH_VARARGS,
    1001             :                 "S.add_child(dn) -> bool\n"
    1002             :                 "Add a child DN to this DN." },
    1003             :         { "add_base", (PyCFunction)py_ldb_dn_add_base, METH_VARARGS,
    1004             :                 "S.add_base(dn) -> bool\n"
    1005             :                 "Add a base DN to this DN." },
    1006             :         { "copy", (PyCFunction)py_ldb_dn_copy_method, METH_VARARGS,
    1007             :                 "dn.copy(ldb) -> dn\n"
    1008             :                 "Make a copy of this DN, attached to the given ldb object." },
    1009             :         { "remove_base_components", (PyCFunction)py_ldb_dn_remove_base_components, METH_VARARGS,
    1010             :                 "S.remove_base_components(int) -> bool\n"
    1011             :                 "Remove a number of DN components from the base of this DN." },
    1012             :         { "check_special", (PyCFunction)py_ldb_dn_check_special, METH_VARARGS,
    1013             :                 "S.check_special(name) -> bool\n\n"
    1014             :                 "Check if name is a special DN name"},
    1015             :         { "get_extended_component", (PyCFunction)py_ldb_dn_get_extended_component, METH_VARARGS,
    1016             :                 "S.get_extended_component(name) -> string\n\n"
    1017             :                 "returns a DN extended component as a binary string"},
    1018             :         { "set_extended_component", (PyCFunction)py_ldb_dn_set_extended_component, METH_VARARGS,
    1019             :                 "S.set_extended_component(name, value) -> None\n\n"
    1020             :                 "set a DN extended component as a binary string"},
    1021             :         { "get_component_name", (PyCFunction)py_ldb_dn_get_component_name, METH_VARARGS,
    1022             :                 "S.get_component_name(num) -> string\n"
    1023             :                 "get the attribute name of the specified component" },
    1024             :         { "get_component_value", (PyCFunction)py_ldb_dn_get_component_value, METH_VARARGS,
    1025             :                 "S.get_component_value(num) -> string\n"
    1026             :                 "get the attribute value of the specified component as a binary string" },
    1027             :         { "set_component", (PyCFunction)py_ldb_dn_set_component, METH_VARARGS,
    1028             :                 "S.set_component(num, name, value) -> None\n"
    1029             :                 "set the attribute name and value of the specified component" },
    1030             :         { "get_rdn_name", (PyCFunction)py_ldb_dn_get_rdn_name, METH_NOARGS,
    1031             :                 "S.get_rdn_name() -> string\n"
    1032             :                 "get the RDN attribute name" },
    1033             :         { "get_rdn_value", (PyCFunction)py_ldb_dn_get_rdn_value, METH_NOARGS,
    1034             :                 "S.get_rdn_value() -> string\n"
    1035             :                 "get the RDN attribute value as a binary string" },
    1036             :         {0}
    1037             : };
    1038             : 
    1039             : 
    1040           0 : static PyObject *py_ldb_dn_get_ldb(PyLdbDnObject *self, void *closure)
    1041             : {
    1042           0 :         if (self->pyldb == NULL) {
    1043           0 :                 Py_RETURN_NONE;
    1044             :         }
    1045           0 :         Py_INCREF(self->pyldb);
    1046           0 :         return (PyObject *)self->pyldb;
    1047             : }
    1048             : 
    1049             : 
    1050             : static PyGetSetDef py_ldb_dn_getset[] = {
    1051             :         {
    1052             :                 .name = discard_const_p(char, "ldb"),
    1053             :                 .get  = (getter)py_ldb_dn_get_ldb,
    1054             :                 .doc = discard_const_p( /* for Py 3.6; 3.7+ have const char* */
    1055             :                         char, "returns the associated ldb object (or None)")
    1056             :         },
    1057             :         { .name = NULL },
    1058             : };
    1059             : 
    1060             : 
    1061        1111 : static Py_ssize_t py_ldb_dn_len(PyLdbDnObject *self)
    1062             : {
    1063        1111 :         struct ldb_dn *dn = pyldb_Dn_AS_DN(self);
    1064        1111 :         if (dn == NULL || self->pyldb->ldb_ctx != ldb_dn_get_ldb_context(dn)) {
    1065           0 :                 return -1;
    1066             :         }
    1067             : 
    1068        1111 :         return ldb_dn_get_comp_num(dn);
    1069             : }
    1070             : 
    1071             : /*
    1072             :   copy a DN as a python object
    1073             :  */
    1074     1486399 : static PyObject *py_ldb_dn_copy(struct ldb_dn *dn, PyLdbObject *pyldb)
    1075             : {
    1076     1486399 :         TALLOC_CTX *mem_ctx = NULL;
    1077     1486399 :         struct ldb_dn *new_dn = NULL;
    1078      126107 :         PyLdbDnObject *py_ret;
    1079             : 
    1080     1486399 :         if (ldb_dn_get_ldb_context(dn) != pyldb->ldb_ctx) {
    1081             :                 /*
    1082             :                  * We can't do this, because we can't (for now) change the ldb
    1083             :                  * pointer of the underlying dn returned by ldb_dn_copy().
    1084             :                  *
    1085             :                  * This error means someone editing this file got confused,
    1086             :                  * which is quite understandable.
    1087             :                  */
    1088           0 :                 PyErr_SetString(PyExc_RuntimeError,
    1089             :                                 "py_ldb_dn_copy can't copy to a new LDB");
    1090           0 :                 return NULL;
    1091             :         }
    1092             : 
    1093     1486399 :         mem_ctx = talloc_new(NULL);
    1094     1486399 :         if (mem_ctx == NULL) {
    1095           0 :                 return PyErr_NoMemory();
    1096             :         }
    1097             : 
    1098     1486399 :         new_dn = ldb_dn_copy(mem_ctx, dn);
    1099     1486399 :         if (new_dn == NULL) {
    1100           0 :                 talloc_free(mem_ctx);
    1101           0 :                 return PyErr_NoMemory();
    1102             :         }
    1103             : 
    1104     1486399 :         py_ret = (PyLdbDnObject *)PyLdbDn.tp_alloc(&PyLdbDn, 0);
    1105     1486399 :         if (py_ret == NULL) {
    1106           0 :                 talloc_free(mem_ctx);
    1107           0 :                 PyErr_NoMemory();
    1108           0 :                 return NULL;
    1109             :         }
    1110     1486399 :         py_ret->mem_ctx = mem_ctx;
    1111     1486399 :         py_ret->dn = new_dn;
    1112             : 
    1113     1486399 :         py_ret->pyldb = pyldb;
    1114     1486399 :         Py_INCREF(py_ret->pyldb);
    1115     1486399 :         return (PyObject *)py_ret;
    1116             : }
    1117             : 
    1118          79 : static PyObject *py_ldb_dn_concat(PyObject *self, PyObject *py_other)
    1119             : {
    1120          79 :         TALLOC_CTX *mem_ctx = NULL;
    1121          79 :         struct ldb_dn *dn = NULL;
    1122          79 :         struct ldb_dn *other = NULL;
    1123             : 
    1124          79 :         struct ldb_dn *new_dn = NULL;
    1125          79 :         PyLdbDnObject *py_ret = NULL;
    1126             : 
    1127             : 
    1128          79 :         PyErr_internal_LDB_DN_OR_RAISE(self, dn);
    1129          79 :         PyErr_internal_LDB_DN_OR_RAISE(py_other, other);
    1130             : 
    1131          79 :         mem_ctx = talloc_new(NULL);
    1132          79 :         if (mem_ctx == NULL) {
    1133           0 :                 return PyErr_NoMemory();
    1134             :         }
    1135             : 
    1136          79 :         new_dn = ldb_dn_copy(mem_ctx, dn);
    1137          79 :         if (new_dn == NULL) {
    1138           0 :                 talloc_free(mem_ctx);
    1139           0 :                 return PyErr_NoMemory();
    1140             :         }
    1141             : 
    1142          79 :         if (!ldb_dn_add_base(new_dn, other)) {
    1143           0 :                 PyErr_SetString(PyExc_RuntimeError, "unable to concatenate DNs");
    1144           0 :                 talloc_free(mem_ctx);
    1145           0 :                 return NULL;
    1146             :         }
    1147             : 
    1148          79 :         py_ret = (PyLdbDnObject *)PyLdbDn.tp_alloc(&PyLdbDn, 0);
    1149          79 :         if (py_ret == NULL) {
    1150           0 :                 talloc_free(mem_ctx);
    1151           0 :                 PyErr_NoMemory();
    1152           0 :                 return NULL;
    1153             :         }
    1154          79 :         py_ret->mem_ctx = mem_ctx;
    1155          79 :         py_ret->dn = new_dn;
    1156             : 
    1157          79 :         py_ret->pyldb = ((PyLdbDnObject *)self)->pyldb;
    1158          79 :         Py_INCREF(py_ret->pyldb);
    1159             : 
    1160          79 :         return (PyObject *)py_ret;
    1161             : }
    1162             : 
    1163             : static PySequenceMethods py_ldb_dn_seq = {
    1164             :         .sq_length = (lenfunc)py_ldb_dn_len,
    1165             :         .sq_concat = (binaryfunc)py_ldb_dn_concat,
    1166             : };
    1167             : 
    1168     1422453 : static PyObject *py_ldb_dn_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
    1169             : {
    1170     1422453 :         struct ldb_dn *ret = NULL;
    1171     1422453 :         char *str = NULL;
    1172     1422453 :         PyObject *py_ldb = NULL;
    1173     1422453 :         struct ldb_context *ldb_ctx = NULL;
    1174     1422453 :         TALLOC_CTX *mem_ctx = NULL;
    1175     1422453 :         PyLdbDnObject *py_ret = NULL;
    1176     1422453 :         const char * const kwnames[] = { "ldb", "dn", NULL };
    1177             : 
    1178     1422453 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!"PYARG_STR_UNI,
    1179             :                                          discard_const_p(char *, kwnames),
    1180             :                                          &PyLdb, &py_ldb, "utf8", &str))
    1181           4 :                 goto out;
    1182             : 
    1183     1422449 :         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(py_ldb);
    1184             : 
    1185     1422449 :         mem_ctx = talloc_new(NULL);
    1186     1422449 :         if (mem_ctx == NULL) {
    1187           0 :                 PyErr_NoMemory();
    1188           0 :                 goto out;
    1189             :         }
    1190             : 
    1191     1422449 :         ret = ldb_dn_new(mem_ctx, ldb_ctx, str);
    1192     1422449 :         if (!ldb_dn_validate(ret)) {
    1193        6885 :                 talloc_free(mem_ctx);
    1194        6885 :                 PyErr_SetString(PyExc_ValueError, "unable to parse dn string");
    1195        6885 :                 goto out;
    1196             :         }
    1197             : 
    1198     1415564 :         py_ret = (PyLdbDnObject *)type->tp_alloc(type, 0);
    1199     1415564 :         if (py_ret == NULL) {
    1200           0 :                 talloc_free(mem_ctx);
    1201           0 :                 PyErr_NoMemory();
    1202           0 :                 goto out;
    1203             :         }
    1204     1415564 :         py_ret->mem_ctx = mem_ctx;
    1205     1415564 :         py_ret->dn = ret;
    1206     1415564 :         py_ret->pyldb = (PyLdbObject *)py_ldb;
    1207     1415564 :         Py_INCREF(py_ret->pyldb);
    1208     1422453 : out:
    1209     1422453 :         if (str != NULL) {
    1210     1422449 :                 PyMem_Free(discard_const_p(char, str));
    1211             :         }
    1212     1422453 :         return (PyObject *)py_ret;
    1213             : }
    1214             : 
    1215    28638929 : static void py_ldb_dn_dealloc(PyLdbDnObject *self)
    1216             : {
    1217    28638929 :         talloc_free(self->mem_ctx);
    1218    28638929 :         Py_DECREF(self->pyldb);
    1219    28638929 :         PyObject_Del(self);
    1220    28638929 : }
    1221             : 
    1222             : static PyTypeObject PyLdbDn = {
    1223             :         .tp_name = "ldb.Dn",
    1224             :         .tp_methods = py_ldb_dn_methods,
    1225             :         .tp_str = (reprfunc)py_ldb_dn_get_linearized,
    1226             :         .tp_repr = (reprfunc)py_ldb_dn_repr,
    1227             :         .tp_richcompare = (richcmpfunc)py_ldb_dn_richcmp,
    1228             :         .tp_as_sequence = &py_ldb_dn_seq,
    1229             :         .tp_getset = py_ldb_dn_getset,
    1230             :         .tp_doc = "A LDB distinguished name.",
    1231             :         .tp_new = py_ldb_dn_new,
    1232             :         .tp_dealloc = (destructor)py_ldb_dn_dealloc,
    1233             :         .tp_basicsize = sizeof(PyLdbDnObject),
    1234             :         .tp_flags = Py_TPFLAGS_DEFAULT,
    1235             : };
    1236             : 
    1237             : /* Debug */
    1238             : static void py_ldb_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3, 0);
    1239           0 : static void py_ldb_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap)
    1240             : {
    1241           0 :         PyObject *fn = (PyObject *)context;
    1242           0 :         PyObject *result = NULL;
    1243           0 :         result = PyObject_CallFunction(fn, discard_const_p(char, "(i,O)"), level, PyUnicode_FromFormatV(fmt, ap));
    1244           0 :         Py_XDECREF(result);
    1245           0 : }
    1246             : 
    1247             : static PyObject *py_ldb_debug_func;
    1248             : 
    1249           4 : static PyObject *py_ldb_set_debug(PyObject *self, PyObject *args)
    1250             : {
    1251           0 :         PyObject *cb;
    1252           0 :         struct ldb_context *ldb_ctx;
    1253             : 
    1254           4 :         if (!PyArg_ParseTuple(args, "O", &cb))
    1255           0 :                 return NULL;
    1256             : 
    1257           4 :         if (py_ldb_debug_func != NULL) {
    1258           2 :                 Py_DECREF(py_ldb_debug_func);
    1259             :         }
    1260             : 
    1261           4 :         Py_INCREF(cb);
    1262             :         /* FIXME: DECREF cb when exiting program */
    1263           4 :         py_ldb_debug_func = cb;
    1264           4 :         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    1265           4 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError,
    1266             :                 ldb_set_debug(ldb_ctx, py_ldb_debug, cb),
    1267             :                 ldb_ctx);
    1268             : 
    1269           4 :         Py_RETURN_NONE;
    1270             : }
    1271             : 
    1272       35379 : static PyObject *py_ldb_set_create_perms(PyTypeObject *self, PyObject *args)
    1273             : {
    1274         450 :         unsigned int perms;
    1275       35379 :         if (!PyArg_ParseTuple(args, "I", &perms))
    1276           0 :                 return NULL;
    1277             : 
    1278       35379 :         ldb_set_create_perms(pyldb_Ldb_AS_LDBCONTEXT(self), perms);
    1279             : 
    1280       35379 :         Py_RETURN_NONE;
    1281             : }
    1282             : 
    1283       35375 : static PyObject *py_ldb_set_modules_dir(PyTypeObject *self, PyObject *args)
    1284             : {
    1285         450 :         char *modules_dir;
    1286       35375 :         if (!PyArg_ParseTuple(args, "s", &modules_dir))
    1287           0 :                 return NULL;
    1288             : 
    1289       35375 :         ldb_set_modules_dir(pyldb_Ldb_AS_LDBCONTEXT(self), modules_dir);
    1290             : 
    1291       35375 :         Py_RETURN_NONE;
    1292             : }
    1293             : 
    1294       39138 : static PyObject *py_ldb_transaction_start(PyLdbObject *self,
    1295             :                 PyObject *Py_UNUSED(ignored))
    1296             : {
    1297       39138 :         struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    1298         285 :         int ldb_err;
    1299       39138 :         ldb_err = ldb_transaction_start(ldb_ctx);
    1300       39138 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
    1301       39138 :         Py_RETURN_NONE;
    1302             : }
    1303             : 
    1304       38825 : static PyObject *py_ldb_transaction_commit(PyLdbObject *self,
    1305             :                 PyObject *Py_UNUSED(ignored))
    1306             : {
    1307       38825 :         struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    1308         283 :         int ldb_err;
    1309       38825 :         ldb_err = ldb_transaction_commit(ldb_ctx);
    1310       38825 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
    1311       38816 :         Py_RETURN_NONE;
    1312             : }
    1313             : 
    1314         112 : static PyObject *py_ldb_transaction_prepare_commit(PyLdbObject *self,
    1315             :                 PyObject *Py_UNUSED(ignored))
    1316             : {
    1317         112 :         struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    1318           4 :         int ldb_err;
    1319         112 :         ldb_err = ldb_transaction_prepare_commit(ldb_ctx);
    1320         112 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
    1321         112 :         Py_RETURN_NONE;
    1322             : }
    1323             : 
    1324         308 : static PyObject *py_ldb_transaction_cancel(PyLdbObject *self,
    1325             :                 PyObject *Py_UNUSED(ignored))
    1326             : {
    1327         308 :         struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    1328           0 :         int ldb_err;
    1329         308 :         ldb_err = ldb_transaction_cancel(ldb_ctx);
    1330         308 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
    1331         308 :         Py_RETURN_NONE;
    1332             : }
    1333             : 
    1334           0 : static PyObject *py_ldb_setup_wellknown_attributes(PyLdbObject *self,
    1335             :                 PyObject *Py_UNUSED(ignored))
    1336             : {
    1337           0 :         struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    1338           0 :         int ldb_err;
    1339           0 :         ldb_err = ldb_setup_wellknown_attributes(ldb_ctx);
    1340           0 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ldb_err, ldb_ctx);
    1341           0 :         Py_RETURN_NONE;
    1342             : }
    1343             : 
    1344           4 : static PyObject *py_ldb_repr(PyLdbObject *self)
    1345             : {
    1346           4 :         return PyUnicode_FromString("<ldb connection>");
    1347             : }
    1348             : 
    1349     1267850 : static PyObject *py_ldb_get_root_basedn(PyLdbObject *self,
    1350             :                 PyObject *Py_UNUSED(ignored))
    1351             : {
    1352     1267850 :         struct ldb_dn *dn = ldb_get_root_basedn(pyldb_Ldb_AS_LDBCONTEXT(self));
    1353     1267850 :         if (dn == NULL)
    1354           4 :                 Py_RETURN_NONE;
    1355     1267846 :         return py_ldb_dn_copy(dn, self);
    1356             : }
    1357             : 
    1358             : 
    1359       21644 : static PyObject *py_ldb_get_schema_basedn(PyLdbObject *self,
    1360             :                 PyObject *Py_UNUSED(ignored))
    1361             : {
    1362       21644 :         struct ldb_dn *dn = ldb_get_schema_basedn(pyldb_Ldb_AS_LDBCONTEXT(self));
    1363       21644 :         if (dn == NULL)
    1364           4 :                 Py_RETURN_NONE;
    1365       21640 :         return py_ldb_dn_copy(dn, self);
    1366             : }
    1367             : 
    1368       51137 : static PyObject *py_ldb_get_config_basedn(PyLdbObject *self,
    1369             :                 PyObject *Py_UNUSED(ignored))
    1370             : {
    1371       51137 :         struct ldb_dn *dn = ldb_get_config_basedn(pyldb_Ldb_AS_LDBCONTEXT(self));
    1372       51137 :         if (dn == NULL)
    1373           4 :                 Py_RETURN_NONE;
    1374       51133 :         return py_ldb_dn_copy(dn, self);
    1375             : }
    1376             : 
    1377      132256 : static PyObject *py_ldb_get_default_basedn(PyLdbObject *self,
    1378             :                 PyObject *Py_UNUSED(ignored))
    1379             : {
    1380      132256 :         struct ldb_dn *dn = ldb_get_default_basedn(pyldb_Ldb_AS_LDBCONTEXT(self));
    1381      132256 :         if (dn == NULL)
    1382           6 :                 Py_RETURN_NONE;
    1383      132250 :         return py_ldb_dn_copy(dn, self);
    1384             : }
    1385             : 
    1386     5777019 : static const char **PyList_AsStrList(TALLOC_CTX *mem_ctx, PyObject *list,
    1387             :                     const char *paramname)
    1388             : {
    1389      546528 :         const char **ret;
    1390      546528 :         Py_ssize_t i;
    1391     5777019 :         if (!PyList_Check(list)) {
    1392          22 :                 PyErr_Format(PyExc_TypeError, "%s is not a list", paramname);
    1393          22 :                 return NULL;
    1394             :         }
    1395     5776997 :         ret = talloc_array(NULL, const char *, PyList_Size(list)+1);
    1396     5776997 :         if (ret == NULL) {
    1397           0 :                 PyErr_NoMemory();
    1398           0 :                 return NULL;
    1399             :         }
    1400             : 
    1401    23622475 :         for (i = 0; i < PyList_Size(list); i++) {
    1402    17845478 :                 const char *str = NULL;
    1403     1679993 :                 Py_ssize_t size;
    1404    17845478 :                 PyObject *item = PyList_GetItem(list, i);
    1405    17845478 :                 if (!PyUnicode_Check(item)) {
    1406           0 :                         PyErr_Format(PyExc_TypeError, "%s should be strings", paramname);
    1407           0 :                         talloc_free(ret);
    1408           0 :                         return NULL;
    1409             :                 }
    1410    17845478 :                 str = PyUnicode_AsUTF8AndSize(item, &size);
    1411    17845478 :                 if (str == NULL) {
    1412           0 :                         talloc_free(ret);
    1413           0 :                         return NULL;
    1414             :                 }
    1415    17845478 :                 ret[i] = talloc_strndup(ret, str, size);
    1416             :         }
    1417     5776997 :         ret[i] = NULL;
    1418     5776997 :         return ret;
    1419             : }
    1420             : 
    1421             : static PyObject *py_ldb_connect(PyLdbObject *self, PyObject *args, PyObject *kwargs);
    1422             : 
    1423        3754 : static int py_ldb_init(PyLdbObject *self, PyObject *args, PyObject *kwargs)
    1424             : {
    1425        3754 :         const char * const kwnames[] = { "url", "flags", "options", NULL };
    1426        3754 :         char *url = NULL;
    1427        3754 :         PyObject *py_options = NULL;
    1428        3754 :         unsigned int flags = 0;
    1429             : 
    1430        3754 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|zIO:Ldb.__init__",
    1431             :                                          discard_const_p(char *, kwnames),
    1432             :                                          &url, &flags, &py_options)) {
    1433           0 :                 return -1;
    1434             :         }
    1435             : 
    1436        3754 :         if (url != NULL) {
    1437             :                 /* py_ldb_connect returns py_None on success, NULL on error */
    1438        3600 :                 PyObject *result = py_ldb_connect(self, args, kwargs);
    1439        3600 :                 if (result == NULL) {
    1440           0 :                         return -1;
    1441             :                 }
    1442        3598 :                 Py_DECREF(result);
    1443             :         } else {
    1444         154 :                 struct ldb_context *ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
    1445         154 :                 ldb_set_flags(ldb, flags);
    1446             :         }
    1447             : 
    1448        3665 :         return 0;
    1449             : }
    1450             : 
    1451       39129 : static PyObject *py_ldb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
    1452             : {
    1453       39129 :         TALLOC_CTX *mem_ctx = NULL;
    1454         539 :         PyLdbObject *ret;
    1455         539 :         struct ldb_context *ldb;
    1456             : 
    1457       39129 :         mem_ctx = talloc_new(NULL);
    1458       39129 :         if (mem_ctx == NULL) {
    1459           0 :                 return PyErr_NoMemory();
    1460             :         }
    1461             : 
    1462       39129 :         ldb = ldb_init(mem_ctx, NULL);
    1463       39129 :         if (ldb == NULL) {
    1464           0 :                 talloc_free(mem_ctx);
    1465           0 :                 PyErr_NoMemory();
    1466           0 :                 return NULL;
    1467             :         }
    1468             : 
    1469       39129 :         ret = (PyLdbObject *)type->tp_alloc(type, 0);
    1470       39129 :         if (ret == NULL) {
    1471           0 :                 talloc_free(mem_ctx);
    1472           0 :                 PyErr_NoMemory();
    1473           0 :                 return NULL;
    1474             :         }
    1475       39129 :         ret->mem_ctx = mem_ctx;
    1476             : 
    1477       39129 :         ret->ldb_ctx = ldb;
    1478       39129 :         return (PyObject *)ret;
    1479             : }
    1480             : 
    1481       38513 : static PyObject *py_ldb_connect(PyLdbObject *self, PyObject *args, PyObject *kwargs)
    1482             : {
    1483       38513 :         char *url = NULL;
    1484       38513 :         unsigned int flags = 0;
    1485       38513 :         PyObject *py_options = Py_None;
    1486         515 :         int ret;
    1487         515 :         const char **options;
    1488       38513 :         const char * const kwnames[] = { "url", "flags", "options", NULL };
    1489         515 :         struct ldb_context *ldb_ctx;
    1490             : 
    1491       38513 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|IO",
    1492             :                                          discard_const_p(char *, kwnames),
    1493             :                                          &url, &flags, &py_options))
    1494           0 :                 return NULL;
    1495             : 
    1496       38513 :         if (py_options == Py_None) {
    1497       32404 :                 options = NULL;
    1498             :         } else {
    1499        5751 :                 options = PyList_AsStrList(NULL, py_options, "options");
    1500        5751 :                 if (options == NULL)
    1501           0 :                         return NULL;
    1502             :         }
    1503             : 
    1504       38513 :         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    1505       38513 :         ret = ldb_connect(ldb_ctx, url, flags, options);
    1506       38513 :         talloc_free(options);
    1507             : 
    1508       38513 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
    1509             : 
    1510       37903 :         Py_RETURN_NONE;
    1511             : }
    1512             : 
    1513      253010 : static PyObject *py_ldb_modify(PyLdbObject *self, PyObject *args, PyObject *kwargs)
    1514             : {
    1515       15600 :         PyObject *py_msg;
    1516      253010 :         PyObject *py_controls = Py_None;
    1517       15600 :         struct ldb_context *ldb_ctx;
    1518       15600 :         struct ldb_request *req;
    1519       15600 :         struct ldb_control **parsed_controls;
    1520       15600 :         struct ldb_message *msg;
    1521       15600 :         int ret;
    1522       15600 :         TALLOC_CTX *mem_ctx;
    1523      253010 :         bool validate=true;
    1524      253010 :         const char * const kwnames[] = { "message", "controls", "validate", NULL };
    1525             : 
    1526      253010 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Ob",
    1527             :                                          discard_const_p(char *, kwnames),
    1528             :                                          &py_msg, &py_controls, &validate))
    1529           0 :                 return NULL;
    1530             : 
    1531      253010 :         mem_ctx = talloc_new(NULL);
    1532      253010 :         if (mem_ctx == NULL) {
    1533           0 :                 PyErr_NoMemory();
    1534           0 :                 return NULL;
    1535             :         }
    1536      253010 :         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    1537             : 
    1538      253010 :         if (py_controls == Py_None) {
    1539       73127 :                 parsed_controls = NULL;
    1540             :         } else {
    1541      179421 :                 const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
    1542      179421 :                 if (controls == NULL) {
    1543           2 :                         talloc_free(mem_ctx);
    1544           2 :                         return NULL;
    1545             :                 }
    1546      179419 :                 parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls);
    1547      179419 :                 if (controls[0] != NULL && parsed_controls == NULL) {
    1548           0 :                         talloc_free(mem_ctx);
    1549           0 :                         PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, ldb_ctx);
    1550           0 :                         return NULL;
    1551             :                 }
    1552      179419 :                 talloc_free(controls);
    1553             :         }
    1554             : 
    1555      253008 :         if (!pyldb_Message_Check(py_msg)) {
    1556           2 :                 PyErr_SetString(PyExc_TypeError, "Expected Ldb Message");
    1557           2 :                 talloc_free(mem_ctx);
    1558           2 :                 return NULL;
    1559             :         }
    1560      253006 :         msg = pyldb_Message_AsMessage(py_msg);
    1561             : 
    1562      253006 :         if (validate) {
    1563      252943 :                 ret = ldb_msg_sanity_check(ldb_ctx, msg);
    1564      252943 :                 if (ret != LDB_SUCCESS) {
    1565           1 :                         PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
    1566           1 :                         talloc_free(mem_ctx);
    1567           1 :                         return NULL;
    1568             :                 }
    1569             :         }
    1570             : 
    1571      253005 :         ret = ldb_build_mod_req(&req, ldb_ctx, mem_ctx, msg, parsed_controls,
    1572             :                                 NULL, ldb_op_default_callback, NULL);
    1573      253005 :         if (ret != LDB_SUCCESS) {
    1574           0 :                 PyErr_SetString(PyExc_TypeError, "failed to build request");
    1575           0 :                 talloc_free(mem_ctx);
    1576           0 :                 return NULL;
    1577             :         }
    1578             : 
    1579             :         /* do request and autostart a transaction */
    1580             :         /* Then let's LDB handle the message error in case of pb as they are meaningful */
    1581             : 
    1582      253005 :         ret = ldb_transaction_start(ldb_ctx);
    1583      253005 :         if (ret != LDB_SUCCESS) {
    1584           0 :                 talloc_free(mem_ctx);
    1585           0 :                 PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
    1586           0 :                 return NULL;
    1587             :         }
    1588             : 
    1589      253005 :         ret = ldb_request(ldb_ctx, req);
    1590      253005 :         if (ret == LDB_SUCCESS) {
    1591      252943 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    1592             :         }
    1593             : 
    1594      253005 :         if (ret == LDB_SUCCESS) {
    1595      248343 :                 ret = ldb_transaction_commit(ldb_ctx);
    1596             :         } else {
    1597        4662 :                 ldb_transaction_cancel(ldb_ctx);
    1598             :         }
    1599             : 
    1600      253005 :         talloc_free(mem_ctx);
    1601      253005 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
    1602             : 
    1603      248343 :         Py_RETURN_NONE;
    1604             : }
    1605             : 
    1606             : 
    1607             : /**
    1608             :  * Obtain a ldb message from a Python Dictionary object.
    1609             :  *
    1610             :  * @param mem_ctx Memory context
    1611             :  * @param py_obj Python Dictionary object
    1612             :  * @param ldb_ctx LDB context
    1613             :  * @param mod_flags Flags to be set on every message element
    1614             :  * @return ldb_message on success or NULL on failure
    1615             :  */
    1616      182386 : static struct ldb_message *PyDict_AsMessage(TALLOC_CTX *mem_ctx,
    1617             :                                             PyObject *py_obj,
    1618             :                                             struct ldb_context *ldb_ctx,
    1619             :                                             unsigned int mod_flags)
    1620             : {
    1621        1025 :         struct ldb_message *msg;
    1622      182386 :         unsigned int msg_pos = 0;
    1623      182386 :         Py_ssize_t dict_pos = 0;
    1624        1025 :         PyObject *key, *value;
    1625        1025 :         struct ldb_message_element *msg_el;
    1626      182386 :         PyObject *dn_value = PyDict_GetItemString(py_obj, "dn");
    1627             : 
    1628      182386 :         msg = ldb_msg_new(mem_ctx);
    1629      182386 :         if (msg == NULL) {
    1630           0 :                 PyErr_NoMemory();
    1631           0 :                 return NULL;
    1632             :         }
    1633      182386 :         msg->elements = talloc_zero_array(msg, struct ldb_message_element, PyDict_Size(py_obj));
    1634      182386 :         if (msg->elements == NULL) {
    1635           0 :                 PyErr_NoMemory();
    1636           0 :                 TALLOC_FREE(msg);
    1637           0 :                 return NULL;
    1638             :         }
    1639             : 
    1640      182386 :         if (dn_value) {
    1641      182382 :                 struct ldb_dn *dn = NULL;
    1642      182382 :                 if (!pyldb_Object_AsDn(msg, dn_value, ldb_ctx, &dn)) {
    1643           0 :                         PyErr_SetString(PyExc_TypeError, "unable to import dn object");
    1644           0 :                         TALLOC_FREE(msg);
    1645           0 :                         return NULL;
    1646             :                 }
    1647      182382 :                 if (dn == NULL) {
    1648           0 :                         PyErr_SetString(PyExc_TypeError, "dn set but not found");
    1649           0 :                         TALLOC_FREE(msg);
    1650           0 :                         return NULL;
    1651             :                 }
    1652      182382 :                 msg->dn = talloc_reference(msg, dn);
    1653      182382 :                 if (msg->dn == NULL) {
    1654           0 :                         talloc_free(mem_ctx);
    1655           0 :                         PyErr_NoMemory();
    1656           0 :                         return NULL;
    1657             :                 }
    1658             :         } else {
    1659           4 :                 PyErr_SetString(PyExc_TypeError, "no dn set");
    1660           4 :                 TALLOC_FREE(msg);
    1661           4 :                 return NULL;
    1662             :         }
    1663             : 
    1664      967205 :         while (PyDict_Next(py_obj, &dict_pos, &key, &value)) {
    1665      768344 :                 const char *key_str = PyUnicode_AsUTF8(key);
    1666      768344 :                 if (ldb_attr_cmp(key_str, "dn") != 0) {
    1667      585962 :                         msg_el = PyObject_AsMessageElement(msg->elements, value,
    1668             :                                                            mod_flags, key_str);
    1669      585962 :                         if (msg_el == NULL) {
    1670           0 :                                 PyErr_Format(PyExc_TypeError, "unable to import element '%s'", key_str);
    1671           0 :                                 TALLOC_FREE(msg);
    1672           0 :                                 return NULL;
    1673             :                         }
    1674      585962 :                         memcpy(&msg->elements[msg_pos], msg_el, sizeof(*msg_el));
    1675             : 
    1676             :                         /*
    1677             :                          * PyObject_AsMessageElement might have returned a
    1678             :                          * reference to an existing MessageElement, and so left
    1679             :                          * the name and flags unchanged. Thus if those members
    1680             :                          * aren’t set, we’ll assume that the user forgot to
    1681             :                          * initialize them.
    1682             :                          */
    1683      585962 :                         if (msg->elements[msg_pos].name == NULL) {
    1684             :                                 /* No name was set — set it now. */
    1685           0 :                                 msg->elements[msg_pos].name = talloc_strdup(msg->elements, key_str);
    1686           0 :                                 if (msg->elements[msg_pos].name == NULL) {
    1687           0 :                                         PyErr_NoMemory();
    1688           0 :                                         TALLOC_FREE(msg);
    1689           0 :                                         return NULL;
    1690             :                                 }
    1691             :                         }
    1692      585962 :                         if (msg->elements[msg_pos].flags == 0) {
    1693             :                                 /* No flags were set — set them now. */
    1694           0 :                                 msg->elements[msg_pos].flags = mod_flags;
    1695             :                         }
    1696             : 
    1697      585962 :                         msg_pos++;
    1698             :                 }
    1699             :         }
    1700             : 
    1701      182382 :         msg->num_elements = msg_pos;
    1702             : 
    1703      182382 :         return msg;
    1704             : }
    1705             : 
    1706      667375 : static PyObject *py_ldb_add(PyLdbObject *self, PyObject *args, PyObject *kwargs)
    1707             : {
    1708       86701 :         PyObject *py_obj;
    1709       86701 :         int ret;
    1710       86701 :         struct ldb_context *ldb_ctx;
    1711       86701 :         struct ldb_request *req;
    1712      667375 :         struct ldb_message *msg = NULL;
    1713      667375 :         PyObject *py_controls = Py_None;
    1714       86701 :         TALLOC_CTX *mem_ctx;
    1715       86701 :         struct ldb_control **parsed_controls;
    1716      667375 :         const char * const kwnames[] = { "message", "controls", NULL };
    1717             : 
    1718      667375 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O",
    1719             :                                          discard_const_p(char *, kwnames),
    1720             :                                          &py_obj, &py_controls))
    1721           2 :                 return NULL;
    1722             : 
    1723      667373 :         mem_ctx = talloc_new(NULL);
    1724      667373 :         if (mem_ctx == NULL) {
    1725           0 :                 PyErr_NoMemory();
    1726           0 :                 return NULL;
    1727             :         }
    1728      667373 :         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    1729             : 
    1730      667373 :         if (py_controls == Py_None) {
    1731      356278 :                 parsed_controls = NULL;
    1732             :         } else {
    1733      273126 :                 const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
    1734      273126 :                 if (controls == NULL) {
    1735           8 :                         talloc_free(mem_ctx);
    1736           8 :                         return NULL;
    1737             :                 }
    1738      273118 :                 parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls);
    1739      273118 :                 if (controls[0] != NULL && parsed_controls == NULL) {
    1740           0 :                         talloc_free(mem_ctx);
    1741           0 :                         PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, ldb_ctx);
    1742           0 :                         return NULL;
    1743             :                 }
    1744      273118 :                 talloc_free(controls);
    1745             :         }
    1746             : 
    1747      667365 :         if (pyldb_Message_Check(py_obj)) {
    1748      487464 :                 msg = pyldb_Message_AsMessage(py_obj);
    1749      179901 :         } else if (PyDict_Check(py_obj)) {
    1750      179897 :                 msg = PyDict_AsMessage(mem_ctx, py_obj, ldb_ctx, LDB_FLAG_MOD_ADD);
    1751             :         } else {
    1752           4 :                 PyErr_SetString(PyExc_TypeError,
    1753             :                                 "Dictionary or LdbMessage object expected!");
    1754             :         }
    1755             : 
    1756      667365 :         if (!msg) {
    1757             :                 /* we should have a PyErr already set */
    1758           4 :                 talloc_free(mem_ctx);
    1759           4 :                 return NULL;
    1760             :         }
    1761             : 
    1762      667361 :         ret = ldb_msg_sanity_check(ldb_ctx, msg);
    1763      667361 :         if (ret != LDB_SUCCESS) {
    1764           1 :                 PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
    1765           1 :                 talloc_free(mem_ctx);
    1766           1 :                 return NULL;
    1767             :         }
    1768             : 
    1769      667360 :         ret = ldb_build_add_req(&req, ldb_ctx, mem_ctx, msg, parsed_controls,
    1770             :                                 NULL, ldb_op_default_callback, NULL);
    1771      667360 :         if (ret != LDB_SUCCESS) {
    1772           0 :                 PyErr_SetString(PyExc_TypeError, "failed to build request");
    1773           0 :                 talloc_free(mem_ctx);
    1774           0 :                 return NULL;
    1775             :         }
    1776             : 
    1777             :         /* do request and autostart a transaction */
    1778             :         /* Then let's LDB handle the message error in case of pb as they are meaningful */
    1779             : 
    1780      667360 :         ret = ldb_transaction_start(ldb_ctx);
    1781      667360 :         if (ret != LDB_SUCCESS) {
    1782           0 :                 talloc_free(mem_ctx);
    1783           0 :                 PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
    1784           0 :                 return NULL;
    1785             :         }
    1786             : 
    1787      667360 :         ret = ldb_request(ldb_ctx, req);
    1788      667360 :         if (ret == LDB_SUCCESS) {
    1789      667338 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    1790             :         }
    1791             : 
    1792      667360 :         if (ret == LDB_SUCCESS) {
    1793      666202 :                 ret = ldb_transaction_commit(ldb_ctx);
    1794             :         } else {
    1795        1158 :                 ldb_transaction_cancel(ldb_ctx);
    1796             :         }
    1797             : 
    1798      667360 :         talloc_free(mem_ctx);
    1799      667360 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
    1800             : 
    1801      666202 :         Py_RETURN_NONE;
    1802             : }
    1803             : 
    1804       79505 : static PyObject *py_ldb_delete(PyLdbObject *self, PyObject *args, PyObject *kwargs)
    1805             : {
    1806         583 :         PyObject *py_dn;
    1807         583 :         struct ldb_dn *dn;
    1808         583 :         int ret;
    1809         583 :         struct ldb_context *ldb_ctx;
    1810         583 :         struct ldb_request *req;
    1811       79505 :         PyObject *py_controls = Py_None;
    1812         583 :         TALLOC_CTX *mem_ctx;
    1813         583 :         struct ldb_control **parsed_controls;
    1814       79505 :         const char * const kwnames[] = { "dn", "controls", NULL };
    1815             : 
    1816       79505 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O",
    1817             :                                          discard_const_p(char *, kwnames),
    1818             :                                          &py_dn, &py_controls))
    1819           0 :                 return NULL;
    1820             : 
    1821       79505 :         mem_ctx = talloc_new(NULL);
    1822       79505 :         if (mem_ctx == NULL) {
    1823           0 :                 PyErr_NoMemory();
    1824           0 :                 return NULL;
    1825             :         }
    1826       79505 :         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    1827             : 
    1828       79505 :         if (py_controls == Py_None) {
    1829       71784 :                 parsed_controls = NULL;
    1830             :         } else {
    1831        7660 :                 const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
    1832        7660 :                 if (controls == NULL) {
    1833           0 :                         talloc_free(mem_ctx);
    1834           0 :                         return NULL;
    1835             :                 }
    1836        7660 :                 parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls);
    1837        7660 :                 if (controls[0] != NULL && parsed_controls == NULL) {
    1838           0 :                         talloc_free(mem_ctx);
    1839           0 :                         PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, ldb_ctx);
    1840           0 :                         return NULL;
    1841             :                 }
    1842        7660 :                 talloc_free(controls);
    1843             :         }
    1844             : 
    1845       79505 :         if (!pyldb_Object_AsDn(mem_ctx, py_dn, ldb_ctx, &dn)) {
    1846           0 :                 talloc_free(mem_ctx);
    1847           0 :                 return NULL;
    1848             :         }
    1849             : 
    1850       79505 :         ret = ldb_build_del_req(&req, ldb_ctx, mem_ctx, dn, parsed_controls,
    1851             :                                 NULL, ldb_op_default_callback, NULL);
    1852       79505 :         if (ret != LDB_SUCCESS) {
    1853           0 :                 PyErr_SetString(PyExc_TypeError, "failed to build request");
    1854           0 :                 talloc_free(mem_ctx);
    1855           0 :                 return NULL;
    1856             :         }
    1857             : 
    1858             :         /* do request and autostart a transaction */
    1859             :         /* Then let's LDB handle the message error in case of pb as they are meaningful */
    1860             : 
    1861       79505 :         ret = ldb_transaction_start(ldb_ctx);
    1862       79505 :         if (ret != LDB_SUCCESS) {
    1863           0 :                 talloc_free(mem_ctx);
    1864           0 :                 PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
    1865           0 :                 return NULL;
    1866             :         }
    1867             : 
    1868       79505 :         ret = ldb_request(ldb_ctx, req);
    1869       79505 :         if (ret == LDB_SUCCESS) {
    1870       79501 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    1871             :         }
    1872             : 
    1873       79505 :         if (ret == LDB_SUCCESS) {
    1874       37198 :                 ret = ldb_transaction_commit(ldb_ctx);
    1875             :         } else {
    1876       42307 :                 ldb_transaction_cancel(ldb_ctx);
    1877             :         }
    1878             : 
    1879       79505 :         talloc_free(mem_ctx);
    1880       79505 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
    1881             : 
    1882       37198 :         Py_RETURN_NONE;
    1883             : }
    1884             : 
    1885        1483 : static PyObject *py_ldb_rename(PyLdbObject *self, PyObject *args, PyObject *kwargs)
    1886             : {
    1887          18 :         PyObject *py_dn1, *py_dn2;
    1888          18 :         struct ldb_dn *dn1, *dn2;
    1889          18 :         int ret;
    1890          18 :         TALLOC_CTX *mem_ctx;
    1891        1483 :         PyObject *py_controls = Py_None;
    1892          18 :         struct ldb_control **parsed_controls;
    1893          18 :         struct ldb_context *ldb_ctx;
    1894          18 :         struct ldb_request *req;
    1895        1483 :         const char * const kwnames[] = { "dn1", "dn2", "controls", NULL };
    1896             : 
    1897        1483 :         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    1898             : 
    1899        1483 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|O",
    1900             :                                          discard_const_p(char *, kwnames),
    1901             :                                          &py_dn1, &py_dn2, &py_controls))
    1902           0 :                 return NULL;
    1903             : 
    1904             : 
    1905        1483 :         mem_ctx = talloc_new(NULL);
    1906        1483 :         if (mem_ctx == NULL) {
    1907           0 :                 PyErr_NoMemory();
    1908           0 :                 return NULL;
    1909             :         }
    1910             : 
    1911        1483 :         if (py_controls == Py_None) {
    1912        1441 :                 parsed_controls = NULL;
    1913             :         } else {
    1914          24 :                 const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
    1915          24 :                 if (controls == NULL) {
    1916           0 :                         talloc_free(mem_ctx);
    1917           0 :                         return NULL;
    1918             :                 }
    1919          24 :                 parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls);
    1920          24 :                 if (controls[0] != NULL && parsed_controls == NULL) {
    1921           0 :                         talloc_free(mem_ctx);
    1922           0 :                         PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, ldb_ctx);
    1923           0 :                         return NULL;
    1924             :                 }
    1925          24 :                 talloc_free(controls);
    1926             :         }
    1927             : 
    1928             : 
    1929        1483 :         if (!pyldb_Object_AsDn(mem_ctx, py_dn1, ldb_ctx, &dn1)) {
    1930           0 :                 talloc_free(mem_ctx);
    1931           0 :                 return NULL;
    1932             :         }
    1933             : 
    1934        1483 :         if (!pyldb_Object_AsDn(mem_ctx, py_dn2, ldb_ctx, &dn2)) {
    1935           0 :                 talloc_free(mem_ctx);
    1936           0 :                 return NULL;
    1937             :         }
    1938             : 
    1939        1483 :         ret = ldb_build_rename_req(&req, ldb_ctx, mem_ctx, dn1, dn2, parsed_controls,
    1940             :                                 NULL, ldb_op_default_callback, NULL);
    1941        1483 :         if (ret != LDB_SUCCESS) {
    1942           0 :                 PyErr_SetString(PyExc_TypeError, "failed to build request");
    1943           0 :                 talloc_free(mem_ctx);
    1944           0 :                 return NULL;
    1945             :         }
    1946             : 
    1947             :         /* do request and autostart a transaction */
    1948             :         /* Then let's LDB handle the message error in case of pb as they are meaningful */
    1949             : 
    1950        1483 :         ret = ldb_transaction_start(ldb_ctx);
    1951        1483 :         if (ret != LDB_SUCCESS) {
    1952           0 :                 talloc_free(mem_ctx);
    1953           0 :                 PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
    1954           0 :                 return NULL;
    1955             :         }
    1956             : 
    1957        1483 :         ret = ldb_request(ldb_ctx, req);
    1958        1483 :         if (ret == LDB_SUCCESS) {
    1959        1440 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    1960             :         }
    1961             : 
    1962        1483 :         if (ret == LDB_SUCCESS) {
    1963        1321 :                 ret = ldb_transaction_commit(ldb_ctx);
    1964             :         } else {
    1965         162 :                 ldb_transaction_cancel(ldb_ctx);
    1966             :         }
    1967             : 
    1968        1483 :         talloc_free(mem_ctx);
    1969        1483 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
    1970             : 
    1971        1321 :         Py_RETURN_NONE;
    1972             : }
    1973             : 
    1974           0 : static PyObject *py_ldb_schema_attribute_remove(PyLdbObject *self, PyObject *args)
    1975             : {
    1976           0 :         char *name;
    1977           0 :         if (!PyArg_ParseTuple(args, "s", &name))
    1978           0 :                 return NULL;
    1979             : 
    1980           0 :         ldb_schema_attribute_remove(pyldb_Ldb_AS_LDBCONTEXT(self), name);
    1981             : 
    1982           0 :         Py_RETURN_NONE;
    1983             : }
    1984             : 
    1985       20140 : static PyObject *py_ldb_schema_attribute_add(PyLdbObject *self, PyObject *args)
    1986             : {
    1987         494 :         char *attribute, *syntax;
    1988         494 :         unsigned int flags;
    1989         494 :         int ret;
    1990         494 :         struct ldb_context *ldb_ctx;
    1991             : 
    1992       20140 :         if (!PyArg_ParseTuple(args, "sIs", &attribute, &flags, &syntax))
    1993           0 :                 return NULL;
    1994             : 
    1995       20140 :         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    1996       20140 :         ret = ldb_schema_attribute_add(ldb_ctx, attribute, flags, syntax);
    1997             : 
    1998       20140 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb_ctx);
    1999             : 
    2000       20140 :         Py_RETURN_NONE;
    2001             : }
    2002             : 
    2003      524791 : static PyObject *ldb_ldif_to_pyobject(PyLdbObject *pyldb, struct ldb_ldif *ldif)
    2004             : {
    2005      524791 :         PyObject *obj = NULL;
    2006      524791 :         PyObject *result = NULL;
    2007      524791 :         struct ldb_context *ldb = pyldb->ldb_ctx;
    2008             : 
    2009      524791 :         if (ldif == NULL) {
    2010           0 :                 Py_RETURN_NONE;
    2011             :         }
    2012             : 
    2013      524791 :         switch (ldif->changetype) {
    2014      476192 :         case LDB_CHANGETYPE_NONE:
    2015             :         case LDB_CHANGETYPE_ADD:
    2016      476192 :                 obj = PyLdbMessage_FromMessage(ldif->msg, pyldb);
    2017      476192 :                 break;
    2018       48595 :         case LDB_CHANGETYPE_MODIFY:
    2019       48595 :                 obj = PyLdbMessage_FromMessage(ldif->msg, pyldb);
    2020       48595 :                 break;
    2021           2 :         case LDB_CHANGETYPE_DELETE:
    2022           2 :                 if (ldif->msg->num_elements != 0) {
    2023           0 :                         PyErr_Format(PyExc_ValueError,
    2024             :                                      "CHANGETYPE(DELETE) with num_elements=%u",
    2025           0 :                                      ldif->msg->num_elements);
    2026           0 :                         return NULL;
    2027             :                 }
    2028           2 :                 obj = pyldb_Dn_FromDn(ldif->msg->dn, pyldb);
    2029           2 :                 break;
    2030           2 :         case LDB_CHANGETYPE_MODRDN: {
    2031           2 :                 struct ldb_dn *olddn = NULL;
    2032           2 :                 PyObject *olddn_obj = NULL;
    2033           2 :                 bool deleteoldrdn = false;
    2034           2 :                 PyObject *deleteoldrdn_obj = NULL;
    2035           2 :                 struct ldb_dn *newdn = NULL;
    2036           2 :                 PyObject *newdn_obj = NULL;
    2037           0 :                 int ret;
    2038             : 
    2039           2 :                 ret = ldb_ldif_parse_modrdn(ldb,
    2040             :                                             ldif,
    2041             :                                             ldif,
    2042             :                                             &olddn,
    2043             :                                             NULL,
    2044             :                                             &deleteoldrdn,
    2045             :                                             NULL,
    2046             :                                             &newdn);
    2047           2 :                 if (ret != LDB_SUCCESS) {
    2048           0 :                         PyErr_Format(PyExc_ValueError,
    2049             :                                      "ldb_ldif_parse_modrdn() failed");
    2050           0 :                         return NULL;
    2051             :                 }
    2052             : 
    2053           2 :                 olddn_obj = pyldb_Dn_FromDn(olddn, pyldb);
    2054           2 :                 if (olddn_obj == NULL) {
    2055           0 :                         return NULL;
    2056             :                 }
    2057           2 :                 if (deleteoldrdn) {
    2058           2 :                         deleteoldrdn_obj = Py_True;
    2059             :                 } else {
    2060           0 :                         deleteoldrdn_obj = Py_False;
    2061             :                 }
    2062           2 :                 newdn_obj = pyldb_Dn_FromDn(newdn, pyldb);
    2063           2 :                 if (newdn_obj == NULL) {
    2064           0 :                         deleteoldrdn_obj = NULL;
    2065           0 :                         Py_CLEAR(olddn_obj);
    2066           0 :                         return NULL;
    2067             :                 }
    2068             : 
    2069           2 :                 obj = Py_BuildValue(discard_const_p(char, "{s:O,s:O,s:O}"),
    2070             :                                     "olddn", olddn_obj,
    2071             :                                     "deleteoldrdn", deleteoldrdn_obj,
    2072             :                                     "newdn", newdn_obj);
    2073           2 :                 Py_CLEAR(olddn_obj);
    2074           2 :                 deleteoldrdn_obj = NULL;
    2075           2 :                 Py_CLEAR(newdn_obj);
    2076             :                 }
    2077           2 :                 break;
    2078           0 :         default:
    2079           0 :                 PyErr_Format(PyExc_NotImplementedError,
    2080             :                              "Unsupported LDB_CHANGETYPE(%u)",
    2081           0 :                              ldif->changetype);
    2082           0 :                 return NULL;
    2083             :         }
    2084             : 
    2085      524791 :         if (obj == NULL) {
    2086           0 :                 return NULL;
    2087             :         }
    2088             : 
    2089             :         /* We don't want this being attached * to the 'ldb' any more */
    2090      611504 :         result = Py_BuildValue(discard_const_p(char, "(iO)"),
    2091      524791 :                                ldif->changetype,
    2092             :                                obj);
    2093      524791 :         Py_CLEAR(obj);
    2094      438078 :         return result;
    2095             : }
    2096             : 
    2097             : 
    2098       14662 : static PyObject *py_ldb_write_ldif(PyLdbObject *self, PyObject *args)
    2099             : {
    2100          81 :         int changetype;
    2101          81 :         PyObject *py_msg;
    2102          81 :         struct ldb_ldif ldif;
    2103          81 :         PyObject *ret;
    2104          81 :         char *string;
    2105          81 :         TALLOC_CTX *mem_ctx;
    2106             : 
    2107       14662 :         if (!PyArg_ParseTuple(args, "Oi", &py_msg, &changetype))
    2108           0 :                 return NULL;
    2109             : 
    2110       14662 :         if (!pyldb_Message_Check(py_msg)) {
    2111           0 :                 PyErr_SetString(PyExc_TypeError, "Expected Ldb Message for msg");
    2112           0 :                 return NULL;
    2113             :         }
    2114             : 
    2115       14662 :         ldif.msg = pyldb_Message_AsMessage(py_msg);
    2116       14662 :         ldif.changetype = changetype;
    2117             : 
    2118       14662 :         mem_ctx = talloc_new(NULL);
    2119       14662 :         if (mem_ctx == NULL) {
    2120           0 :                 return PyErr_NoMemory();
    2121             :         }
    2122             : 
    2123       14662 :         string = ldb_ldif_write_string(pyldb_Ldb_AS_LDBCONTEXT(self), mem_ctx, &ldif);
    2124       14662 :         if (!string) {
    2125           0 :                 PyErr_SetString(PyExc_KeyError, "Failed to generate LDIF");
    2126           0 :                 talloc_free(mem_ctx);
    2127           0 :                 return NULL;
    2128             :         }
    2129             : 
    2130       14662 :         ret = PyUnicode_FromString(string);
    2131             : 
    2132       14662 :         talloc_free(mem_ctx);
    2133             : 
    2134       14662 :         return ret;
    2135             : }
    2136             : 
    2137       61753 : static PyObject *py_ldb_parse_ldif(PyLdbObject *self, PyObject *args)
    2138             : {
    2139        4124 :         PyObject *list, *ret;
    2140        4124 :         struct ldb_ldif *ldif;
    2141        4124 :         const char *s;
    2142       61753 :         struct ldb_dn *last_dn = NULL;
    2143             : 
    2144        4124 :         TALLOC_CTX *mem_ctx;
    2145             : 
    2146       61753 :         if (!PyArg_ParseTuple(args, "s", &s))
    2147           0 :                 return NULL;
    2148             : 
    2149       61753 :         mem_ctx = talloc_new(NULL);
    2150       61753 :         if (!mem_ctx) {
    2151           0 :                 Py_RETURN_NONE;
    2152             :         }
    2153             : 
    2154       61753 :         list = PyList_New(0);
    2155       61753 :         if (list == NULL) {
    2156           0 :                 talloc_free(mem_ctx);
    2157           0 :                 return NULL;
    2158             :         }
    2159             : 
    2160      586544 :         while (s && *s != '\0') {
    2161      524791 :                 ldif = ldb_ldif_read_string(self->ldb_ctx, &s);
    2162      524791 :                 talloc_steal(mem_ctx, ldif);
    2163      524791 :                 if (ldif) {
    2164      524791 :                         int res = 0;
    2165      524791 :                         PyObject *py_ldif = ldb_ldif_to_pyobject(self, ldif);
    2166      524791 :                         if (py_ldif == NULL) {
    2167           0 :                                 Py_CLEAR(list);
    2168           0 :                                 if (PyErr_Occurred() == NULL) {
    2169           0 :                                         PyErr_BadArgument();
    2170             :                                 }
    2171           0 :                                 talloc_free(mem_ctx);
    2172           0 :                                 return NULL;
    2173             :                         }
    2174      524791 :                         res = PyList_Append(list, py_ldif);
    2175      524791 :                         Py_CLEAR(py_ldif);
    2176      524791 :                         if (res == -1) {
    2177           0 :                                 Py_CLEAR(list);
    2178           0 :                                 talloc_free(mem_ctx);
    2179           0 :                                 return NULL;
    2180             :                         }
    2181      524791 :                         last_dn = ldif->msg->dn;
    2182             :                 } else {
    2183           0 :                         const char *last_dn_str = NULL;
    2184           0 :                         const char *err_string = NULL;
    2185           0 :                         if (last_dn == NULL) {
    2186           0 :                                 PyErr_SetString(PyExc_ValueError,
    2187             :                                                 "unable to parse LDIF "
    2188             :                                                 "string at first chunk");
    2189           0 :                                 Py_CLEAR(list);
    2190           0 :                                 talloc_free(mem_ctx);
    2191           0 :                                 return NULL;
    2192             :                         }
    2193             : 
    2194           0 :                         last_dn_str
    2195           0 :                                 = ldb_dn_get_linearized(last_dn);
    2196             : 
    2197           0 :                         err_string
    2198           0 :                                 = talloc_asprintf(mem_ctx,
    2199             :                                                   "unable to parse ldif "
    2200             :                                                   "string AFTER %s",
    2201             :                                                   last_dn_str);
    2202             : 
    2203           0 :                         PyErr_SetString(PyExc_ValueError,
    2204             :                                         err_string);
    2205           0 :                         talloc_free(mem_ctx);
    2206           0 :                         Py_CLEAR(list);
    2207           0 :                         return NULL;
    2208             :                 }
    2209             :         }
    2210       61753 :         talloc_free(mem_ctx); /* The pyobject already has a reference to the things it needs */
    2211       61753 :         ret = PyObject_GetIter(list);
    2212       61753 :         Py_DECREF(list);
    2213       57629 :         return ret;
    2214             : }
    2215             : 
    2216       11147 : static PyObject *py_ldb_msg_diff(PyLdbObject *self, PyObject *args)
    2217             : {
    2218           8 :         int ldb_ret;
    2219           8 :         PyObject *py_msg_old;
    2220           8 :         PyObject *py_msg_new;
    2221           8 :         struct ldb_message *diff;
    2222           8 :         struct ldb_context *ldb;
    2223           8 :         PyObject *py_ret;
    2224       11147 :         TALLOC_CTX *mem_ctx = NULL;
    2225             : 
    2226       11147 :         if (!PyArg_ParseTuple(args, "OO", &py_msg_old, &py_msg_new))
    2227           0 :                 return NULL;
    2228             : 
    2229       11147 :         if (!pyldb_Message_Check(py_msg_old)) {
    2230           0 :                 PyErr_SetString(PyExc_TypeError, "Expected Ldb Message for old message");
    2231           0 :                 return NULL;
    2232             :         }
    2233             : 
    2234       11147 :         if (!pyldb_Message_Check(py_msg_new)) {
    2235           0 :                 PyErr_SetString(PyExc_TypeError, "Expected Ldb Message for new message");
    2236           0 :                 return NULL;
    2237             :         }
    2238             : 
    2239       11147 :         mem_ctx = talloc_new(NULL);
    2240       11147 :         if (mem_ctx == NULL) {
    2241           0 :                 PyErr_NoMemory();
    2242           0 :                 return NULL;
    2243             :         }
    2244             : 
    2245       11147 :         ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
    2246       11155 :         ldb_ret = ldb_msg_difference(ldb, mem_ctx,
    2247       11147 :                                      pyldb_Message_AsMessage(py_msg_old),
    2248       11147 :                                      pyldb_Message_AsMessage(py_msg_new),
    2249             :                                      &diff);
    2250       11147 :         if (ldb_ret != LDB_SUCCESS) {
    2251           0 :                 talloc_free(mem_ctx);
    2252           0 :                 PyErr_SetString(PyExc_RuntimeError, "Failed to generate the Ldb Message diff");
    2253           0 :                 return NULL;
    2254             :         }
    2255             : 
    2256       11147 :         diff = ldb_msg_copy(mem_ctx, diff);
    2257       11147 :         if (diff == NULL) {
    2258           0 :                 talloc_free(mem_ctx);
    2259           0 :                 PyErr_NoMemory();
    2260           0 :                 return NULL;
    2261             :         }
    2262             : 
    2263       11147 :         py_ret = PyLdbMessage_FromMessage(diff, self);
    2264             : 
    2265       11147 :         talloc_free(mem_ctx);
    2266             : 
    2267       11147 :         return py_ret;
    2268             : }
    2269             : 
    2270       26235 : static PyObject *py_ldb_schema_format_value(PyLdbObject *self, PyObject *args)
    2271             : {
    2272         657 :         const struct ldb_schema_attribute *a;
    2273         657 :         struct ldb_val old_val;
    2274         657 :         struct ldb_val new_val;
    2275         657 :         TALLOC_CTX *mem_ctx;
    2276         657 :         PyObject *ret;
    2277         657 :         char *element_name;
    2278         657 :         PyObject *val;
    2279         657 :         Py_ssize_t size;
    2280         657 :         int result;
    2281             : 
    2282       26235 :         if (!PyArg_ParseTuple(args, "sO", &element_name, &val))
    2283           0 :                 return NULL;
    2284             : 
    2285       26235 :         result = PyBytes_AsStringAndSize(val, (char **)&old_val.data, &size);
    2286       26235 :         old_val.length = size;
    2287             : 
    2288       26235 :         if (result != 0) {
    2289           0 :                 PyErr_SetString(PyExc_RuntimeError, "Failed to convert passed value to String");
    2290           0 :                 return NULL;
    2291             :         }
    2292             : 
    2293       26235 :         a = ldb_schema_attribute_by_name(pyldb_Ldb_AS_LDBCONTEXT(self), element_name);
    2294             : 
    2295       26235 :         if (a == NULL) {
    2296           0 :                 Py_RETURN_NONE;
    2297             :         }
    2298             : 
    2299       26235 :         mem_ctx = talloc_new(NULL);
    2300       26235 :         if (mem_ctx == NULL) {
    2301           0 :                 PyErr_NoMemory();
    2302           0 :                 return NULL;
    2303             :         }
    2304             : 
    2305       26235 :         if (a->syntax->ldif_write_fn(pyldb_Ldb_AS_LDBCONTEXT(self), mem_ctx, &old_val, &new_val) != 0) {
    2306           0 :                 talloc_free(mem_ctx);
    2307           0 :                 Py_RETURN_NONE;
    2308             :         }
    2309             : 
    2310       26235 :         ret = PyBytes_FromStringAndSize((const char *)new_val.data, new_val.length);
    2311             : 
    2312       26235 :         talloc_free(mem_ctx);
    2313             : 
    2314       26235 :         return ret;
    2315             : }
    2316             : 
    2317     3374569 : static PyObject *py_ldb_search(PyLdbObject *self, PyObject *args, PyObject *kwargs)
    2318             : {
    2319     3374569 :         PyObject *py_base = Py_None;
    2320     3374569 :         int scope = LDB_SCOPE_DEFAULT;
    2321     3374569 :         char *expr = NULL;
    2322     3374569 :         PyObject *py_attrs = Py_None;
    2323     3374569 :         PyObject *py_controls = Py_None;
    2324     3374569 :         const char * const kwnames[] = { "base", "scope", "expression", "attrs", "controls", NULL };
    2325      278269 :         int ret;
    2326      278269 :         struct ldb_result *res;
    2327      278269 :         struct ldb_request *req;
    2328      278269 :         const char **attrs;
    2329      278269 :         struct ldb_context *ldb_ctx;
    2330      278269 :         struct ldb_control **parsed_controls;
    2331      278269 :         struct ldb_dn *base;
    2332      278269 :         PyObject *py_ret;
    2333      278269 :         TALLOC_CTX *mem_ctx;
    2334             : 
    2335             :         /* type "int" rather than "enum" for "scope" is intentional */
    2336     3374569 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OizOO",
    2337             :                                          discard_const_p(char *, kwnames),
    2338             :                                          &py_base, &scope, &expr, &py_attrs, &py_controls))
    2339           7 :                 return NULL;
    2340             : 
    2341             : 
    2342     3374562 :         mem_ctx = talloc_new(NULL);
    2343     3374562 :         if (mem_ctx == NULL) {
    2344           0 :                 PyErr_NoMemory();
    2345           0 :                 return NULL;
    2346             :         }
    2347     3374562 :         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    2348             : 
    2349     3374562 :         if (py_attrs == Py_None) {
    2350      699057 :                 attrs = NULL;
    2351             :         } else {
    2352     2618017 :                 attrs = PyList_AsStrList(mem_ctx, py_attrs, "attrs");
    2353     2618017 :                 if (attrs == NULL) {
    2354          10 :                         talloc_free(mem_ctx);
    2355          10 :                         return NULL;
    2356             :                 }
    2357             :         }
    2358             : 
    2359     3374552 :         if (py_base == Py_None) {
    2360        2267 :                 base = ldb_get_default_basedn(ldb_ctx);
    2361             :         } else {
    2362     3372285 :                 if (!pyldb_Object_AsDn(mem_ctx, py_base, ldb_ctx, &base)) {
    2363           2 :                         talloc_free(mem_ctx);
    2364           2 :                         return NULL;
    2365             :                 }
    2366             :         }
    2367             : 
    2368     3374550 :         if (py_controls == Py_None) {
    2369      667335 :                 parsed_controls = NULL;
    2370             :         } else {
    2371     2690144 :                 const char **controls = PyList_AsStrList(mem_ctx, py_controls, "controls");
    2372     2690144 :                 if (controls == NULL) {
    2373           2 :                         talloc_free(mem_ctx);
    2374           2 :                         return NULL;
    2375             :                 }
    2376     2690142 :                 parsed_controls = ldb_parse_control_strings(ldb_ctx, mem_ctx, controls);
    2377     2690142 :                 if (controls[0] != NULL && parsed_controls == NULL) {
    2378           0 :                         talloc_free(mem_ctx);
    2379           0 :                         PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, ldb_ctx);
    2380           0 :                         return NULL;
    2381             :                 }
    2382     2690142 :                 talloc_free(controls);
    2383             :         }
    2384             : 
    2385     3374548 :         res = talloc_zero(mem_ctx, struct ldb_result);
    2386     3374548 :         if (res == NULL) {
    2387           0 :                 PyErr_NoMemory();
    2388           0 :                 talloc_free(mem_ctx);
    2389           0 :                 return NULL;
    2390             :         }
    2391             : 
    2392     3374548 :         ret = ldb_build_search_req(&req, ldb_ctx, mem_ctx,
    2393             :                                    base,
    2394             :                                    scope,
    2395             :                                    expr,
    2396             :                                    attrs,
    2397             :                                    parsed_controls,
    2398             :                                    res,
    2399             :                                    ldb_search_default_callback,
    2400             :                                    NULL);
    2401             : 
    2402     3374548 :         if (ret != LDB_SUCCESS) {
    2403           6 :                 talloc_free(mem_ctx);
    2404           6 :                 PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
    2405           6 :                 return NULL;
    2406             :         }
    2407             : 
    2408     3374542 :         talloc_steal(req, attrs);
    2409             : 
    2410     3374542 :         ret = ldb_request(ldb_ctx, req);
    2411             : 
    2412     3374542 :         if (ret == LDB_SUCCESS) {
    2413     3374353 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    2414             :         }
    2415             : 
    2416     3374542 :         if (ret != LDB_SUCCESS) {
    2417      116348 :                 talloc_free(mem_ctx);
    2418      116348 :                 PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
    2419      116348 :                 return NULL;
    2420             :         }
    2421             : 
    2422     3258194 :         py_ret = PyLdbResult_FromResult(res, self);
    2423             : 
    2424     3258194 :         talloc_free(mem_ctx);
    2425             : 
    2426     3258194 :         return py_ret;
    2427             : }
    2428             : 
    2429       15382 : static int py_ldb_search_iterator_reply_destructor(struct py_ldb_search_iterator_reply *reply)
    2430             : {
    2431       15382 :         if (reply->py_iter != NULL) {
    2432       15382 :                 DLIST_REMOVE(reply->py_iter->state.next, reply);
    2433       15382 :                 if (reply->py_iter->state.result == reply) {
    2434          51 :                         reply->py_iter->state.result = NULL;
    2435             :                 }
    2436       15382 :                 reply->py_iter = NULL;
    2437             :         }
    2438             : 
    2439       15382 :         Py_CLEAR(reply->obj);
    2440             : 
    2441       15382 :         return 0;
    2442             : }
    2443             : 
    2444       16749 : static int py_ldb_search_iterator_callback(struct ldb_request *req,
    2445             :                                            struct ldb_reply *ares)
    2446             : {
    2447       16749 :         PyLdbSearchIteratorObject *py_iter = (PyLdbSearchIteratorObject *)req->context;
    2448       16749 :         struct ldb_result result = { .msgs = NULL };
    2449       16749 :         struct py_ldb_search_iterator_reply *reply = NULL;
    2450             : 
    2451       16749 :         if (ares == NULL) {
    2452           0 :                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    2453             :         }
    2454             : 
    2455       16749 :         if (ares->error != LDB_SUCCESS) {
    2456        1367 :                 int ret = ares->error;
    2457        1367 :                 TALLOC_FREE(ares);
    2458        1367 :                 return ldb_request_done(req, ret);
    2459             :         }
    2460             : 
    2461       15382 :         reply = talloc_zero(py_iter->mem_ctx,
    2462             :                             struct py_ldb_search_iterator_reply);
    2463       15382 :         if (reply == NULL) {
    2464           0 :                 TALLOC_FREE(ares);
    2465           0 :                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    2466             :         }
    2467       15382 :         reply->py_iter = py_iter;
    2468       15382 :         talloc_set_destructor(reply, py_ldb_search_iterator_reply_destructor);
    2469             : 
    2470       15382 :         switch (ares->type) {
    2471       15313 :         case LDB_REPLY_ENTRY:
    2472       15313 :                 reply->obj = PyLdbMessage_FromMessage(ares->message, py_iter->ldb);
    2473       15313 :                 if (reply->obj == NULL) {
    2474           0 :                         TALLOC_FREE(ares);
    2475           0 :                         return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    2476             :                 }
    2477       15313 :                 DLIST_ADD_END(py_iter->state.next, reply);
    2478       15313 :                 TALLOC_FREE(ares);
    2479       15313 :                 return LDB_SUCCESS;
    2480             : 
    2481          18 :         case LDB_REPLY_REFERRAL:
    2482          18 :                 reply->obj = PyUnicode_FromString(ares->referral);
    2483          18 :                 if (reply->obj == NULL) {
    2484           0 :                         TALLOC_FREE(ares);
    2485           0 :                         return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    2486             :                 }
    2487          18 :                 DLIST_ADD_END(py_iter->state.next, reply);
    2488          18 :                 TALLOC_FREE(ares);
    2489          18 :                 return LDB_SUCCESS;
    2490             : 
    2491          51 :         case LDB_REPLY_DONE:
    2492          51 :                 result = (struct ldb_result) { .controls = ares->controls };
    2493          51 :                 reply->obj = PyLdbResult_FromResult(&result, py_iter->ldb);
    2494          51 :                 if (reply->obj == NULL) {
    2495           0 :                         TALLOC_FREE(ares);
    2496           0 :                         return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    2497             :                 }
    2498          51 :                 py_iter->state.result = reply;
    2499          51 :                 TALLOC_FREE(ares);
    2500          51 :                 return ldb_request_done(req, LDB_SUCCESS);
    2501             :         }
    2502             : 
    2503           0 :         TALLOC_FREE(ares);
    2504           0 :         return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    2505             : }
    2506             : 
    2507        1502 : static PyObject *py_ldb_search_iterator(PyLdbObject *self, PyObject *args, PyObject *kwargs)
    2508             : {
    2509        1502 :         PyObject *py_base = Py_None;
    2510        1502 :         int scope = LDB_SCOPE_DEFAULT;
    2511        1502 :         int timeout = 0;
    2512        1502 :         char *expr = NULL;
    2513        1502 :         PyObject *py_attrs = Py_None;
    2514        1502 :         PyObject *py_controls = Py_None;
    2515        1502 :         const char * const kwnames[] = { "base", "scope", "expression", "attrs", "controls", "timeout", NULL };
    2516           0 :         int ret;
    2517           0 :         const char **attrs;
    2518           0 :         struct ldb_context *ldb_ctx;
    2519           0 :         struct ldb_control **parsed_controls;
    2520           0 :         struct ldb_dn *base;
    2521           0 :         PyLdbSearchIteratorObject *py_iter;
    2522             : 
    2523             :         /* type "int" rather than "enum" for "scope" is intentional */
    2524        1502 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OizOOi",
    2525             :                                          discard_const_p(char *, kwnames),
    2526             :                                          &py_base, &scope, &expr, &py_attrs, &py_controls, &timeout))
    2527           0 :                 return NULL;
    2528             : 
    2529        1502 :         py_iter = (PyLdbSearchIteratorObject *)PyLdbSearchIterator.tp_alloc(&PyLdbSearchIterator, 0);
    2530        1502 :         if (py_iter == NULL) {
    2531           0 :                 PyErr_NoMemory();
    2532           0 :                 return NULL;
    2533             :         }
    2534        1502 :         py_iter->ldb = self;
    2535        1464 :         Py_INCREF(self);
    2536        1502 :         ZERO_STRUCT(py_iter->state);
    2537        1502 :         py_iter->mem_ctx = talloc_new(NULL);
    2538        1502 :         if (py_iter->mem_ctx == NULL) {
    2539           0 :                 Py_DECREF(py_iter);
    2540           0 :                 PyErr_NoMemory();
    2541           0 :                 return NULL;
    2542             :         }
    2543             : 
    2544        1502 :         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    2545             : 
    2546        1502 :         if (py_attrs == Py_None) {
    2547          48 :                 attrs = NULL;
    2548             :         } else {
    2549        1454 :                 attrs = PyList_AsStrList(py_iter->mem_ctx, py_attrs, "attrs");
    2550        1454 :                 if (attrs == NULL) {
    2551           0 :                         Py_DECREF(py_iter);
    2552           0 :                         PyErr_NoMemory();
    2553           0 :                         return NULL;
    2554             :                 }
    2555             :         }
    2556             : 
    2557        1502 :         if (py_base == Py_None) {
    2558         113 :                 base = ldb_get_default_basedn(ldb_ctx);
    2559             :         } else {
    2560        1389 :                 if (!pyldb_Object_AsDn(py_iter->mem_ctx, py_base, ldb_ctx, &base)) {
    2561           0 :                         Py_DECREF(py_iter);
    2562           0 :                         PyErr_NoMemory();
    2563           0 :                         return NULL;
    2564             :                 }
    2565             :         }
    2566             : 
    2567        1502 :         if (py_controls == Py_None) {
    2568          80 :                 parsed_controls = NULL;
    2569             :         } else {
    2570        1422 :                 const char **controls = NULL;
    2571             : 
    2572        1422 :                 controls = PyList_AsStrList(py_iter->mem_ctx,
    2573             :                                             py_controls, "controls");
    2574        1422 :                 if (controls == NULL) {
    2575           0 :                         Py_DECREF(py_iter);
    2576           0 :                         PyErr_NoMemory();
    2577           0 :                         return NULL;
    2578             :                 }
    2579             : 
    2580        1422 :                 parsed_controls = ldb_parse_control_strings(ldb_ctx,
    2581             :                                                             py_iter->mem_ctx,
    2582             :                                                             controls);
    2583        1422 :                 if (controls[0] != NULL && parsed_controls == NULL) {
    2584           0 :                         Py_DECREF(py_iter);
    2585           0 :                         PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, ldb_ctx);
    2586           0 :                         return NULL;
    2587             :                 }
    2588        1422 :                 talloc_free(controls);
    2589             :         }
    2590             : 
    2591        1502 :         ret = ldb_build_search_req(&py_iter->state.req,
    2592             :                                    ldb_ctx,
    2593             :                                    py_iter->mem_ctx,
    2594             :                                    base,
    2595             :                                    scope,
    2596             :                                    expr,
    2597             :                                    attrs,
    2598             :                                    parsed_controls,
    2599             :                                    py_iter,
    2600             :                                    py_ldb_search_iterator_callback,
    2601             :                                    NULL);
    2602        1502 :         if (ret != LDB_SUCCESS) {
    2603           0 :                 Py_DECREF(py_iter);
    2604           0 :                 PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
    2605           0 :                 return NULL;
    2606             :         }
    2607             : 
    2608        1502 :         ldb_set_timeout(ldb_ctx, py_iter->state.req, timeout);
    2609             : 
    2610        1502 :         ret = ldb_request(ldb_ctx, py_iter->state.req);
    2611        1502 :         if (ret != LDB_SUCCESS) {
    2612           0 :                 Py_DECREF(py_iter);
    2613           0 :                 PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
    2614           0 :                 return NULL;
    2615             :         }
    2616             : 
    2617        1502 :         return (PyObject *)py_iter;
    2618             : }
    2619             : 
    2620         244 : static PyObject *py_ldb_get_opaque(PyLdbObject *self, PyObject *args)
    2621             : {
    2622           0 :         char *name;
    2623           0 :         void *data;
    2624             : 
    2625         244 :         if (!PyArg_ParseTuple(args, "s", &name))
    2626           0 :                 return NULL;
    2627             : 
    2628         244 :         data = ldb_get_opaque(pyldb_Ldb_AS_LDBCONTEXT(self), name);
    2629             : 
    2630         244 :         if (data == NULL)
    2631         140 :                 Py_RETURN_NONE;
    2632             : 
    2633         104 :         if (data == (void *)1) {
    2634             :                 /*
    2635             :                  * This value is sometimes used to indicate that a opaque is
    2636             :                  * set.
    2637             :                  */
    2638           0 :                 Py_RETURN_TRUE;
    2639             :         }
    2640             : 
    2641             :         {
    2642             :                 /*
    2643             :                  * Let’s hope the opaque data is actually a talloc pointer,
    2644             :                  * otherwise calling this would be Very Bad.
    2645             :                  */
    2646         104 :                 const bool *opaque = talloc_get_type(data, bool);
    2647         104 :                 if (opaque != NULL) {
    2648          12 :                         return PyBool_FromLong(*opaque);
    2649             :                 }
    2650             :         }
    2651             : 
    2652             :         {
    2653          92 :                 const unsigned long long *opaque = talloc_get_type(
    2654             :                         data, unsigned long long);
    2655          92 :                 if (opaque != NULL) {
    2656          84 :                         return PyLong_FromUnsignedLongLong(*opaque);
    2657             :                 }
    2658             :         }
    2659             : 
    2660             :         {
    2661           8 :                 const char *opaque = talloc_get_type(data, char);
    2662           8 :                 if (opaque != NULL) {
    2663           8 :                         return PyUnicode_FromString(opaque);
    2664             :                 }
    2665             :         }
    2666             : 
    2667           0 :         PyErr_SetString(PyExc_ValueError, "Unsupported type for opaque");
    2668           0 :         return NULL;
    2669             : }
    2670             : 
    2671         653 : static PyObject *py_ldb_set_opaque(PyLdbObject *self, PyObject *args)
    2672             : {
    2673         110 :         char *name;
    2674         110 :         PyObject *data;
    2675         653 :         void *value = NULL;
    2676         110 :         int ret;
    2677             : 
    2678         653 :         if (!PyArg_ParseTuple(args, "sO", &name, &data))
    2679           0 :                 return NULL;
    2680             : 
    2681         653 :         if (data == Py_None) {
    2682           4 :                 value = NULL;
    2683         649 :         } else if (PyBool_Check(data)) {
    2684          12 :                 bool *opaque = NULL;
    2685           0 :                 bool b;
    2686             :                 {
    2687          12 :                         const int is_true = PyObject_IsTrue(data);
    2688          12 :                         if (is_true == -1) {
    2689           0 :                                 return NULL;
    2690             :                         }
    2691          12 :                         b = is_true;
    2692             :                 }
    2693             : 
    2694          12 :                 opaque = talloc(self->ldb_ctx, bool);
    2695          12 :                 if (opaque == NULL) {
    2696           0 :                         return PyErr_NoMemory();
    2697             :                 }
    2698          12 :                 *opaque = b;
    2699          12 :                 value = opaque;
    2700         637 :         } else if (PyLong_Check(data)) {
    2701         565 :                 unsigned long long *opaque = NULL;
    2702         565 :                 const unsigned long long n = PyLong_AsUnsignedLongLong(data);
    2703         565 :                 if (n == -1 && PyErr_Occurred()) {
    2704           4 :                         return NULL;
    2705             :                 }
    2706             : 
    2707         561 :                 opaque = talloc(self->ldb_ctx, unsigned long long);
    2708         561 :                 if (opaque == NULL) {
    2709           0 :                         return PyErr_NoMemory();
    2710             :                 }
    2711         561 :                 *opaque = n;
    2712         561 :                 value = opaque;
    2713          72 :         } else if (PyUnicode_Check(data)) {
    2714          52 :                 char *opaque = NULL;
    2715          52 :                 const char *s = PyUnicode_AsUTF8(data);
    2716          52 :                 if (s == NULL) {
    2717           0 :                         return NULL;
    2718             :                 }
    2719             : 
    2720          52 :                 opaque = talloc_strdup(self->ldb_ctx, s);
    2721          52 :                 if (opaque == NULL) {
    2722           0 :                         return PyErr_NoMemory();
    2723             :                 }
    2724             : 
    2725             :                 /*
    2726             :                  * Assign the right type to the talloc pointer, so that
    2727             :                  * py_ldb_get_opaque() can recognize it.
    2728             :                  */
    2729          52 :                 talloc_set_name_const(opaque, "char");
    2730             : 
    2731          52 :                 value = opaque;
    2732             :         } else {
    2733          20 :                 PyErr_SetString(PyExc_ValueError,
    2734             :                                 "Unsupported type for opaque");
    2735          20 :                 return NULL;
    2736             :         }
    2737             : 
    2738         629 :         ret = ldb_set_opaque(pyldb_Ldb_AS_LDBCONTEXT(self), name, value);
    2739         629 :         if (ret) {
    2740           0 :                 PyErr_SetLdbError(PyExc_LdbError,
    2741             :                                   ret,
    2742             :                                   pyldb_Ldb_AS_LDBCONTEXT(self));
    2743           0 :                 return NULL;
    2744             :         }
    2745             : 
    2746         629 :         Py_RETURN_NONE;
    2747             : }
    2748             : 
    2749          47 : static PyObject *py_ldb_sequence_number(PyLdbObject *self, PyObject *args)
    2750             : {
    2751          47 :         struct ldb_context *ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
    2752           0 :         int type, ret;
    2753           0 :         uint64_t value;
    2754             : 
    2755          47 :         if (!PyArg_ParseTuple(args, "i", &type))
    2756           0 :                 return NULL;
    2757             : 
    2758             :         /* FIXME: More interpretation */
    2759             : 
    2760          47 :         ret = ldb_sequence_number(ldb, type, &value);
    2761             : 
    2762          47 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb);
    2763             : 
    2764          47 :         return PyLong_FromLongLong(value);
    2765             : }
    2766             : 
    2767           1 : static PyObject *py_ldb_whoami(PyLdbObject *self, PyObject *args)
    2768             : {
    2769           1 :         struct ldb_context *ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
    2770           1 :         struct ldb_result *res = NULL;
    2771           1 :         struct ldb_extended *ext_res = NULL;
    2772           1 :         size_t len = 0;
    2773           0 :         int ret;
    2774             : 
    2775           1 :         ret = ldb_extended(ldb, LDB_EXTENDED_WHOAMI_OID, NULL, &res);
    2776           1 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb);
    2777             : 
    2778           1 :         ext_res = res->extended;
    2779           1 :         if (ext_res == NULL) {
    2780           0 :                 PyErr_SetString(PyExc_TypeError, "Got no exop reply");
    2781           0 :                 return NULL;
    2782             :         }
    2783             : 
    2784           1 :         if (strcmp(ext_res->oid, LDB_EXTENDED_WHOAMI_OID) != 0) {
    2785           0 :                 PyErr_SetString(PyExc_TypeError, "Got wrong reply OID");
    2786           0 :                 return NULL;
    2787             :         }
    2788             : 
    2789           1 :         len = talloc_get_size(ext_res->data);
    2790           1 :         if (len == 0) {
    2791           0 :                 Py_RETURN_NONE;
    2792             :         }
    2793             : 
    2794           1 :         return PyUnicode_FromStringAndSize(ext_res->data, len);
    2795             : }
    2796             : 
    2797          66 : static PyObject *py_ldb_disconnect(PyLdbObject *self, PyObject *args)
    2798             : {
    2799           0 :         size_t ref_count;
    2800          66 :         void *parent = NULL;
    2801          66 :         TALLOC_CTX *mem_ctx = NULL;
    2802          66 :         struct ldb_context *ldb = NULL;
    2803             : 
    2804          66 :         if (self->ldb_ctx == NULL) {
    2805             :                 /* It is hard to see how we'd get here. */
    2806           0 :                 PyErr_SetLdbError(PyExc_LdbError, LDB_ERR_OPERATIONS_ERROR, NULL);
    2807           0 :                 return NULL;
    2808             :         }
    2809             : 
    2810          66 :         ref_count = talloc_reference_count(self->ldb_ctx);
    2811             : 
    2812          66 :         if (ref_count != 0) {
    2813           0 :                 PyErr_SetString(PyExc_RuntimeError,
    2814             :                                 "ldb.disconnect() not possible as "
    2815             :                                 "object still has C (or second "
    2816             :                                 "python object) references");
    2817           0 :                 return NULL;
    2818             :         }
    2819             : 
    2820          66 :         parent = talloc_parent(self->ldb_ctx);
    2821             : 
    2822          66 :         if (parent != self->mem_ctx) {
    2823           0 :                 PyErr_SetString(PyExc_RuntimeError,
    2824             :                                 "ldb.disconnect() not possible as "
    2825             :                                 "object is not talloc owned by this "
    2826             :                                 "python object!");
    2827           0 :                 return NULL;
    2828             :         }
    2829             : 
    2830             :         /*
    2831             :          * This recapitulates py_ldb_new(), cleaning out all the
    2832             :          * connections and state, but leaving the python object in a
    2833             :          * workable condition.
    2834             :          */
    2835          66 :         mem_ctx = talloc_new(NULL);
    2836          66 :         if (mem_ctx == NULL) {
    2837           0 :                 return PyErr_NoMemory();
    2838             :         }
    2839             : 
    2840          66 :         ldb = ldb_init(mem_ctx, NULL);
    2841          66 :         if (ldb == NULL) {
    2842           0 :                 talloc_free(mem_ctx);
    2843           0 :                 PyErr_NoMemory();
    2844           0 :                 return NULL;
    2845             :         }
    2846             : 
    2847             :         /*
    2848             :          * Notice we allocate the new mem_ctx and ldb before freeing
    2849             :          * the old one. This has two purposes: 1, the python object
    2850             :          * will still be consistent if an exception happens, and 2, it
    2851             :          * ensures the new ldb can't have the same memory address as
    2852             :          * the old one, and ldb address equality is a guard we use in
    2853             :          * Python DNs and such. Repeated calls to disconnect() *can* make
    2854             :          * this happen, so we don't advise doing that.
    2855             :          */
    2856          66 :         TALLOC_FREE(self->mem_ctx);
    2857             : 
    2858          66 :         self->mem_ctx = mem_ctx;
    2859          66 :         self->ldb_ctx = ldb;
    2860             : 
    2861          66 :         Py_RETURN_NONE;
    2862             : }
    2863             : 
    2864             : 
    2865             : static const struct ldb_dn_extended_syntax test_dn_syntax = {
    2866             :         .name             = "TEST",
    2867             :         .read_fn          = ldb_handler_copy,
    2868             :         .write_clear_fn   = ldb_handler_copy,
    2869             :         .write_hex_fn     = ldb_handler_copy,
    2870             : };
    2871             : 
    2872           6 : static PyObject *py_ldb_register_test_extensions(PyLdbObject *self,
    2873             :                 PyObject *Py_UNUSED(ignored))
    2874             : {
    2875           6 :         struct ldb_context *ldb = pyldb_Ldb_AS_LDBCONTEXT(self);
    2876           0 :         int ret;
    2877             : 
    2878           6 :         ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &test_dn_syntax);
    2879             : 
    2880           6 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb);
    2881             : 
    2882           6 :         Py_RETURN_NONE;
    2883             : }
    2884             : 
    2885             : 
    2886             : static PyMethodDef py_ldb_methods[] = {
    2887             :         { "set_debug", (PyCFunction)py_ldb_set_debug, METH_VARARGS,
    2888             :                 "S.set_debug(callback) -> None\n"
    2889             :                 "Set callback for LDB debug messages.\n"
    2890             :                 "The callback should accept a debug level and debug text." },
    2891             :         { "set_create_perms", (PyCFunction)py_ldb_set_create_perms, METH_VARARGS,
    2892             :                 "S.set_create_perms(mode) -> None\n"
    2893             :                 "Set mode to use when creating new LDB files." },
    2894             :         { "set_modules_dir", (PyCFunction)py_ldb_set_modules_dir, METH_VARARGS,
    2895             :                 "S.set_modules_dir(path) -> None\n"
    2896             :                 "Set path LDB should search for modules" },
    2897             :         { "transaction_start", (PyCFunction)py_ldb_transaction_start, METH_NOARGS,
    2898             :                 "S.transaction_start() -> None\n"
    2899             :                 "Start a new transaction." },
    2900             :         { "transaction_prepare_commit", (PyCFunction)py_ldb_transaction_prepare_commit, METH_NOARGS,
    2901             :                 "S.transaction_prepare_commit() -> None\n"
    2902             :                 "prepare to commit a new transaction (2-stage commit)." },
    2903             :         { "transaction_commit", (PyCFunction)py_ldb_transaction_commit, METH_NOARGS,
    2904             :                 "S.transaction_commit() -> None\n"
    2905             :                 "commit a new transaction." },
    2906             :         { "transaction_cancel", (PyCFunction)py_ldb_transaction_cancel, METH_NOARGS,
    2907             :                 "S.transaction_cancel() -> None\n"
    2908             :                 "cancel a new transaction." },
    2909             :         { "setup_wellknown_attributes", (PyCFunction)py_ldb_setup_wellknown_attributes, METH_NOARGS,
    2910             :                 NULL },
    2911             :         { "get_root_basedn", (PyCFunction)py_ldb_get_root_basedn, METH_NOARGS,
    2912             :                 NULL },
    2913             :         { "get_schema_basedn", (PyCFunction)py_ldb_get_schema_basedn, METH_NOARGS,
    2914             :                 NULL },
    2915             :         { "get_default_basedn", (PyCFunction)py_ldb_get_default_basedn, METH_NOARGS,
    2916             :                 NULL },
    2917             :         { "get_config_basedn", (PyCFunction)py_ldb_get_config_basedn, METH_NOARGS,
    2918             :                 NULL },
    2919             :         { "connect", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_connect),
    2920             :                 METH_VARARGS|METH_KEYWORDS,
    2921             :                 "S.connect(url, flags=0, options=None) -> None\n"
    2922             :                 "Connect to a LDB URL." },
    2923             :         { "modify", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_modify),
    2924             :                 METH_VARARGS|METH_KEYWORDS,
    2925             :                 "S.modify(message, controls=None, validate=False) -> None\n"
    2926             :                 "Modify an entry." },
    2927             :         { "add", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_add),
    2928             :                 METH_VARARGS|METH_KEYWORDS,
    2929             :                 "S.add(message, controls=None) -> None\n"
    2930             :                 "Add an entry." },
    2931             :         { "delete", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_delete),
    2932             :                 METH_VARARGS|METH_KEYWORDS,
    2933             :                 "S.delete(dn, controls=None) -> None\n"
    2934             :                 "Remove an entry." },
    2935             :         { "rename", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_rename),
    2936             :                 METH_VARARGS|METH_KEYWORDS,
    2937             :                 "S.rename(old_dn, new_dn, controls=None) -> None\n"
    2938             :                 "Rename an entry." },
    2939             :         { "search", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_search),
    2940             :                 METH_VARARGS|METH_KEYWORDS,
    2941             :                 "S.search(base=None, scope=None, expression=None, attrs=None, controls=None) -> result\n"
    2942             :                 "Search in a database.\n"
    2943             :                 "\n"
    2944             :                 ":param base: Optional base DN to search\n"
    2945             :                 ":param scope: Search scope (SCOPE_BASE, SCOPE_ONELEVEL or SCOPE_SUBTREE)\n"
    2946             :                 ":param expression: Optional search expression\n"
    2947             :                 ":param attrs: Attributes to return (defaults to all)\n"
    2948             :                 ":param controls: Optional list of controls\n"
    2949             :                 ":return: ldb.Result object\n"
    2950             :         },
    2951             :         { "search_iterator", PY_DISCARD_FUNC_SIG(PyCFunction,
    2952             :                                                  py_ldb_search_iterator),
    2953             :                 METH_VARARGS|METH_KEYWORDS,
    2954             :                 "S.search_iterator(base=None, scope=None, expression=None, attrs=None, controls=None, timeout=None) -> iterator\n"
    2955             :                 "Search in a database.\n"
    2956             :                 "\n"
    2957             :                 ":param base: Optional base DN to search\n"
    2958             :                 ":param scope: Search scope (SCOPE_BASE, SCOPE_ONELEVEL or SCOPE_SUBTREE)\n"
    2959             :                 ":param expression: Optional search expression\n"
    2960             :                 ":param attrs: Attributes to return (defaults to all)\n"
    2961             :                 ":param controls: Optional list of controls\n"
    2962             :                 ":param timeout: Optional timeout in seconds (defaults to 300), 0 means the default, -1 no timeout\n"
    2963             :                 ":return: ldb.SearchIterator object that provides results when they arrive\n"
    2964             :         },
    2965             :         { "schema_attribute_remove", (PyCFunction)py_ldb_schema_attribute_remove, METH_VARARGS,
    2966             :                 NULL },
    2967             :         { "schema_attribute_add", (PyCFunction)py_ldb_schema_attribute_add, METH_VARARGS,
    2968             :                 NULL },
    2969             :         { "schema_format_value", (PyCFunction)py_ldb_schema_format_value, METH_VARARGS,
    2970             :                 NULL },
    2971             :         { "parse_ldif", (PyCFunction)py_ldb_parse_ldif, METH_VARARGS,
    2972             :                 "S.parse_ldif(ldif) -> iter(messages)\n"
    2973             :                 "Parse a string formatted using LDIF." },
    2974             :         { "write_ldif", (PyCFunction)py_ldb_write_ldif, METH_VARARGS,
    2975             :                 "S.write_ldif(message, changetype) -> ldif\n"
    2976             :                 "Print the message as a string formatted using LDIF." },
    2977             :         { "msg_diff", (PyCFunction)py_ldb_msg_diff, METH_VARARGS,
    2978             :                 "S.msg_diff(Message) -> Message\n"
    2979             :                 "Return an LDB Message of the difference between two Message objects." },
    2980             :         { "get_opaque", (PyCFunction)py_ldb_get_opaque, METH_VARARGS,
    2981             :                 "S.get_opaque(name) -> value\n"
    2982             :                 "Get an opaque value set on this LDB connection. \n"
    2983             :                 ":note: The returned value may not be useful in Python."
    2984             :         },
    2985             :         { "set_opaque", (PyCFunction)py_ldb_set_opaque, METH_VARARGS,
    2986             :                 "S.set_opaque(name, value) -> None\n"
    2987             :                 "Set an opaque value on this LDB connection. \n"
    2988             :                 ":note: Passing incorrect values may cause crashes." },
    2989             :         { "sequence_number", (PyCFunction)py_ldb_sequence_number, METH_VARARGS,
    2990             :                 "S.sequence_number(type) -> value\n"
    2991             :                 "Return the value of the sequence according to the requested type" },
    2992             :         { "whoami",
    2993             :           (PyCFunction)py_ldb_whoami,
    2994             :           METH_NOARGS,
    2995             :           "S.whoami() -> value\n"
    2996             :           "Return the RFC4532 whoami string",
    2997             :         },
    2998             :         { "disconnect",
    2999             :           (PyCFunction)py_ldb_disconnect,
    3000             :           METH_NOARGS,
    3001             :           "S.disconnect() -> None\n"
    3002             :           "Make this Ldb object unusable, disconnect and free the "
    3003             :           "underlying LDB, releasing any file handles and sockets.",
    3004             :         },
    3005             :         { "_register_test_extensions", (PyCFunction)py_ldb_register_test_extensions, METH_NOARGS,
    3006             :                 "S._register_test_extensions() -> None\n"
    3007             :                 "Register internal extensions used in testing" },
    3008             :         {0},
    3009             : };
    3010             : 
    3011          12 : static int py_ldb_contains(PyLdbObject *self, PyObject *obj)
    3012             : {
    3013          12 :         struct ldb_context *ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self);
    3014           0 :         struct ldb_dn *dn;
    3015           0 :         struct ldb_result *result;
    3016           0 :         unsigned int count;
    3017           0 :         int ret;
    3018             : 
    3019          12 :         if (!pyldb_Object_AsDn(ldb_ctx, obj, ldb_ctx, &dn)) {
    3020           0 :                 return -1;
    3021             :         }
    3022             : 
    3023          12 :         ret = ldb_search(ldb_ctx, ldb_ctx, &result, dn, LDB_SCOPE_BASE, NULL,
    3024             :                          NULL);
    3025          12 :         if (ret != LDB_SUCCESS) {
    3026           0 :                 PyErr_SetLdbError(PyExc_LdbError, ret, ldb_ctx);
    3027           0 :                 return -1;
    3028             :         }
    3029             : 
    3030          12 :         count = result->count;
    3031             : 
    3032          12 :         talloc_free(result);
    3033             : 
    3034          12 :         if (count > 1) {
    3035           0 :                 PyErr_Format(PyExc_RuntimeError,
    3036             :                              "Searching for [%s] dn gave %u results!",
    3037             :                              ldb_dn_get_linearized(dn),
    3038             :                              count);
    3039           0 :                 return -1;
    3040             :         }
    3041             : 
    3042          12 :         return count;
    3043             : }
    3044             : 
    3045             : static PySequenceMethods py_ldb_seq = {
    3046             :         .sq_contains = (objobjproc)py_ldb_contains,
    3047             : };
    3048             : 
    3049       39135 : static void py_ldb_dealloc(PyLdbObject *self)
    3050             : {
    3051       39135 :         talloc_free(self->mem_ctx);
    3052       39135 :         Py_TYPE(self)->tp_free(self);
    3053       39135 : }
    3054             : 
    3055             : static PyTypeObject PyLdb = {
    3056             :         .tp_name = "ldb.Ldb",
    3057             :         .tp_methods = py_ldb_methods,
    3058             :         .tp_repr = (reprfunc)py_ldb_repr,
    3059             :         .tp_new = py_ldb_new,
    3060             :         .tp_init = (initproc)py_ldb_init,
    3061             :         .tp_dealloc = (destructor)py_ldb_dealloc,
    3062             :         .tp_getattro = PyObject_GenericGetAttr,
    3063             :         .tp_basicsize = sizeof(PyLdbObject),
    3064             :         .tp_doc = "Connection to a LDB database.",
    3065             :         .tp_as_sequence = &py_ldb_seq,
    3066             :         .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
    3067             : };
    3068             : 
    3069     3258245 : static void py_ldb_result_dealloc(PyLdbResultObject *self)
    3070             : {
    3071     3258245 :         talloc_free(self->mem_ctx);
    3072     3258245 :         Py_CLEAR(self->msgs);
    3073     3258245 :         Py_CLEAR(self->referals);
    3074     3258245 :         Py_CLEAR(self->controls);
    3075     3258245 :         Py_DECREF(self->pyldb);
    3076     3258245 :         Py_TYPE(self)->tp_free(self);
    3077     3258245 : }
    3078             : 
    3079        6309 : static PyObject *py_ldb_result_get_msgs(PyLdbResultObject *self, void *closure)
    3080             : {
    3081        6309 :         Py_INCREF(self->msgs);
    3082        6309 :         return self->msgs;
    3083             : }
    3084             : 
    3085       54700 : static PyObject *py_ldb_result_get_controls(PyLdbResultObject *self, void *closure)
    3086             : {
    3087       54700 :         Py_INCREF(self->controls);
    3088       54700 :         return self->controls;
    3089             : }
    3090             : 
    3091          62 : static PyObject *py_ldb_result_get_referals(PyLdbResultObject *self, void *closure)
    3092             : {
    3093          62 :         Py_INCREF(self->referals);
    3094          62 :         return self->referals;
    3095             : }
    3096             : 
    3097        2044 : static PyObject *py_ldb_result_get_count(PyLdbResultObject *self, void *closure)
    3098             : {
    3099           0 :         Py_ssize_t size;
    3100        2044 :         if (self->msgs == NULL) {
    3101           0 :                 PyErr_SetString(PyExc_AttributeError, "Count attribute is meaningless in this context");
    3102           0 :                 return NULL;
    3103             :         }
    3104        2044 :         size = PyList_Size(self->msgs);
    3105        2044 :         return PyLong_FromLong(size);
    3106             : }
    3107             : 
    3108             : static PyGetSetDef py_ldb_result_getset[] = {
    3109             :         {
    3110             :                 .name = discard_const_p(char, "controls"),
    3111             :                 .get  = (getter)py_ldb_result_get_controls,
    3112             :         },
    3113             :         {
    3114             :                 .name = discard_const_p(char, "msgs"),
    3115             :                 .get  = (getter)py_ldb_result_get_msgs,
    3116             :         },
    3117             :         {
    3118             :                 .name = discard_const_p(char, "referals"),
    3119             :                 .get  = (getter)py_ldb_result_get_referals,
    3120             :         },
    3121             :         {
    3122             :                 .name = discard_const_p(char, "count"),
    3123             :                 .get  = (getter)py_ldb_result_get_count,
    3124             :         },
    3125             :         { .name = NULL },
    3126             : };
    3127             : 
    3128      165838 : static PyObject *py_ldb_result_iter(PyLdbResultObject *self)
    3129             : {
    3130      165838 :         return PyObject_GetIter(self->msgs);
    3131             : }
    3132             : 
    3133     1811155 : static Py_ssize_t py_ldb_result_len(PyLdbResultObject *self)
    3134             : {
    3135     1811155 :         return PySequence_Size(self->msgs);
    3136             : }
    3137             : 
    3138     4677211 : static PyObject *py_ldb_result_find(PyLdbResultObject *self, Py_ssize_t idx)
    3139             : {
    3140     4677211 :         return PySequence_GetItem(self->msgs, idx);
    3141             : }
    3142             : 
    3143             : static PySequenceMethods py_ldb_result_seq = {
    3144             :         .sq_length = (lenfunc)py_ldb_result_len,
    3145             :         .sq_item = (ssizeargfunc)py_ldb_result_find,
    3146             : };
    3147             : 
    3148           4 : static PyObject *py_ldb_result_repr(PyLdbObject *self)
    3149             : {
    3150           4 :         return PyUnicode_FromString("<ldb result>");
    3151             : }
    3152             : 
    3153             : 
    3154             : static PyTypeObject PyLdbResult = {
    3155             :         .tp_name = "ldb.Result",
    3156             :         .tp_repr = (reprfunc)py_ldb_result_repr,
    3157             :         .tp_dealloc = (destructor)py_ldb_result_dealloc,
    3158             :         .tp_iter = (getiterfunc)py_ldb_result_iter,
    3159             :         .tp_getset = py_ldb_result_getset,
    3160             :         .tp_getattro = PyObject_GenericGetAttr,
    3161             :         .tp_basicsize = sizeof(PyLdbResultObject),
    3162             :         .tp_as_sequence = &py_ldb_result_seq,
    3163             :         .tp_doc = "LDB result.",
    3164             :         .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
    3165             : };
    3166             : 
    3167        1502 : static void py_ldb_search_iterator_dealloc(PyLdbSearchIteratorObject *self)
    3168             : {
    3169        1502 :         Py_CLEAR(self->state.exception);
    3170        1502 :         TALLOC_FREE(self->mem_ctx);
    3171        1502 :         ZERO_STRUCT(self->state);
    3172        1502 :         Py_CLEAR(self->ldb);
    3173        1502 :         Py_TYPE(self)->tp_free(self);
    3174        1502 : }
    3175             : 
    3176       16274 : static PyObject *py_ldb_search_iterator_next(PyLdbSearchIteratorObject *self)
    3177             : {
    3178       16274 :         PyObject *py_ret = NULL;
    3179             : 
    3180       16274 :         if (self->state.req == NULL) {
    3181           4 :                 PyErr_SetString(PyExc_RuntimeError,
    3182             :                                 "ldb.SearchIterator request already finished");
    3183           4 :                 return NULL;
    3184             :         }
    3185             : 
    3186             :         /*
    3187             :          * TODO: do we want a non-blocking mode?
    3188             :          * In future we may add an optional 'nonblocking'
    3189             :          * argument to search_iterator().
    3190             :          *
    3191             :          * For now we keep it simple and wait for at
    3192             :          * least one reply.
    3193             :          */
    3194             : 
    3195     3485725 :         while (self->state.next == NULL) {
    3196           0 :                 int ret;
    3197             : 
    3198     3470871 :                 if (self->state.result != NULL) {
    3199             :                         /*
    3200             :                          * We (already) got a final result from the server.
    3201             :                          *
    3202             :                          * We stop the iteration and let
    3203             :                          * py_ldb_search_iterator_result() will deliver
    3204             :                          * the result details.
    3205             :                          */
    3206          49 :                         TALLOC_FREE(self->state.req);
    3207          49 :                         PyErr_SetNone(PyExc_StopIteration);
    3208          49 :                         return NULL;
    3209             :                 }
    3210             : 
    3211     3470822 :                 ret = ldb_wait(self->state.req->handle, LDB_WAIT_NONE);
    3212     3470822 :                 if (ret != LDB_SUCCESS) {
    3213           0 :                         struct ldb_context *ldb_ctx;
    3214        1367 :                         TALLOC_FREE(self->state.req);
    3215        1367 :                         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(self->ldb);
    3216             :                         /*
    3217             :                          * We stop the iteration and let
    3218             :                          * py_ldb_search_iterator_result() will deliver
    3219             :                          * the exception.
    3220             :                          */
    3221        1367 :                         self->state.exception = Py_BuildValue(discard_const_p(char, "(i,s)"),
    3222             :                                                 ret, ldb_errstring(ldb_ctx));
    3223        1367 :                         PyErr_SetNone(PyExc_StopIteration);
    3224        1367 :                         return NULL;
    3225             :                 }
    3226             :         }
    3227             : 
    3228       14854 :         py_ret = self->state.next->obj;
    3229       14854 :         self->state.next->obj = NULL;
    3230             :         /* no TALLOC_FREE() as self->state.next is a list */
    3231       14854 :         talloc_free(self->state.next);
    3232       14854 :         return py_ret;
    3233             : }
    3234             : 
    3235        1398 : static PyObject *py_ldb_search_iterator_result(PyLdbSearchIteratorObject *self,
    3236             :                 PyObject *Py_UNUSED(ignored))
    3237             : {
    3238        1398 :         PyObject *py_ret = NULL;
    3239             : 
    3240        1398 :         if (self->state.req != NULL) {
    3241           4 :                 PyErr_SetString(PyExc_RuntimeError,
    3242             :                                 "ldb.SearchIterator request running");
    3243           4 :                 return NULL;
    3244             :         }
    3245             : 
    3246        1394 :         if (self->state.next != NULL) {
    3247           0 :                 PyErr_SetString(PyExc_RuntimeError,
    3248             :                                 "ldb.SearchIterator not fully consumed.");
    3249           0 :                 return NULL;
    3250             :         }
    3251             : 
    3252        1394 :         if (self->state.exception != NULL) {
    3253        1357 :                 PyErr_SetObject(PyExc_LdbError, self->state.exception);
    3254        1357 :                 Py_DECREF(self->state.exception);
    3255        1357 :                 self->state.exception = NULL;
    3256        1357 :                 return NULL;
    3257             :         }
    3258             : 
    3259          37 :         if (self->state.result == NULL) {
    3260           4 :                 PyErr_SetString(PyExc_RuntimeError,
    3261             :                                 "ldb.SearchIterator result already consumed");
    3262           4 :                 return NULL;
    3263             :         }
    3264             : 
    3265          33 :         py_ret = self->state.result->obj;
    3266          33 :         self->state.result->obj = NULL;
    3267          33 :         TALLOC_FREE(self->state.result);
    3268          33 :         return py_ret;
    3269             : }
    3270             : 
    3271           8 : static PyObject *py_ldb_search_iterator_abandon(PyLdbSearchIteratorObject *self,
    3272             :                 PyObject *Py_UNUSED(ignored))
    3273             : {
    3274           8 :         if (self->state.req == NULL) {
    3275           4 :                 PyErr_SetString(PyExc_RuntimeError,
    3276             :                                 "ldb.SearchIterator request already finished");
    3277           4 :                 return NULL;
    3278             :         }
    3279             : 
    3280           4 :         Py_CLEAR(self->state.exception);
    3281           4 :         TALLOC_FREE(self->mem_ctx);
    3282           4 :         ZERO_STRUCT(self->state);
    3283           4 :         Py_RETURN_NONE;
    3284             : }
    3285             : 
    3286             : static PyMethodDef py_ldb_search_iterator_methods[] = {
    3287             :         { "result", (PyCFunction)py_ldb_search_iterator_result, METH_NOARGS,
    3288             :                 "S.result() -> ldb.Result (without msgs and referrals)\n" },
    3289             :         { "abandon", (PyCFunction)py_ldb_search_iterator_abandon, METH_NOARGS,
    3290             :                 "S.abandon()\n" },
    3291             :         {0}
    3292             : };
    3293             : 
    3294           0 : static PyObject *py_ldb_search_iterator_repr(PyLdbSearchIteratorObject *self)
    3295             : {
    3296           0 :         return PyUnicode_FromString("<ldb search iterator>");
    3297             : }
    3298             : 
    3299             : static PyTypeObject PyLdbSearchIterator = {
    3300             :         .tp_name = "ldb.SearchIterator",
    3301             :         .tp_repr = (reprfunc)py_ldb_search_iterator_repr,
    3302             :         .tp_dealloc = (destructor)py_ldb_search_iterator_dealloc,
    3303             :         .tp_iter = PyObject_SelfIter,
    3304             :         .tp_iternext = (iternextfunc)py_ldb_search_iterator_next,
    3305             :         .tp_methods = py_ldb_search_iterator_methods,
    3306             :         .tp_basicsize = sizeof(PyLdbSearchIteratorObject),
    3307             :         .tp_doc = "LDB search_iterator.",
    3308             :         .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
    3309             : };
    3310             : 
    3311             : /**
    3312             :  * Create a ldb_message_element from a Python object.
    3313             :  *
    3314             :  * This will accept any sequence objects that contains strings, or
    3315             :  * a string object.
    3316             :  *
    3317             :  * A reference to set_obj might be borrowed.
    3318             :  *
    3319             :  * @param mem_ctx Memory context
    3320             :  * @param set_obj Python object to convert
    3321             :  * @param flags ldb_message_element flags to set, if a new element is returned
    3322             :  * @param attr_name Name of the attribute to set, if a new element is returned
    3323             :  * @return New ldb_message_element, allocated as child of mem_ctx
    3324             :  */
    3325      930997 : static struct ldb_message_element *PyObject_AsMessageElement(
    3326             :                                                       TALLOC_CTX *mem_ctx,
    3327             :                                                       PyObject *set_obj,
    3328             :                                                       unsigned int flags,
    3329             :                                                       const char *attr_name)
    3330             : {
    3331       21317 :         struct ldb_message_element *me;
    3332      930997 :         const char *msg = NULL;
    3333       21317 :         Py_ssize_t size;
    3334       21317 :         int result;
    3335             : 
    3336      930997 :         if (pyldb_MessageElement_Check(set_obj)) {
    3337      333035 :                 PyLdbMessageElementObject *set_obj_as_me = (PyLdbMessageElementObject *)set_obj;
    3338             :                 /* We have to talloc_reference() the memory context, not the pointer
    3339             :                  * which may not actually be it's own context */
    3340      333035 :                 if (talloc_reference(mem_ctx, set_obj_as_me->mem_ctx)) {
    3341      333035 :                         return pyldb_MessageElement_AsMessageElement(set_obj);
    3342             :                 }
    3343           0 :                 return NULL;
    3344             :         }
    3345             : 
    3346      597962 :         me = talloc(mem_ctx, struct ldb_message_element);
    3347      597962 :         if (me == NULL) {
    3348           0 :                 PyErr_NoMemory();
    3349           0 :                 return NULL;
    3350             :         }
    3351             : 
    3352      597962 :         me->name = talloc_strdup(me, attr_name);
    3353      597962 :         if (me->name == NULL) {
    3354           0 :                 PyErr_NoMemory();
    3355           0 :                 talloc_free(me);
    3356           0 :                 return NULL;
    3357             :         }
    3358      597962 :         me->flags = flags;
    3359      597962 :         if (PyBytes_Check(set_obj) || PyUnicode_Check(set_obj)) {
    3360      577133 :                 me->num_values = 1;
    3361      577133 :                 me->values = talloc_array(me, struct ldb_val, me->num_values);
    3362      577133 :                 if (PyBytes_Check(set_obj)) {
    3363      224237 :                         char *_msg = NULL;
    3364      224237 :                         result = PyBytes_AsStringAndSize(set_obj, &_msg, &size);
    3365      224237 :                         if (result != 0) {
    3366           0 :                                 talloc_free(me);
    3367           0 :                                 return NULL;
    3368             :                         }
    3369      224237 :                         msg = _msg;
    3370             :                 } else {
    3371      352896 :                         msg = PyUnicode_AsUTF8AndSize(set_obj, &size);
    3372      352896 :                         if (msg == NULL) {
    3373           0 :                                 talloc_free(me);
    3374           0 :                                 return NULL;
    3375             :                         }
    3376             :                 }
    3377      577133 :                 me->values[0].data = talloc_memdup(me,
    3378             :                                                    (const uint8_t *)msg,
    3379             :                                                    size+1);
    3380      577133 :                 me->values[0].length = size;
    3381       20829 :         } else if (PySequence_Check(set_obj)) {
    3382        2031 :                 Py_ssize_t i;
    3383       20829 :                 me->num_values = PySequence_Size(set_obj);
    3384       20829 :                 me->values = talloc_array(me, struct ldb_val, me->num_values);
    3385       61282 :                 for (i = 0; i < me->num_values; i++) {
    3386       40453 :                         PyObject *obj = PySequence_GetItem(set_obj, i);
    3387       40453 :                         if (PyBytes_Check(obj)) {
    3388       15784 :                                 char *_msg = NULL;
    3389       15784 :                                 result = PyBytes_AsStringAndSize(obj, &_msg, &size);
    3390       15784 :                                 if (result != 0) {
    3391           0 :                                         talloc_free(me);
    3392           0 :                                         return NULL;
    3393             :                                 }
    3394       15784 :                                 msg = _msg;
    3395       24669 :                         } else if (PyUnicode_Check(obj)) {
    3396       24669 :                                 msg = PyUnicode_AsUTF8AndSize(obj, &size);
    3397       24669 :                                 if (msg == NULL) {
    3398           0 :                                         talloc_free(me);
    3399           0 :                                         return NULL;
    3400             :                                 }
    3401             :                         } else {
    3402           0 :                                 PyErr_Format(PyExc_TypeError,
    3403             :                                              "Expected string as element %zd in list", i);
    3404           0 :                                 talloc_free(me);
    3405           0 :                                 return NULL;
    3406             :                         }
    3407       40453 :                         me->values[i].data = talloc_memdup(me,
    3408             :                                                            (const uint8_t *)msg,
    3409             :                                                            size+1);
    3410       40453 :                         me->values[i].length = size;
    3411             :                 }
    3412             :         } else {
    3413           0 :                 PyErr_Format(PyExc_TypeError,
    3414             :                              "String or List type expected for '%s' attribute", attr_name);
    3415           0 :                 talloc_free(me);
    3416           0 :                 me = NULL;
    3417             :         }
    3418             : 
    3419      593949 :         return me;
    3420             : }
    3421             : 
    3422             : 
    3423    26010360 : static PyObject *ldb_msg_element_to_set(struct ldb_context *ldb_ctx,
    3424             :                                         struct ldb_message_element *me)
    3425             : {
    3426     2980873 :         Py_ssize_t i;
    3427     2980873 :         PyObject *result;
    3428             : 
    3429             :         /* Python << 2.5 doesn't have PySet_New and PySet_Add. */
    3430    26010360 :         result = PyList_New(me->num_values);
    3431    26010360 :         if (result == NULL) {
    3432           0 :                 return NULL;
    3433             :         }
    3434             : 
    3435    59613123 :         for (i = 0; i < me->num_values; i++) {
    3436    33602763 :                 PyObject *obj = NULL;
    3437     3985343 :                 int ret;
    3438             : 
    3439    33602763 :                 obj = PyObject_FromLdbValue(&me->values[i]);
    3440    33602763 :                 if (obj == NULL) {
    3441           0 :                         Py_DECREF(result);
    3442           0 :                         return NULL;
    3443             :                 }
    3444             : 
    3445    33602763 :                 ret = PyList_SetItem(result, i, obj);
    3446    33602763 :                 if (ret) {
    3447           0 :                         Py_DECREF(obj);
    3448           0 :                         Py_DECREF(result);
    3449           0 :                         return NULL;
    3450             :                 }
    3451             :         }
    3452             : 
    3453    23029487 :         return result;
    3454             : }
    3455             : 
    3456           0 : static PyObject *py_ldb_msg_element_get(PyLdbMessageElementObject *self, PyObject *args)
    3457             : {
    3458           0 :         unsigned int i;
    3459           0 :         if (!PyArg_ParseTuple(args, "I", &i))
    3460           0 :                 return NULL;
    3461           0 :         if (i >= pyldb_MessageElement_AsMessageElement(self)->num_values)
    3462           0 :                 Py_RETURN_NONE;
    3463             : 
    3464           0 :         return PyObject_FromLdbValue(&(pyldb_MessageElement_AsMessageElement(self)->values[i]));
    3465             : }
    3466             : 
    3467          46 : static PyObject *py_ldb_msg_element_flags(PyLdbMessageElementObject *self, PyObject *args)
    3468             : {
    3469          46 :         struct ldb_message_element *el = pyldb_MessageElement_AsMessageElement(self);
    3470          46 :         return PyLong_FromLong(el->flags);
    3471             : }
    3472             : 
    3473        5275 : static PyObject *py_ldb_msg_element_set_flags(PyLdbMessageElementObject *self, PyObject *args)
    3474             : {
    3475          22 :         unsigned int flags;
    3476          22 :         struct ldb_message_element *el;
    3477        5275 :         if (!PyArg_ParseTuple(args, "I", &flags))
    3478           0 :                 return NULL;
    3479             : 
    3480        5275 :         el = pyldb_MessageElement_AsMessageElement(self);
    3481        5275 :         el->flags = flags;
    3482        5275 :         Py_RETURN_NONE;
    3483             : }
    3484             : 
    3485             : static PyMethodDef py_ldb_msg_element_methods[] = {
    3486             :         { "get", (PyCFunction)py_ldb_msg_element_get, METH_VARARGS, NULL },
    3487             :         { "set_flags", (PyCFunction)py_ldb_msg_element_set_flags, METH_VARARGS, NULL },
    3488             :         { "flags", (PyCFunction)py_ldb_msg_element_flags, METH_NOARGS, NULL },
    3489             :         {0},
    3490             : };
    3491             : 
    3492    28401928 : static Py_ssize_t py_ldb_msg_element_len(PyLdbMessageElementObject *self)
    3493             : {
    3494    28401928 :         return pyldb_MessageElement_AsMessageElement(self)->num_values;
    3495             : }
    3496             : 
    3497    20036961 : static PyObject *py_ldb_msg_element_find(PyLdbMessageElementObject *self, Py_ssize_t idx)
    3498             : {
    3499    20036961 :         struct ldb_message_element *el = pyldb_MessageElement_AsMessageElement(self);
    3500    20036961 :         if (idx < 0 || idx >= el->num_values) {
    3501           4 :                 PyErr_SetString(PyExc_IndexError, "Out of range");
    3502           4 :                 return NULL;
    3503             :         }
    3504    20036957 :         return PyLdbBytes_FromStringAndSize((char *)el->values[idx].data, el->values[idx].length);
    3505             : }
    3506             : 
    3507             : static PySequenceMethods py_ldb_msg_element_seq = {
    3508             :         .sq_length = (lenfunc)py_ldb_msg_element_len,
    3509             :         .sq_item = (ssizeargfunc)py_ldb_msg_element_find,
    3510             : };
    3511             : 
    3512         377 : static PyObject *py_ldb_msg_element_richcmp(PyObject *self, PyObject *other, int op)
    3513             : {
    3514          12 :         int ret;
    3515         377 :         if (!pyldb_MessageElement_Check(other)) {
    3516         192 :                 Py_INCREF(Py_NotImplemented);
    3517         211 :                 return Py_NotImplemented;
    3518             :         }
    3519         166 :         ret = ldb_msg_element_compare(pyldb_MessageElement_AsMessageElement(self),
    3520             :                                                                           pyldb_MessageElement_AsMessageElement(other));
    3521         166 :         return richcmp(ret, op);
    3522             : }
    3523             : 
    3524    26010360 : static PyObject *py_ldb_msg_element_iter(PyLdbMessageElementObject *self)
    3525             : {
    3526    26010360 :         PyObject *el = ldb_msg_element_to_set(NULL,
    3527             :                                               pyldb_MessageElement_AsMessageElement(self));
    3528    26010360 :         PyObject *ret = PyObject_GetIter(el);
    3529    22883719 :         Py_DECREF(el);
    3530    26010360 :         return ret;
    3531             : }
    3532             : 
    3533    44711083 : static PyObject *PyLdbMessageElement_FromMessageElement(struct ldb_message_element *el, TALLOC_CTX *mem_ctx)
    3534             : {
    3535    44711083 :         TALLOC_CTX *ret_mem_ctx = NULL;
    3536     5368830 :         PyLdbMessageElementObject *ret;
    3537             : 
    3538    44711083 :         ret_mem_ctx = talloc_new(NULL);
    3539    44711083 :         if (ret_mem_ctx == NULL) {
    3540           0 :                 return PyErr_NoMemory();
    3541             :         }
    3542             : 
    3543    44711083 :         if (talloc_reference(ret_mem_ctx, mem_ctx) == NULL) {
    3544           0 :                 talloc_free(ret_mem_ctx);
    3545           0 :                 PyErr_NoMemory();
    3546           0 :                 return NULL;
    3547             :         }
    3548             : 
    3549    44711083 :         ret = PyObject_New(PyLdbMessageElementObject, &PyLdbMessageElement);
    3550    44711083 :         if (ret == NULL) {
    3551           0 :                 talloc_free(ret_mem_ctx);
    3552           0 :                 PyErr_NoMemory();
    3553           0 :                 return NULL;
    3554             :         }
    3555    44711083 :         ret->mem_ctx = ret_mem_ctx;
    3556    44711083 :         ret->el = el;
    3557    44711083 :         return (PyObject *)ret;
    3558             : }
    3559             : 
    3560      330641 : static PyObject *py_ldb_msg_element_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
    3561             : {
    3562      330641 :         PyObject *py_elements = NULL;
    3563       17334 :         struct ldb_message_element *el;
    3564      330641 :         unsigned int flags = 0;
    3565      330641 :         char *name = NULL;
    3566      330641 :         const char * const kwnames[] = { "elements", "flags", "name", NULL };
    3567       17334 :         PyLdbMessageElementObject *ret;
    3568       17334 :         TALLOC_CTX *mem_ctx;
    3569      330641 :         const char *msg = NULL;
    3570       17334 :         Py_ssize_t size;
    3571       17334 :         int result;
    3572             : 
    3573      330641 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OIs",
    3574             :                                          discard_const_p(char *, kwnames),
    3575             :                                          &py_elements, &flags, &name))
    3576           0 :                 return NULL;
    3577             : 
    3578      330641 :         mem_ctx = talloc_new(NULL);
    3579      330641 :         if (mem_ctx == NULL) {
    3580           0 :                 PyErr_NoMemory();
    3581           0 :                 return NULL;
    3582             :         }
    3583             : 
    3584      330641 :         el = talloc_zero(mem_ctx, struct ldb_message_element);
    3585      330641 :         if (el == NULL) {
    3586           0 :                 PyErr_NoMemory();
    3587           0 :                 talloc_free(mem_ctx);
    3588           0 :                 return NULL;
    3589             :         }
    3590             : 
    3591      330641 :         if (py_elements != NULL) {
    3592       17334 :                 Py_ssize_t i;
    3593      330641 :                 if (PyBytes_Check(py_elements) || PyUnicode_Check(py_elements)) {
    3594      317690 :                         char *_msg = NULL;
    3595      317690 :                         el->num_values = 1;
    3596      317690 :                         el->values = talloc_array(el, struct ldb_val, 1);
    3597      317690 :                         if (el->values == NULL) {
    3598           0 :                                 talloc_free(mem_ctx);
    3599           0 :                                 PyErr_NoMemory();
    3600           0 :                                 return NULL;
    3601             :                         }
    3602      317690 :                         if (PyBytes_Check(py_elements)) {
    3603       87117 :                                 result = PyBytes_AsStringAndSize(py_elements, &_msg, &size);
    3604       87117 :                                 msg = _msg;
    3605             :                         } else {
    3606      230573 :                                 msg = PyUnicode_AsUTF8AndSize(py_elements, &size);
    3607      230573 :                                 result = (msg == NULL) ? -1 : 0;
    3608             :                         }
    3609      317690 :                         if (result != 0) {
    3610           0 :                                 talloc_free(mem_ctx);
    3611           0 :                                 return NULL;
    3612             :                         }
    3613      317690 :                         el->values[0].data = talloc_memdup(el->values,
    3614             :                                 (const uint8_t *)msg, size + 1);
    3615      317690 :                         el->values[0].length = size;
    3616       12951 :                 } else if (PySequence_Check(py_elements)) {
    3617       12951 :                         el->num_values = PySequence_Size(py_elements);
    3618       12951 :                         el->values = talloc_array(el, struct ldb_val, el->num_values);
    3619       12951 :                         if (el->values == NULL) {
    3620           0 :                                 talloc_free(mem_ctx);
    3621           0 :                                 PyErr_NoMemory();
    3622           0 :                                 return NULL;
    3623             :                         }
    3624       33639 :                         for (i = 0; i < el->num_values; i++) {
    3625       20688 :                                 PyObject *item = PySequence_GetItem(py_elements, i);
    3626       20688 :                                 if (item == NULL) {
    3627           0 :                                         talloc_free(mem_ctx);
    3628           0 :                                         return NULL;
    3629             :                                 }
    3630       20688 :                                 if (PyBytes_Check(item)) {
    3631       10919 :                                         char *_msg = NULL;
    3632       10919 :                                         result = PyBytes_AsStringAndSize(item, &_msg, &size);
    3633       10919 :                                         msg = _msg;
    3634        9769 :                                 } else if (PyUnicode_Check(item)) {
    3635        9769 :                                         msg = PyUnicode_AsUTF8AndSize(item, &size);
    3636        9769 :                                         result = (msg == NULL) ? -1 : 0;
    3637             :                                 } else {
    3638           0 :                                         PyErr_Format(PyExc_TypeError,
    3639             :                                                      "Expected string as element %zd in list", i);
    3640           0 :                                         result = -1;
    3641             :                                 }
    3642       20688 :                                 if (result != 0) {
    3643           0 :                                         talloc_free(mem_ctx);
    3644           0 :                                         return NULL;
    3645             :                                 }
    3646       20688 :                                 el->values[i].data = talloc_memdup(el,
    3647             :                                         (const uint8_t *)msg, size+1);
    3648       20688 :                                 el->values[i].length = size;
    3649             :                         }
    3650             :                 } else {
    3651           0 :                         PyErr_SetString(PyExc_TypeError,
    3652             :                                         "Expected string or list");
    3653           0 :                         talloc_free(mem_ctx);
    3654           0 :                         return NULL;
    3655             :                 }
    3656             :         }
    3657             : 
    3658      330641 :         el->flags = flags;
    3659      330641 :         if (name != NULL) {
    3660      330493 :                 el->name = talloc_strdup(el, name);
    3661      330493 :                 if (el->name == NULL) {
    3662           0 :                         talloc_free(mem_ctx);
    3663           0 :                         return PyErr_NoMemory();
    3664             :                 }
    3665             :         }
    3666             : 
    3667      330641 :         ret = PyObject_New(PyLdbMessageElementObject, type);
    3668      330641 :         if (ret == NULL) {
    3669           0 :                 talloc_free(mem_ctx);
    3670           0 :                 return NULL;
    3671             :         }
    3672             : 
    3673      330641 :         ret->mem_ctx = mem_ctx;
    3674      330641 :         ret->el = el;
    3675      330641 :         return (PyObject *)ret;
    3676             : }
    3677             : 
    3678       58454 : static PyObject *py_ldb_msg_element_repr(PyLdbMessageElementObject *self)
    3679             : {
    3680       58454 :         char *element_str = NULL;
    3681           0 :         Py_ssize_t i;
    3682       58454 :         struct ldb_message_element *el = pyldb_MessageElement_AsMessageElement(self);
    3683           0 :         PyObject *ret, *repr;
    3684             : 
    3685      116930 :         for (i = 0; i < el->num_values; i++) {
    3686       58476 :                 PyObject *o = py_ldb_msg_element_find(self, i);
    3687       58476 :                 repr = PyObject_Repr(o);
    3688       58476 :                 if (element_str == NULL)
    3689       58454 :                         element_str = talloc_strdup(NULL, PyUnicode_AsUTF8(repr));
    3690             :                 else
    3691          22 :                         element_str = talloc_asprintf_append(element_str, ",%s", PyUnicode_AsUTF8(repr));
    3692       36870 :                 Py_DECREF(repr);
    3693             : 
    3694       58476 :                 if (element_str == NULL) {
    3695           0 :                         return PyErr_NoMemory();
    3696             :                 }
    3697             :         }
    3698             : 
    3699       58454 :         if (element_str != NULL) {
    3700       58454 :                 ret = PyUnicode_FromFormat("MessageElement([%s])", element_str);
    3701       58454 :                 talloc_free(element_str);
    3702             :         } else {
    3703           0 :                 ret = PyUnicode_FromString("MessageElement([])");
    3704             :         }
    3705             : 
    3706       58454 :         return ret;
    3707             : }
    3708             : 
    3709       84979 : static PyObject *py_ldb_msg_element_str(PyLdbMessageElementObject *self)
    3710             : {
    3711       84979 :         struct ldb_message_element *el = pyldb_MessageElement_AsMessageElement(self);
    3712             : 
    3713       84979 :         if (el->num_values == 1)
    3714       84979 :                 return PyUnicode_FromStringAndSize((char *)el->values[0].data, el->values[0].length);
    3715             :         else
    3716           0 :                 Py_RETURN_NONE;
    3717             : }
    3718             : 
    3719    55928914 : static void py_ldb_msg_element_dealloc(PyLdbMessageElementObject *self)
    3720             : {
    3721    55928914 :         talloc_free(self->mem_ctx);
    3722    55928914 :         PyObject_Del(self);
    3723    55928914 : }
    3724             : 
    3725          18 : static PyObject *py_ldb_msg_element_get_text(PyObject *self, void *closure)
    3726             : {
    3727          18 :         return wrap_text("MessageElementTextWrapper", self);
    3728             : }
    3729             : 
    3730             : static PyGetSetDef py_ldb_msg_element_getset[] = {
    3731             :         {
    3732             :                 .name = discard_const_p(char, "text"),
    3733             :                 .get  = (getter)py_ldb_msg_element_get_text,
    3734             :         },
    3735             :         { .name = NULL }
    3736             : };
    3737             : 
    3738             : static PyTypeObject PyLdbMessageElement = {
    3739             :         .tp_name = "ldb.MessageElement",
    3740             :         .tp_basicsize = sizeof(PyLdbMessageElementObject),
    3741             :         .tp_dealloc = (destructor)py_ldb_msg_element_dealloc,
    3742             :         .tp_repr = (reprfunc)py_ldb_msg_element_repr,
    3743             :         .tp_str = (reprfunc)py_ldb_msg_element_str,
    3744             :         .tp_methods = py_ldb_msg_element_methods,
    3745             :         .tp_getset = py_ldb_msg_element_getset,
    3746             :         .tp_richcompare = (richcmpfunc)py_ldb_msg_element_richcmp,
    3747             :         .tp_iter = (getiterfunc)py_ldb_msg_element_iter,
    3748             :         .tp_as_sequence = &py_ldb_msg_element_seq,
    3749             :         .tp_new = py_ldb_msg_element_new,
    3750             :         .tp_flags = Py_TPFLAGS_DEFAULT,
    3751             :         .tp_doc = "An element of a Message",
    3752             : };
    3753             : 
    3754             : 
    3755        2501 : static PyObject *py_ldb_msg_from_dict(PyTypeObject *type, PyObject *args)
    3756             : {
    3757           0 :         PyObject *py_ldb;
    3758           0 :         PyObject *py_dict;
    3759           0 :         PyObject *py_ret;
    3760           0 :         struct ldb_message *msg;
    3761           0 :         struct ldb_context *ldb_ctx;
    3762        2501 :         unsigned int mod_flags = LDB_FLAG_MOD_REPLACE;
    3763             : 
    3764        2501 :         if (!PyArg_ParseTuple(args, "O!O!|I",
    3765             :                               &PyLdb, &py_ldb, &PyDict_Type, &py_dict,
    3766             :                               &mod_flags)) {
    3767           8 :                 return NULL;
    3768             :         }
    3769             : 
    3770             :         /* mask only flags we are going to use */
    3771        2493 :         mod_flags = LDB_FLAG_MOD_TYPE(mod_flags);
    3772        2493 :         if (!mod_flags) {
    3773           4 :                 PyErr_SetString(PyExc_ValueError,
    3774             :                                 "FLAG_MOD_ADD, FLAG_MOD_REPLACE or FLAG_MOD_DELETE"
    3775             :                                 " expected as mod_flag value");
    3776           4 :                 return NULL;
    3777             :         }
    3778             : 
    3779        2489 :         ldb_ctx = pyldb_Ldb_AS_LDBCONTEXT(py_ldb);
    3780             : 
    3781        2489 :         msg = PyDict_AsMessage(ldb_ctx, py_dict, ldb_ctx, mod_flags);
    3782        2489 :         if (!msg) {
    3783           4 :                 return NULL;
    3784             :         }
    3785             : 
    3786        2485 :         py_ret = PyLdbMessage_FromMessage(msg, (PyLdbObject *)py_ldb);
    3787             : 
    3788        2485 :         talloc_unlink(ldb_ctx, msg);
    3789             : 
    3790        2485 :         return py_ret;
    3791             : }
    3792             : 
    3793             : 
    3794             : #define pyldb_Message_as_message(pyobj) ((PyLdbMessageObject *)pyobj)->msg
    3795             : 
    3796             : #define pyldb_Message_get_pyldb(pyobj) ((PyLdbMessageObject *)pyobj)->pyldb
    3797             : 
    3798             : /*
    3799             :  * PyErr_LDB_MESSAGE_OR_RAISE does 3 things:
    3800             :  * 1. checks that a PyObject is really a PyLdbMessageObject.
    3801             :  * 2. checks that the ldb that the PyLdbMessageObject knows is the ldb that
    3802             :  *    its dn knows -- but only if the underlying message has a DN.
    3803             :  * 3. sets message to the relevant struct ldb_message *.
    3804             :  *
    3805             :  * We need to do all this to ensure the message belongs to the right
    3806             :  * ldb, lest it be freed before we are ready.
    3807             :  */
    3808             : #define PyErr_LDB_MESSAGE_OR_RAISE(_py_obj, message) do {               \
    3809             :         PyLdbMessageObject *_py_message = NULL;                 \
    3810             :         struct ldb_dn *_dn = NULL;                                      \
    3811             :         if (_py_obj == NULL || !pyldb_Message_Check(_py_obj)) {         \
    3812             :                 PyErr_SetString(PyExc_TypeError,                        \
    3813             :                                 "ldb Message object required");       \
    3814             :                 return NULL;                                            \
    3815             :         }                                                               \
    3816             :         _py_message = (PyLdbMessageObject *)_py_obj;                    \
    3817             :         message = pyldb_Message_as_message(_py_message);                \
    3818             :         _dn = message->dn;                                           \
    3819             :         if (_dn != NULL &&                                              \
    3820             :             (_py_message->pyldb->ldb_ctx != ldb_dn_get_ldb_context(_dn))) { \
    3821             :                 PyErr_SetString(PyExc_RuntimeError,                     \
    3822             :                                 "Message has a stale LDB connection");        \
    3823             :                 return NULL;                                            \
    3824             :         }                                                               \
    3825             : } while(0)
    3826             : 
    3827             : 
    3828      751882 : static PyObject *py_ldb_msg_remove_attr(PyObject *self, PyObject *args)
    3829             : {
    3830         182 :         char *name;
    3831      751882 :         struct ldb_message *msg = NULL;
    3832      752064 :         PyErr_LDB_MESSAGE_OR_RAISE(self, msg);
    3833             : 
    3834      751882 :         if (!PyArg_ParseTuple(args, "s", &name)) {
    3835           0 :                 return NULL;
    3836             :         }
    3837             : 
    3838      751882 :         ldb_msg_remove_attr(msg, name);
    3839             : 
    3840      751882 :         Py_RETURN_NONE;
    3841             : }
    3842             : 
    3843     2912396 : static PyObject *py_ldb_msg_keys(PyObject *self,
    3844             :                 PyObject *Py_UNUSED(ignored))
    3845             : {
    3846     2912396 :         struct ldb_message *msg = NULL;
    3847     2912396 :         Py_ssize_t i, j = 0;
    3848     2912396 :         PyObject *obj = NULL;
    3849             : 
    3850     3157558 :         PyErr_LDB_MESSAGE_OR_RAISE(self, msg);
    3851             : 
    3852     2912398 :         obj = PyList_New(msg->num_elements+(msg->dn != NULL?1:0));
    3853     2912396 :         if (obj == NULL) {
    3854           0 :                 return NULL;
    3855             :         }
    3856             : 
    3857     2912396 :         if (msg->dn != NULL) {
    3858     2912393 :                 PyObject *py_dn = NULL;
    3859      245160 :                 int ret;
    3860             : 
    3861     2912393 :                 py_dn = PyUnicode_FromString("dn");
    3862     2912393 :                 if (py_dn == NULL) {
    3863           0 :                         Py_DECREF(obj);
    3864           0 :                         return NULL;
    3865             :                 }
    3866             : 
    3867     2912393 :                 ret = PyList_SetItem(obj, j, py_dn);
    3868     2912393 :                 if (ret) {
    3869           0 :                         Py_DECREF(py_dn);
    3870           0 :                         Py_DECREF(obj);
    3871           0 :                         return NULL;
    3872             :                 }
    3873             : 
    3874     2667233 :                 j++;
    3875             :         }
    3876    32339507 :         for (i = 0; i < msg->num_elements; i++) {
    3877    29427111 :                 PyObject *py_name = NULL;
    3878     3350065 :                 int ret;
    3879             : 
    3880    29427111 :                 py_name = PyUnicode_FromString(msg->elements[i].name);
    3881    29427111 :                 if (py_name == NULL) {
    3882           0 :                         Py_DECREF(obj);
    3883           0 :                         return NULL;
    3884             :                 }
    3885             : 
    3886    29427111 :                 ret = PyList_SetItem(obj, j, py_name);
    3887    29427111 :                 if (ret) {
    3888           0 :                         Py_DECREF(py_name);
    3889           0 :                         Py_DECREF(obj);
    3890           0 :                         return NULL;
    3891             :                 }
    3892             : 
    3893    29427111 :                 j++;
    3894             :         }
    3895     2667234 :         return obj;
    3896             : }
    3897             : 
    3898     2271162 : static int py_ldb_msg_contains(PyLdbMessageObject *self, PyObject *py_name)
    3899             : {
    3900     2271162 :         struct ldb_message_element *el = NULL;
    3901     2271162 :         const char *name = NULL;
    3902     2271162 :         struct ldb_message *msg = pyldb_Message_as_message(self);
    3903     2271162 :         struct ldb_dn *dn = msg->dn;
    3904             : 
    3905     2271162 :         if (dn != NULL && (self->pyldb->ldb_ctx != ldb_dn_get_ldb_context(dn))) {
    3906           0 :                 return -1;
    3907             :         }
    3908             : 
    3909     2271162 :         name = PyUnicode_AsUTF8(py_name);
    3910     2271162 :         if (name == NULL) {
    3911           2 :                 return -1;
    3912             :         }
    3913     2271160 :         if (!ldb_attr_cmp(name, "dn")) {
    3914        1914 :                 return 1;
    3915             :         }
    3916     2269246 :         el = ldb_msg_find_element(msg, name);
    3917     2269246 :         return el != NULL ? 1 : 0;
    3918             : }
    3919             : 
    3920    45310117 : static PyObject *py_ldb_msg_getitem(PyObject *self, PyObject *py_name)
    3921             : {
    3922    45310117 :         struct ldb_message_element *el = NULL;
    3923    45310117 :         const char *name = NULL;
    3924    45310117 :         struct ldb_message *msg = NULL;
    3925    50674122 :         PyErr_LDB_MESSAGE_OR_RAISE(self, msg);
    3926             : 
    3927    45310117 :         name = PyUnicode_AsUTF8(py_name);
    3928    45310117 :         if (name == NULL) {
    3929           2 :                 return NULL;
    3930             :         }
    3931    45310115 :         if (!ldb_attr_cmp(name, "dn")) {
    3932      672399 :                 return pyldb_Dn_FromDn(msg->dn, pyldb_Message_get_pyldb(self));
    3933             :         }
    3934    44637716 :         el = ldb_msg_find_element(msg, name);
    3935    44637716 :         if (el == NULL) {
    3936        1127 :                 PyErr_SetString(PyExc_KeyError, "No such element");
    3937        1127 :                 return NULL;
    3938             :         }
    3939             : 
    3940    44636589 :         return PyLdbMessageElement_FromMessageElement(el, msg->elements);
    3941             : }
    3942             : 
    3943       99818 : static PyObject *py_ldb_msg_get(PyObject *self, PyObject *args, PyObject *kwargs)
    3944             : {
    3945       99818 :         PyObject *def = NULL;
    3946       99818 :         const char *kwnames[] = { "name", "default", "idx", NULL };
    3947       99818 :         const char *name = NULL;
    3948       99818 :         int idx = -1;
    3949        5469 :         struct ldb_message_element *el;
    3950       99818 :         struct ldb_message *msg = NULL;
    3951      105287 :         PyErr_LDB_MESSAGE_OR_RAISE(self, msg);
    3952             : 
    3953       99818 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|Oi:msg",
    3954             :                                          discard_const_p(char *, kwnames), &name, &def, &idx)) {
    3955           2 :                 return NULL;
    3956             :         }
    3957             : 
    3958       99816 :         if (strcasecmp(name, "dn") == 0) {
    3959         755 :                 return pyldb_Dn_FromDn(msg->dn, pyldb_Message_get_pyldb(self));
    3960             :         }
    3961             : 
    3962       99061 :         el = ldb_msg_find_element(msg, name);
    3963             : 
    3964       99061 :         if (el == NULL || (idx != -1 && el->num_values <= idx)) {
    3965       14406 :                 if (def != NULL) {
    3966         166 :                         Py_INCREF(def);
    3967         166 :                         return def;
    3968             :                 }
    3969       14240 :                 Py_RETURN_NONE;
    3970             :         }
    3971             : 
    3972       84655 :         if (idx == -1) {
    3973       74209 :                 return (PyObject *)PyLdbMessageElement_FromMessageElement(el, msg->elements);
    3974             :         }
    3975             : 
    3976       10446 :         return PyObject_FromLdbValue(&el->values[idx]);
    3977             : }
    3978             : 
    3979          66 : static PyObject *py_ldb_msg_items(PyObject *self,
    3980             :                 PyObject *Py_UNUSED(ignored))
    3981             : {
    3982          66 :         struct ldb_message *msg = NULL;
    3983          66 :         Py_ssize_t i, j = 0;
    3984          66 :         PyObject *l = NULL;
    3985             : 
    3986          66 :         PyErr_LDB_MESSAGE_OR_RAISE(self, msg);
    3987             : 
    3988          66 :         l = PyList_New(msg->num_elements + (msg->dn == NULL?0:1));
    3989          66 :         if (l == NULL) {
    3990           0 :                 return PyErr_NoMemory();
    3991             :         }
    3992          66 :         if (msg->dn != NULL) {
    3993          62 :                 PyObject *value = NULL;
    3994          62 :                 int res = 0;
    3995          62 :                 PyObject *obj = pyldb_Dn_FromDn(msg->dn, pyldb_Message_get_pyldb(self));
    3996          62 :                 if (obj == NULL) {
    3997           0 :                         Py_CLEAR(l);
    3998           0 :                         return NULL;
    3999             :                 }
    4000          62 :                 value = Py_BuildValue("(sO)", "dn", obj);
    4001          62 :                 Py_CLEAR(obj);
    4002          62 :                 if (value == NULL) {
    4003           0 :                         Py_CLEAR(l);
    4004           0 :                         return NULL;
    4005             :                 }
    4006          62 :                 res = PyList_SetItem(l, 0, value);
    4007          62 :                 if (res == -1) {
    4008           0 :                         Py_CLEAR(l);
    4009           0 :                         return NULL;
    4010             :                 }
    4011          62 :                 j++;
    4012             :         }
    4013         347 :         for (i = 0; i < msg->num_elements; i++, j++) {
    4014         281 :                 PyObject *value = NULL;
    4015         281 :                 int res = 0;
    4016         281 :                 PyObject *py_el = PyLdbMessageElement_FromMessageElement(&msg->elements[i],
    4017         281 :                                                                          msg->elements);
    4018         281 :                 if (py_el == NULL) {
    4019           0 :                         Py_CLEAR(l);
    4020           0 :                         return NULL;
    4021             :                 }
    4022         281 :                 value = Py_BuildValue("(sO)", msg->elements[i].name, py_el);
    4023         281 :                 Py_CLEAR(py_el);
    4024         281 :                 if (value == NULL ) {
    4025           0 :                         Py_CLEAR(l);
    4026           0 :                         return NULL;
    4027             :                 }
    4028         281 :                 res = PyList_SetItem(l, j, value);
    4029         281 :                 if (res == -1) {
    4030           0 :                         Py_CLEAR(l);
    4031           0 :                         return NULL;
    4032             :                 }
    4033             :         }
    4034          66 :         return l;
    4035             : }
    4036             : 
    4037           6 : static PyObject *py_ldb_msg_elements(PyObject *self,
    4038             :                 PyObject *Py_UNUSED(ignored))
    4039             : {
    4040           6 :         Py_ssize_t i = 0;
    4041           6 :         PyObject *l = NULL;
    4042           6 :         struct ldb_message *msg = NULL;
    4043           6 :         PyErr_LDB_MESSAGE_OR_RAISE(self, msg);
    4044             : 
    4045           6 :         l = PyList_New(msg->num_elements);
    4046           6 :         if (l == NULL) {
    4047           0 :                 return NULL;
    4048             :         }
    4049          10 :         for (i = 0; i < msg->num_elements; i++) {
    4050           4 :                 PyObject *msg_el = NULL;
    4051           0 :                 int ret;
    4052             : 
    4053           4 :                 msg_el = PyLdbMessageElement_FromMessageElement(&msg->elements[i], msg->elements);
    4054           4 :                 if (msg_el == NULL) {
    4055           0 :                         Py_DECREF(l);
    4056           0 :                         return NULL;
    4057             :                 }
    4058             : 
    4059           4 :                 ret = PyList_SetItem(l, i, msg_el);
    4060           4 :                 if (ret) {
    4061           0 :                         Py_DECREF(msg_el);
    4062           0 :                         Py_DECREF(l);
    4063           0 :                         return NULL;
    4064             :                 }
    4065             :         }
    4066           6 :         return l;
    4067             : }
    4068             : 
    4069        2776 : static PyObject *py_ldb_msg_add(PyObject *self, PyObject *args)
    4070             : {
    4071          30 :         PyLdbMessageElementObject *py_element;
    4072          30 :         int i, ret;
    4073          30 :         struct ldb_message_element *el;
    4074          30 :         struct ldb_message_element *el_new;
    4075        2776 :         struct ldb_message *msg = NULL;
    4076        2806 :         PyErr_LDB_MESSAGE_OR_RAISE(self, msg);
    4077             : 
    4078        2776 :         if (!PyArg_ParseTuple(args, "O!", &PyLdbMessageElement, &py_element)) {
    4079           0 :                 return NULL;
    4080             :         }
    4081             : 
    4082        2776 :         el = py_element->el;
    4083        2776 :         if (el == NULL) {
    4084           0 :                 PyErr_SetString(PyExc_ValueError, "Invalid MessageElement object");
    4085           0 :                 return NULL;
    4086             :         }
    4087        2776 :         if (el->name == NULL) {
    4088           0 :                 PyErr_SetString(PyExc_ValueError,
    4089             :                                 "The element has no name");
    4090           0 :                 return NULL;
    4091             :         }
    4092        2776 :         ret = ldb_msg_add_empty(msg, el->name, el->flags, &el_new);
    4093        2776 :         PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, NULL);
    4094             : 
    4095             :         /* now deep copy all attribute values */
    4096        2776 :         el_new->values = talloc_array(msg->elements, struct ldb_val, el->num_values);
    4097        2776 :         if (el_new->values == NULL) {
    4098           0 :                 PyErr_NoMemory();
    4099           0 :                 return NULL;
    4100             :         }
    4101        2776 :         el_new->num_values = el->num_values;
    4102             : 
    4103        5017 :         for (i = 0; i < el->num_values; i++) {
    4104        2241 :                 el_new->values[i] = ldb_val_dup(el_new->values, &el->values[i]);
    4105        2241 :                 if (el_new->values[i].data == NULL
    4106           0 :                                 && el->values[i].length != 0) {
    4107           0 :                         PyErr_NoMemory();
    4108           0 :                         return NULL;
    4109             :                 }
    4110             :         }
    4111             : 
    4112        2776 :         Py_RETURN_NONE;
    4113             : }
    4114             : 
    4115             : static PyMethodDef py_ldb_msg_methods[] = {
    4116             :         { "from_dict", (PyCFunction)py_ldb_msg_from_dict, METH_CLASS | METH_VARARGS,
    4117             :                 "Message.from_dict(ldb, dict, mod_flag) -> ldb.Message\n"
    4118             :                 "Class method to create ldb.Message object from Dictionary.\n"
    4119             :                 "mod_flag is one of FLAG_MOD_ADD, FLAG_MOD_REPLACE or FLAG_MOD_DELETE."},
    4120             :         { "keys", (PyCFunction)py_ldb_msg_keys, METH_NOARGS,
    4121             :                 "S.keys() -> list\n\n"
    4122             :                 "Return sequence of all attribute names." },
    4123             :         { "remove", (PyCFunction)py_ldb_msg_remove_attr, METH_VARARGS,
    4124             :                 "S.remove(name)\n\n"
    4125             :                 "Remove all entries for attributes with the specified name."},
    4126             :         { "get", PY_DISCARD_FUNC_SIG(PyCFunction, py_ldb_msg_get),
    4127             :                 METH_VARARGS | METH_KEYWORDS,
    4128             :           "msg.get(name,default=None,idx=None) -> string\n"
    4129             :           "idx is the index into the values array\n"
    4130             :           "if idx is None, then a list is returned\n"
    4131             :           "if idx is not None, then the element with that index is returned\n"
    4132             :           "if you pass the special name 'dn' then the DN object is returned\n"},
    4133             :         { "items", (PyCFunction)py_ldb_msg_items, METH_NOARGS, NULL },
    4134             :         { "elements", (PyCFunction)py_ldb_msg_elements, METH_NOARGS, NULL },
    4135             :         { "add", (PyCFunction)py_ldb_msg_add, METH_VARARGS,
    4136             :                 "S.add(element)\n\n"
    4137             :                 "Add an element to this message." },
    4138             :         {0},
    4139             : };
    4140             : 
    4141     2549330 : static PyObject *py_ldb_msg_iter(PyObject *self)
    4142             : {
    4143      244742 :         PyObject *list, *iter;
    4144             : 
    4145     2549330 :         list = py_ldb_msg_keys(self, NULL);
    4146     2549330 :         iter = PyObject_GetIter(list);
    4147     2086910 :         Py_DECREF(list);
    4148     2549330 :         return iter;
    4149             : }
    4150             : 
    4151      346642 : static int py_ldb_msg_setitem(PyLdbMessageObject *self, PyObject *name, PyObject *value)
    4152             : {
    4153       18978 :         const char *attr_name;
    4154             : 
    4155      346642 :         attr_name = PyUnicode_AsUTF8(name);
    4156      346642 :         if (attr_name == NULL) {
    4157           0 :                 PyErr_SetNone(PyExc_TypeError);
    4158           0 :                 return -1;
    4159             :         }
    4160             : 
    4161      346642 :         if (value == NULL) {
    4162             :                 /* delitem */
    4163        1607 :                 ldb_msg_remove_attr(self->msg, attr_name);
    4164             :         } else {
    4165       18928 :                 int ret;
    4166      345035 :                 struct ldb_message_element *el = PyObject_AsMessageElement(self->msg,
    4167             :                                                                            value, 0, attr_name);
    4168      345035 :                 if (el == NULL) {
    4169           0 :                         return -1;
    4170             :                 }
    4171      345035 :                 if (el->name == NULL) {
    4172             :                         /*
    4173             :                          * If ‘value’ is a MessageElement,
    4174             :                          * PyObject_AsMessageElement() will have returned a
    4175             :                          * reference to it without setting the name. We don’t
    4176             :                          * want to modify the original object to set the name
    4177             :                          * ourselves, but making a copy would result in
    4178             :                          * different behaviour for a caller relying on a
    4179             :                          * reference being kept. Rather than continue with a
    4180             :                          * NULL name (and probably fail later on), let’s catch
    4181             :                          * this potential mistake early.
    4182             :                          */
    4183           0 :                         PyErr_SetString(PyExc_ValueError, "MessageElement has no name set");
    4184           0 :                         talloc_unlink(self->msg, el);
    4185           0 :                         return -1;
    4186             :                 }
    4187      345035 :                 ldb_msg_remove_attr(pyldb_Message_AsMessage(self), attr_name);
    4188      345035 :                 ret = ldb_msg_add(pyldb_Message_AsMessage(self), el, el->flags);
    4189      345035 :                 if (ret != LDB_SUCCESS) {
    4190           0 :                         PyErr_SetLdbError(PyExc_LdbError, ret, NULL);
    4191           0 :                         talloc_unlink(self->msg, el);
    4192           0 :                         return -1;
    4193             :                 }
    4194             :         }
    4195      327664 :         return 0;
    4196             : }
    4197             : 
    4198       35934 : static Py_ssize_t py_ldb_msg_length(PyLdbMessageObject *self)
    4199             : {
    4200       35934 :         return pyldb_Message_AsMessage(self)->num_elements;
    4201             : }
    4202             : 
    4203             : static PySequenceMethods py_ldb_msg_sequence = {
    4204             :         .sq_contains = (objobjproc)py_ldb_msg_contains,
    4205             : };
    4206             : 
    4207             : static PyMappingMethods py_ldb_msg_mapping = {
    4208             :         .mp_length = (lenfunc)py_ldb_msg_length,
    4209             :         .mp_subscript = (binaryfunc)py_ldb_msg_getitem,
    4210             :         .mp_ass_subscript = (objobjargproc)py_ldb_msg_setitem,
    4211             : };
    4212             : 
    4213      213340 : static PyObject *py_ldb_msg_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
    4214             : {
    4215      213340 :         const char * const kwnames[] = { "dn", NULL };
    4216       14594 :         struct ldb_message *ret;
    4217       14594 :         TALLOC_CTX *mem_ctx;
    4218      213340 :         PyObject *pydn = NULL;
    4219       14594 :         PyLdbMessageObject *py_ret;
    4220             : 
    4221      213340 :         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O",
    4222             :                                          discard_const_p(char *, kwnames),
    4223             :                                          &pydn))
    4224           0 :                 return NULL;
    4225             : 
    4226      213340 :         mem_ctx = talloc_new(NULL);
    4227      213340 :         if (mem_ctx == NULL) {
    4228           0 :                 PyErr_NoMemory();
    4229           0 :                 return NULL;
    4230             :         }
    4231             : 
    4232      213340 :         ret = ldb_msg_new(mem_ctx);
    4233      213340 :         if (ret == NULL) {
    4234           0 :                 talloc_free(mem_ctx);
    4235           0 :                 PyErr_NoMemory();
    4236           0 :                 return NULL;
    4237             :         }
    4238             : 
    4239      213340 :         if (pydn != NULL) {
    4240        1416 :                 struct ldb_dn *dn;
    4241       10118 :                 if (!pyldb_Object_AsDn(NULL, pydn, NULL, &dn)) {
    4242           0 :                         talloc_free(mem_ctx);
    4243           0 :                         return NULL;
    4244             :                 }
    4245       10118 :                 ret->dn = talloc_reference(ret, dn);
    4246       10118 :                 if (ret->dn == NULL) {
    4247           0 :                         talloc_free(mem_ctx);
    4248           0 :                         return PyErr_NoMemory();
    4249             :                 }
    4250             :         }
    4251             : 
    4252      213340 :         py_ret = (PyLdbMessageObject *)type->tp_alloc(type, 0);
    4253      213340 :         if (py_ret == NULL) {
    4254           0 :                 PyErr_NoMemory();
    4255           0 :                 talloc_free(mem_ctx);
    4256           0 :                 return NULL;
    4257             :         }
    4258             : 
    4259      213340 :         py_ret->mem_ctx = mem_ctx;
    4260      213340 :         py_ret->msg = ret;
    4261      213340 :         if (pydn != NULL) {
    4262       10118 :                 py_ret->pyldb = ((PyLdbDnObject *)pydn)->pyldb;
    4263       10118 :                 Py_INCREF(py_ret->pyldb);
    4264             :         }
    4265      198746 :         return (PyObject *)py_ret;
    4266             : }
    4267             : 
    4268     5751733 : static PyObject *PyLdbMessage_FromMessage(struct ldb_message *msg, PyLdbObject *pyldb)
    4269             : {
    4270     5751733 :         TALLOC_CTX *mem_ctx = NULL;
    4271     5751733 :         struct ldb_message *msg_ref = NULL;
    4272      475315 :         PyLdbMessageObject *ret;
    4273             : 
    4274     5751733 :         mem_ctx = talloc_new(NULL);
    4275     5751733 :         if (mem_ctx == NULL) {
    4276           0 :                 return PyErr_NoMemory();
    4277             :         }
    4278             : 
    4279     5751733 :         msg_ref = talloc_reference(mem_ctx, msg);
    4280     5751733 :         if (msg_ref == NULL) {
    4281           0 :                 talloc_free(mem_ctx);
    4282           0 :                 return PyErr_NoMemory();
    4283             :         }
    4284             : 
    4285     5751733 :         ret = (PyLdbMessageObject *)PyLdbMessage.tp_alloc(&PyLdbMessage, 0);
    4286     5751733 :         if (ret == NULL) {
    4287           0 :                 talloc_free(mem_ctx);
    4288           0 :                 PyErr_NoMemory();
    4289           0 :                 return NULL;
    4290             :         }
    4291     5751733 :         ret->mem_ctx = mem_ctx;
    4292     5751733 :         ret->msg = msg_ref;
    4293             : 
    4294     5751733 :         ret->pyldb = pyldb;
    4295     5751733 :         Py_INCREF(ret->pyldb);
    4296             : 
    4297     5751733 :         return (PyObject *)ret;
    4298             : }
    4299             : 
    4300    20909602 : static PyObject *py_ldb_msg_get_dn(PyObject *self, void *closure)
    4301             : {
    4302    20909602 :         struct ldb_message *msg = NULL;
    4303    23557622 :         PyErr_LDB_MESSAGE_OR_RAISE(self, msg);
    4304    20909602 :         return pyldb_Dn_FromDn(msg->dn, pyldb_Message_get_pyldb(self));
    4305             : }
    4306             : 
    4307      209684 : static int py_ldb_msg_set_dn(PyObject *self, PyObject *value, void *closure)
    4308             : {
    4309             :         /*
    4310             :          * no PyErr_LDB_MESSAGE_OR_RAISE here, because this returns int.
    4311             :          *
    4312             :          * Also, since this is trying to replace the dn, we don't need to
    4313             :          * check the old one.
    4314             :          */
    4315      209684 :         struct ldb_message *msg = pyldb_Message_as_message(self);
    4316      209684 :         struct ldb_dn *dn = NULL;
    4317      209684 :         PyLdbObject *pyldb = pyldb_Message_get_pyldb(self);
    4318      209684 :         PyLdbMessageObject *self_as_msg = (PyLdbMessageObject *)self;
    4319             : 
    4320      209684 :         if (value == NULL) {
    4321           0 :                 PyErr_SetString(PyExc_AttributeError, "cannot delete dn");
    4322           0 :                 return -1;
    4323             :         }
    4324      209684 :         if (!pyldb_Dn_Check(value)) {
    4325           2 :                 PyErr_SetString(PyExc_TypeError, "expected dn");
    4326           2 :                 return -1;
    4327             :         }
    4328             : 
    4329      209682 :         dn = talloc_reference(msg, pyldb_Dn_AS_DN(value));
    4330      209682 :         if (dn == NULL) {
    4331           0 :                 PyErr_NoMemory();
    4332           0 :                 return -1;
    4333             :         }
    4334             : 
    4335      209682 :         if (pyldb != NULL) {
    4336        6839 :                 if (pyldb->ldb_ctx != ldb_dn_get_ldb_context(dn)) {
    4337           0 :                         PyErr_SetString(PyExc_RuntimeError,
    4338             :                                         "DN is from the wrong LDB");
    4339           0 :                         return -1;
    4340             :                 }
    4341        6839 :                 Py_DECREF(pyldb);
    4342             :         }
    4343             : 
    4344      209682 :         msg->dn = dn;
    4345             : 
    4346      209682 :         self_as_msg->pyldb = ((PyLdbDnObject *)value)->pyldb;
    4347      209682 :         Py_INCREF(self_as_msg->pyldb);
    4348             : 
    4349      209682 :         return 0;
    4350             : }
    4351             : 
    4352          90 : static PyObject *py_ldb_msg_get_text(PyObject *self, void *closure)
    4353             : {
    4354          90 :         return wrap_text("MessageTextWrapper", self);
    4355             : }
    4356             : 
    4357             : 
    4358             : 
    4359        6797 : static PyObject *py_ldb_msg_get_ldb(PyLdbMessageObject *self, void *closure)
    4360             : {
    4361        6797 :         if (self->pyldb == NULL) {
    4362           0 :                 Py_RETURN_NONE;
    4363             :         }
    4364        6797 :         Py_INCREF(self->pyldb);
    4365        6797 :         return (PyObject *)self->pyldb;
    4366             : }
    4367             : 
    4368             : 
    4369             : static PyGetSetDef py_ldb_msg_getset[] = {
    4370             :         {
    4371             :                 .name = discard_const_p(char, "dn"),
    4372             :                 .get  = (getter)py_ldb_msg_get_dn,
    4373             :                 .set  = (setter)py_ldb_msg_set_dn,
    4374             :         },
    4375             :         {
    4376             :                 .name = discard_const_p(char, "text"),
    4377             :                 .get  = (getter)py_ldb_msg_get_text,
    4378             :         },
    4379             :         {
    4380             :                 .name = discard_const_p(char, "ldb"),
    4381             :                 .get  = (getter)py_ldb_msg_get_ldb,
    4382             :                 .doc = discard_const_p(
    4383             :                         char, "returns the associated ldb object (or None)")
    4384             :         },
    4385             :         { .name = NULL },
    4386             : };
    4387             : 
    4388       64746 : static PyObject *py_ldb_msg_repr(PyLdbMessageObject *self)
    4389             : {
    4390       64746 :         PyObject *dict = PyDict_New(), *ret, *repr;
    4391       64746 :         const char *repr_str = NULL;
    4392       64746 :         if (dict == NULL) {
    4393           0 :                 return NULL;
    4394             :         }
    4395       64746 :         if (PyDict_Update(dict, (PyObject *)self) != 0) {
    4396           0 :                 Py_DECREF(dict);
    4397           0 :                 return NULL;
    4398             :         }
    4399       64746 :         repr = PyObject_Repr(dict);
    4400       64746 :         if (repr == NULL) {
    4401           0 :                 Py_DECREF(dict);
    4402           0 :                 return NULL;
    4403             :         }
    4404       64746 :         repr_str = PyUnicode_AsUTF8(repr);
    4405       64746 :         if (repr_str == NULL) {
    4406           0 :                 Py_DECREF(repr);
    4407           0 :                 Py_DECREF(dict);
    4408           0 :                 return NULL;
    4409             :         }
    4410       64746 :         ret = PyUnicode_FromFormat("Message(%s)", repr_str);
    4411       36245 :         Py_DECREF(repr);
    4412       36245 :         Py_DECREF(dict);
    4413       64746 :         return ret;
    4414             : }
    4415             : 
    4416     5965073 : static void py_ldb_msg_dealloc(PyLdbMessageObject *self)
    4417             : {
    4418     5965073 :         talloc_free(self->mem_ctx);
    4419             :         /* The pyldb element will only be present if a DN is assigned */
    4420     5965073 :         if (self->pyldb) {
    4421     5964694 :                 Py_DECREF(self->pyldb);
    4422             :         }
    4423     5965073 :         PyObject_Del(self);
    4424     5965073 : }
    4425             : 
    4426        1777 : static PyObject *py_ldb_msg_richcmp(PyLdbMessageObject *py_msg1,
    4427             :                               PyLdbMessageObject *py_msg2, int op)
    4428             : {
    4429           1 :         struct ldb_message *msg1, *msg2;
    4430           1 :         unsigned int i;
    4431           1 :         int ret;
    4432             : 
    4433        1777 :         if (!pyldb_Message_Check(py_msg2)) {
    4434         948 :                 Py_INCREF(Py_NotImplemented);
    4435         953 :                 return Py_NotImplemented;
    4436             :         }
    4437             : 
    4438         825 :         PyErr_LDB_MESSAGE_OR_RAISE(py_msg1, msg1);
    4439         824 :         PyErr_LDB_MESSAGE_OR_RAISE(py_msg2, msg2);
    4440             :         /*
    4441             :          * FIXME: this can be a non-transitive compare, unsuitable for
    4442             :          * sorting.
    4443             :          *
    4444             :          * supposing msg1, msg2, and msg3 have 1, 2, and 3 elements
    4445             :          * each. msg2 has a NULL DN, while msg1 has a DN that compares
    4446             :          * higher than msg3. Then:
    4447             :          *
    4448             :          * msg1 < msg2, due to num_elements.
    4449             :          * msg2 < msg3, due to num_elements.
    4450             :          * msg1 > msg3, due to DNs.
    4451             :          */
    4452         824 :         if ((msg1->dn != NULL) || (msg2->dn != NULL)) {
    4453         822 :                 ret = ldb_dn_compare(msg1->dn, msg2->dn);
    4454         822 :                 if (ret != 0) {
    4455           0 :                         return richcmp(ret, op);
    4456             :                 }
    4457             :         }
    4458             : 
    4459         824 :         if (msg1->num_elements > msg2->num_elements) {
    4460           0 :                 return richcmp(1, op);
    4461             :         }
    4462         824 :         if (msg1->num_elements < msg2->num_elements) {
    4463           0 :                 return richcmp(-1, op);
    4464             :         }
    4465             : 
    4466        8143 :         for (i = 0; i < msg1->num_elements; i++) {
    4467        7323 :                 ret = ldb_msg_element_compare_name(&msg1->elements[i],
    4468        7321 :                                                    &msg2->elements[i]);
    4469        7321 :                 if (ret != 0) {
    4470           0 :                         return richcmp(ret, op);
    4471             :                 }
    4472             : 
    4473        7323 :                 ret = ldb_msg_element_compare(&msg1->elements[i],
    4474        7321 :                                               &msg2->elements[i]);
    4475        7321 :                 if (ret != 0) {
    4476           2 :                         return richcmp(ret, op);
    4477             :                 }
    4478             :         }
    4479             : 
    4480         822 :         return richcmp(0, op);
    4481             : }
    4482             : 
    4483             : static PyTypeObject PyLdbMessage = {
    4484             :         .tp_name = "ldb.Message",
    4485             :         .tp_methods = py_ldb_msg_methods,
    4486             :         .tp_getset = py_ldb_msg_getset,
    4487             :         .tp_as_sequence = &py_ldb_msg_sequence,
    4488             :         .tp_as_mapping = &py_ldb_msg_mapping,
    4489             :         .tp_basicsize = sizeof(PyLdbMessageObject),
    4490             :         .tp_dealloc = (destructor)py_ldb_msg_dealloc,
    4491             :         .tp_new = py_ldb_msg_new,
    4492             :         .tp_repr = (reprfunc)py_ldb_msg_repr,
    4493             :         .tp_flags = Py_TPFLAGS_DEFAULT,
    4494             :         .tp_iter = (getiterfunc)py_ldb_msg_iter,
    4495             :         .tp_richcompare = (richcmpfunc)py_ldb_msg_richcmp,
    4496             :         .tp_doc = "A LDB Message",
    4497             : };
    4498             : 
    4499           0 : static void py_ldb_tree_dealloc(PyLdbTreeObject *self)
    4500             : {
    4501           0 :         talloc_free(self->mem_ctx);
    4502           0 :         PyObject_Del(self);
    4503           0 : }
    4504             : 
    4505             : static PyTypeObject PyLdbTree = {
    4506             :         .tp_name = "ldb.Tree",
    4507             :         .tp_basicsize = sizeof(PyLdbTreeObject),
    4508             :         .tp_dealloc = (destructor)py_ldb_tree_dealloc,
    4509             :         .tp_flags = Py_TPFLAGS_DEFAULT,
    4510             :         .tp_doc = "A search tree",
    4511             : };
    4512             : 
    4513        5131 : static PyObject *py_timestring(PyObject *module, PyObject *args)
    4514             : {
    4515             :         /* most times "time_t" is a signed integer type with 32 or 64 bit:
    4516             :          * http://stackoverflow.com/questions/471248/what-is-ultimately-a-time-t-typedef-to */
    4517          45 :         long int t_val;
    4518          45 :         char *tresult;
    4519          45 :         PyObject *ret;
    4520        5131 :         if (!PyArg_ParseTuple(args, "l", &t_val))
    4521           0 :                 return NULL;
    4522        5131 :         tresult = ldb_timestring(NULL, (time_t) t_val);
    4523        5131 :         if (tresult == NULL) {
    4524             :                 /*
    4525             :                  * Most likely EOVERFLOW from gmtime()
    4526             :                  */
    4527           6 :                 PyErr_SetFromErrno(PyExc_OSError);
    4528           6 :                 return NULL;
    4529             :         }
    4530        5125 :         ret = PyUnicode_FromString(tresult);
    4531        5125 :         talloc_free(tresult);
    4532        5125 :         return ret;
    4533             : }
    4534             : 
    4535        6298 : static PyObject *py_string_to_time(PyObject *module, PyObject *args)
    4536             : {
    4537          72 :         char *str;
    4538          72 :         time_t t;
    4539        6298 :         if (!PyArg_ParseTuple(args, "s", &str)) {
    4540           0 :                 return NULL;
    4541             :         }
    4542        6298 :         t = ldb_string_to_time(str);
    4543             : 
    4544        6298 :         if (t == 0 && errno != 0) {
    4545           0 :                 PyErr_SetFromErrno(PyExc_ValueError);
    4546           0 :                 return NULL;
    4547             :         }
    4548        6298 :         return PyLong_FromLong(t);
    4549             : }
    4550             : 
    4551           4 : static PyObject *py_valid_attr_name(PyObject *self, PyObject *args)
    4552             : {
    4553           0 :         char *name;
    4554           4 :         if (!PyArg_ParseTuple(args, "s", &name))
    4555           0 :                 return NULL;
    4556           4 :         return PyBool_FromLong(ldb_valid_attr_name(name));
    4557             : }
    4558             : 
    4559             : /*
    4560             :   encode a string using RFC2254 rules
    4561             :  */
    4562       58894 : static PyObject *py_binary_encode(PyObject *self, PyObject *args)
    4563             : {
    4564          90 :         char *str, *encoded;
    4565       58894 :         Py_ssize_t size = 0;
    4566          90 :         struct ldb_val val;
    4567          90 :         PyObject *ret;
    4568             : 
    4569       58894 :         if (!PyArg_ParseTuple(args, "s#", &str, &size))
    4570           0 :                 return NULL;
    4571       58894 :         val.data = (uint8_t *)str;
    4572       58894 :         val.length = size;
    4573             : 
    4574       58894 :         encoded = ldb_binary_encode(NULL, val);
    4575       58894 :         if (encoded == NULL) {
    4576           0 :                 PyErr_SetString(PyExc_TypeError, "unable to encode binary string");
    4577           0 :                 return NULL;
    4578             :         }
    4579       58894 :         ret = PyUnicode_FromString(encoded);
    4580       58894 :         talloc_free(encoded);
    4581       58894 :         return ret;
    4582             : }
    4583             : 
    4584             : /*
    4585             :   decode a string using RFC2254 rules
    4586             :  */
    4587           2 : static PyObject *py_binary_decode(PyObject *self, PyObject *args)
    4588             : {
    4589           0 :         char *str;
    4590           0 :         struct ldb_val val;
    4591           0 :         PyObject *ret;
    4592             : 
    4593           2 :         if (!PyArg_ParseTuple(args, "s", &str))
    4594           0 :                 return NULL;
    4595             : 
    4596           2 :         val = ldb_binary_decode(NULL, str);
    4597           2 :         if (val.data == NULL) {
    4598           0 :                 PyErr_SetString(PyExc_TypeError, "unable to decode binary string");
    4599           0 :                 return NULL;
    4600             :         }
    4601           2 :         ret = PyBytes_FromStringAndSize((const char*)val.data, val.length);
    4602           2 :         talloc_free(val.data);
    4603           2 :         return ret;
    4604             : }
    4605             : 
    4606             : static PyMethodDef py_ldb_global_methods[] = {
    4607             :         { "timestring", py_timestring, METH_VARARGS,
    4608             :                 "S.timestring(int) -> string\n\n"
    4609             :                 "Generate a LDAP time string from a UNIX timestamp" },
    4610             :         { "string_to_time", py_string_to_time, METH_VARARGS,
    4611             :                 "S.string_to_time(string) -> int\n\n"
    4612             :                 "Parse a LDAP time string into a UNIX timestamp." },
    4613             :         { "valid_attr_name", py_valid_attr_name, METH_VARARGS,
    4614             :                 "S.valid_attr_name(name) -> bool\n\n"
    4615             :                 "Check whether the supplied name is a valid attribute name." },
    4616             :         { "binary_encode", py_binary_encode, METH_VARARGS,
    4617             :                 "S.binary_encode(string) -> string\n\n"
    4618             :                 "Perform a RFC2254 binary encoding on a string" },
    4619             :         { "binary_decode", py_binary_decode, METH_VARARGS,
    4620             :                 "S.binary_decode(string) -> string\n\n"
    4621             :                 "Perform a RFC2254 binary decode on a string" },
    4622             :         {0}
    4623             : };
    4624             : 
    4625             : #define MODULE_DOC "An interface to LDB, a LDAP-like API that can either to talk an embedded database (TDB-based) or a standards-compliant LDAP server."
    4626             : 
    4627             : static struct PyModuleDef moduledef = {
    4628             :         PyModuleDef_HEAD_INIT,
    4629             :         .m_name = "ldb",
    4630             :         .m_doc = MODULE_DOC,
    4631             :         .m_size = -1,
    4632             :         .m_methods = py_ldb_global_methods,
    4633             : };
    4634             : 
    4635       12850 : static PyObject* module_init(void)
    4636             : {
    4637         563 :         PyObject *m;
    4638             : 
    4639       12850 :         PyLdbBytesType.tp_base = &PyBytes_Type;
    4640       12850 :         if (PyType_Ready(&PyLdbBytesType) < 0) {
    4641           0 :                 return NULL;
    4642             :         }
    4643             : 
    4644       12850 :         if (PyType_Ready(&PyLdbDn) < 0)
    4645           0 :                 return NULL;
    4646             : 
    4647       12850 :         if (PyType_Ready(&PyLdbMessage) < 0)
    4648           0 :                 return NULL;
    4649             : 
    4650       12850 :         if (PyType_Ready(&PyLdbMessageElement) < 0)
    4651           0 :                 return NULL;
    4652             : 
    4653       12850 :         if (PyType_Ready(&PyLdb) < 0)
    4654           0 :                 return NULL;
    4655             : 
    4656       12850 :         if (PyType_Ready(&PyLdbTree) < 0)
    4657           0 :                 return NULL;
    4658             : 
    4659       12850 :         if (PyType_Ready(&PyLdbResult) < 0)
    4660           0 :                 return NULL;
    4661             : 
    4662       12850 :         if (PyType_Ready(&PyLdbSearchIterator) < 0)
    4663           0 :                 return NULL;
    4664             : 
    4665       12850 :         if (PyType_Ready(&PyLdbControl) < 0)
    4666           0 :                 return NULL;
    4667             : 
    4668       12850 :         m = PyModule_Create(&moduledef);
    4669       12850 :         if (m == NULL)
    4670           0 :                 return NULL;
    4671             : 
    4672             : #define ADD_LDB_INT(val) PyModule_AddIntConstant(m, #val, LDB_ ## val)
    4673             : 
    4674       12850 :         ADD_LDB_INT(SEQ_HIGHEST_SEQ);
    4675       12850 :         ADD_LDB_INT(SEQ_HIGHEST_TIMESTAMP);
    4676       12850 :         ADD_LDB_INT(SEQ_NEXT);
    4677       12850 :         ADD_LDB_INT(SCOPE_DEFAULT);
    4678       12850 :         ADD_LDB_INT(SCOPE_BASE);
    4679       12850 :         ADD_LDB_INT(SCOPE_ONELEVEL);
    4680       12850 :         ADD_LDB_INT(SCOPE_SUBTREE);
    4681             : 
    4682       12850 :         ADD_LDB_INT(CHANGETYPE_NONE);
    4683       12850 :         ADD_LDB_INT(CHANGETYPE_ADD);
    4684       12850 :         ADD_LDB_INT(CHANGETYPE_DELETE);
    4685       12850 :         ADD_LDB_INT(CHANGETYPE_MODIFY);
    4686       12850 :         ADD_LDB_INT(CHANGETYPE_MODRDN);
    4687             : 
    4688       12850 :         ADD_LDB_INT(FLAG_MOD_ADD);
    4689       12850 :         ADD_LDB_INT(FLAG_MOD_REPLACE);
    4690       12850 :         ADD_LDB_INT(FLAG_MOD_DELETE);
    4691       12850 :         ADD_LDB_INT(FLAG_FORCE_NO_BASE64_LDIF);
    4692             : 
    4693       12850 :         ADD_LDB_INT(ATTR_FLAG_HIDDEN);
    4694       12850 :         ADD_LDB_INT(ATTR_FLAG_UNIQUE_INDEX);
    4695       12850 :         ADD_LDB_INT(ATTR_FLAG_SINGLE_VALUE);
    4696       12850 :         ADD_LDB_INT(ATTR_FLAG_FORCE_BASE64_LDIF);
    4697             : 
    4698       12850 :         ADD_LDB_INT(SUCCESS);
    4699       12850 :         ADD_LDB_INT(ERR_OPERATIONS_ERROR);
    4700       12850 :         ADD_LDB_INT(ERR_PROTOCOL_ERROR);
    4701       12850 :         ADD_LDB_INT(ERR_TIME_LIMIT_EXCEEDED);
    4702       12850 :         ADD_LDB_INT(ERR_SIZE_LIMIT_EXCEEDED);
    4703       12850 :         ADD_LDB_INT(ERR_COMPARE_FALSE);
    4704       12850 :         ADD_LDB_INT(ERR_COMPARE_TRUE);
    4705       12850 :         ADD_LDB_INT(ERR_AUTH_METHOD_NOT_SUPPORTED);
    4706       12850 :         ADD_LDB_INT(ERR_STRONG_AUTH_REQUIRED);
    4707       12850 :         ADD_LDB_INT(ERR_REFERRAL);
    4708       12850 :         ADD_LDB_INT(ERR_ADMIN_LIMIT_EXCEEDED);
    4709       12850 :         ADD_LDB_INT(ERR_UNSUPPORTED_CRITICAL_EXTENSION);
    4710       12850 :         ADD_LDB_INT(ERR_CONFIDENTIALITY_REQUIRED);
    4711       12850 :         ADD_LDB_INT(ERR_SASL_BIND_IN_PROGRESS);
    4712       12850 :         ADD_LDB_INT(ERR_NO_SUCH_ATTRIBUTE);
    4713       12850 :         ADD_LDB_INT(ERR_UNDEFINED_ATTRIBUTE_TYPE);
    4714       12850 :         ADD_LDB_INT(ERR_INAPPROPRIATE_MATCHING);
    4715       12850 :         ADD_LDB_INT(ERR_CONSTRAINT_VIOLATION);
    4716       12850 :         ADD_LDB_INT(ERR_ATTRIBUTE_OR_VALUE_EXISTS);
    4717       12850 :         ADD_LDB_INT(ERR_INVALID_ATTRIBUTE_SYNTAX);
    4718       12850 :         ADD_LDB_INT(ERR_NO_SUCH_OBJECT);
    4719       12850 :         ADD_LDB_INT(ERR_ALIAS_PROBLEM);
    4720       12850 :         ADD_LDB_INT(ERR_INVALID_DN_SYNTAX);
    4721       12850 :         ADD_LDB_INT(ERR_ALIAS_DEREFERENCING_PROBLEM);
    4722       12850 :         ADD_LDB_INT(ERR_INAPPROPRIATE_AUTHENTICATION);
    4723       12850 :         ADD_LDB_INT(ERR_INVALID_CREDENTIALS);
    4724       12850 :         ADD_LDB_INT(ERR_INSUFFICIENT_ACCESS_RIGHTS);
    4725       12850 :         ADD_LDB_INT(ERR_BUSY);
    4726       12850 :         ADD_LDB_INT(ERR_UNAVAILABLE);
    4727       12850 :         ADD_LDB_INT(ERR_UNWILLING_TO_PERFORM);
    4728       12850 :         ADD_LDB_INT(ERR_LOOP_DETECT);
    4729       12850 :         ADD_LDB_INT(ERR_NAMING_VIOLATION);
    4730       12850 :         ADD_LDB_INT(ERR_OBJECT_CLASS_VIOLATION);
    4731       12850 :         ADD_LDB_INT(ERR_NOT_ALLOWED_ON_NON_LEAF);
    4732       12850 :         ADD_LDB_INT(ERR_NOT_ALLOWED_ON_RDN);
    4733       12850 :         ADD_LDB_INT(ERR_ENTRY_ALREADY_EXISTS);
    4734       12850 :         ADD_LDB_INT(ERR_OBJECT_CLASS_MODS_PROHIBITED);
    4735       12850 :         ADD_LDB_INT(ERR_AFFECTS_MULTIPLE_DSAS);
    4736       12850 :         ADD_LDB_INT(ERR_OTHER);
    4737             : 
    4738       12850 :         ADD_LDB_INT(FLG_RDONLY);
    4739       12850 :         ADD_LDB_INT(FLG_NOSYNC);
    4740       12850 :         ADD_LDB_INT(FLG_RECONNECT);
    4741       12850 :         ADD_LDB_INT(FLG_NOMMAP);
    4742       12850 :         ADD_LDB_INT(FLG_SHOW_BINARY);
    4743       12850 :         ADD_LDB_INT(FLG_ENABLE_TRACING);
    4744       12850 :         ADD_LDB_INT(FLG_DONT_CREATE_DB);
    4745             : 
    4746       12850 :         ADD_LDB_INT(PACKING_FORMAT);
    4747       12850 :         ADD_LDB_INT(PACKING_FORMAT_V2);
    4748             : 
    4749             :         /* Historical misspelling */
    4750       12850 :         PyModule_AddIntConstant(m, "ERR_ALIAS_DEREFERINCING_PROBLEM", LDB_ERR_ALIAS_DEREFERENCING_PROBLEM);
    4751             : 
    4752       12850 :         PyModule_AddStringConstant(m, "__docformat__", "restructuredText");
    4753             : 
    4754       12850 :         PyExc_LdbError = PyErr_NewException(discard_const_p(char, "_ldb.LdbError"), NULL, NULL);
    4755       12850 :         PyModule_AddObject(m, "LdbError", PyExc_LdbError);
    4756             : 
    4757       10719 :         Py_INCREF(&PyLdb);
    4758       10719 :         Py_INCREF(&PyLdbDn);
    4759       10719 :         Py_INCREF(&PyLdbMessage);
    4760       10719 :         Py_INCREF(&PyLdbMessageElement);
    4761       10719 :         Py_INCREF(&PyLdbTree);
    4762       10719 :         Py_INCREF(&PyLdbResult);
    4763       10719 :         Py_INCREF(&PyLdbControl);
    4764             : 
    4765       12850 :         PyModule_AddObject(m, "Ldb", (PyObject *)&PyLdb);
    4766       12850 :         PyModule_AddObject(m, "Dn", (PyObject *)&PyLdbDn);
    4767       12850 :         PyModule_AddObject(m, "Message", (PyObject *)&PyLdbMessage);
    4768       12850 :         PyModule_AddObject(m, "MessageElement", (PyObject *)&PyLdbMessageElement);
    4769       12850 :         PyModule_AddObject(m, "Tree", (PyObject *)&PyLdbTree);
    4770       12850 :         PyModule_AddObject(m, "Result", (PyObject *)&PyLdbResult);
    4771       12850 :         PyModule_AddObject(m, "Control", (PyObject *)&PyLdbControl);
    4772             : 
    4773       12850 :         PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
    4774             : 
    4775             : #define ADD_LDB_STRING(val)  PyModule_AddStringConstant(m, #val, LDB_## val)
    4776             : 
    4777       12850 :         ADD_LDB_STRING(SYNTAX_DN);
    4778       12850 :         ADD_LDB_STRING(SYNTAX_DIRECTORY_STRING);
    4779       12850 :         ADD_LDB_STRING(SYNTAX_INTEGER);
    4780       12850 :         ADD_LDB_STRING(SYNTAX_ORDERED_INTEGER);
    4781       12850 :         ADD_LDB_STRING(SYNTAX_BOOLEAN);
    4782       12850 :         ADD_LDB_STRING(SYNTAX_OCTET_STRING);
    4783       12850 :         ADD_LDB_STRING(SYNTAX_UTC_TIME);
    4784       12850 :         ADD_LDB_STRING(OID_COMPARATOR_AND);
    4785       12850 :         ADD_LDB_STRING(OID_COMPARATOR_OR);
    4786             : 
    4787       12850 :         return m;
    4788             : }
    4789             : 
    4790             : PyMODINIT_FUNC PyInit_ldb(void);
    4791       12850 : PyMODINIT_FUNC PyInit_ldb(void)
    4792             : {
    4793       12850 :         return module_init();
    4794             : }

Generated by: LCOV version 1.14