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

Generated by: LCOV version 1.14