LCOV - code coverage report
Current view: top level - Modules - LDAPObject.c (source / functions) Hit Total Coverage
Test: python-ldap LCOV report Lines: 586 679 86.3 %
Date: 2017-12-08 13:03:20 Functions: 30 30 100.0 %

          Line data    Source code
       1             : /* See https://www.python-ldap.org/ for details. */
       2             : 
       3             : #include "common.h"
       4             : #include "patchlevel.h"
       5             : 
       6             : #include <math.h>
       7             : #include <limits.h>
       8             : #include "constants.h"
       9             : #include "LDAPObject.h"
      10             : #include "ldapcontrol.h"
      11             : #include "message.h"
      12             : #include "berval.h"
      13             : #include "options.h"
      14             : 
      15             : #ifdef HAVE_SASL
      16             : #include <sasl/sasl.h>
      17             : #endif
      18             : 
      19             : static void free_attrs(char***, PyObject*);
      20             : 
      21             : /* constructor */
      22             : 
      23             : LDAPObject*
      24         108 : newLDAPObject( LDAP* l ) 
      25             : {
      26         108 :     LDAPObject* self = (LDAPObject*) PyObject_NEW(LDAPObject, &LDAP_Type);
      27         108 :     if (self == NULL) 
      28           0 :         return NULL;
      29         108 :     self->ldap = l;
      30         108 :     self->_save = NULL;
      31         108 :     self->valid = 1;
      32         108 :     return self;
      33             : }
      34             : 
      35             : /* destructor */
      36             : 
      37             : static void
      38         108 : dealloc( LDAPObject* self )
      39             : {
      40         108 :     if (self->ldap) {
      41         108 :         if (self->valid) {
      42          86 :             LDAP_BEGIN_ALLOW_THREADS( self );
      43          86 :             ldap_unbind_ext( self->ldap, NULL, NULL );
      44          86 :             LDAP_END_ALLOW_THREADS( self );
      45          86 :             self->valid = 0;
      46             :         }
      47         108 :         self->ldap = NULL;
      48             :     }
      49         108 :     PyObject_DEL(self);
      50         108 : }
      51             : 
      52             : /*------------------------------------------------------------
      53             :  * utility functions
      54             :  */
      55             : 
      56             : /* 
      57             :  * check to see if the LDAPObject is valid, 
      58             :  * ie has been opened, and not closed. An exception is set if not valid.
      59             :  */
      60             : 
      61             : static int
      62         425 : not_valid( LDAPObject* l ) {
      63         425 :     if (l->valid) {
      64         423 :         return 0;
      65             :     } else {
      66           2 :         PyErr_SetString( LDAPexception_class, "LDAP connection invalid" );
      67           2 :         return 1;
      68             :     }
      69             : }
      70             : 
      71             : /* free a LDAPMod (complete or partially) allocated in Tuple_to_LDAPMod() */
      72             : 
      73             : static void
      74          30 : LDAPMod_DEL( LDAPMod* lm )
      75             : {
      76             :     Py_ssize_t i;
      77             : 
      78          30 :     if (lm->mod_type)
      79          30 :         PyMem_DEL(lm->mod_type);
      80          30 :     if (lm->mod_bvalues) {
      81          61 :         for (i = 0; lm->mod_bvalues[i]; i++) {
      82          31 :             PyMem_DEL(lm->mod_bvalues[i]);
      83             :         }
      84          30 :         PyMem_DEL(lm->mod_bvalues);
      85             :     }
      86          30 :     PyMem_DEL(lm);
      87          30 : }
      88             : 
      89             : /* 
      90             :  * convert a tuple of the form (int,str,[str,...]) 
      91             :  * or (str, [str,...]) if no_op is true, into an LDAPMod structure.
      92             :  * See ldap_modify(3) for details.
      93             :  *
      94             :  * NOTE: the resulting LDAPMod structure has pointers directly into
      95             :  *       the Python string storage, so LDAPMod structures MUST have a
      96             :  *       shorter lifetime than the tuple passed in.
      97             :  */
      98             : 
      99             : /* XXX - there is no way to pass complex-structured BER objects in here! */
     100             : 
     101             : static LDAPMod*
     102          30 : Tuple_to_LDAPMod( PyObject* tup, int no_op ) 
     103             : {
     104             :     int op;
     105             :     char *type;
     106             :     PyObject *list, *item;
     107          30 :     LDAPMod *lm = NULL;
     108             :     Py_ssize_t i, len, nstrs;
     109             : 
     110          30 :     if (!PyTuple_Check(tup)) {
     111           0 :         LDAPerror_TypeError("expected a tuple", tup);
     112          30 :         return NULL;
     113             :     }
     114             : 
     115          30 :     if (no_op) {
     116          25 :         if (!PyArg_ParseTuple( tup, "sO", &type, &list ))
     117           0 :                 return NULL;
     118          25 :         op = 0;
     119             :     } else {
     120           5 :         if (!PyArg_ParseTuple( tup, "isO", &op, &type, &list ))
     121           0 :                 return NULL;
     122             :     }
     123             : 
     124          30 :     lm = PyMem_NEW(LDAPMod, 1);
     125          30 :     if (lm == NULL)
     126           0 :         goto nomem;
     127             : 
     128          30 :     lm->mod_op = op | LDAP_MOD_BVALUES;
     129          30 :     lm->mod_bvalues = NULL;
     130             : 
     131          30 :     len = strlen(type);
     132          30 :     lm->mod_type = PyMem_NEW(char, len + 1);
     133          30 :     if (lm->mod_type == NULL)
     134           0 :         goto nomem;
     135          30 :     memcpy(lm->mod_type, type, len + 1);
     136             : 
     137          30 :     if (list == Py_None) {
     138             :         /* None indicates a NULL mod_bvals */
     139          30 :     } else if (PyBytes_Check(list)) {
     140             :         /* Single string is a singleton list */
     141          23 :         lm->mod_bvalues = PyMem_NEW(struct berval *, 2);
     142          23 :         if (lm->mod_bvalues == NULL)
     143           0 :             goto nomem;
     144          23 :         lm->mod_bvalues[0] = PyMem_NEW(struct berval, 1);
     145          23 :         if (lm->mod_bvalues[0] == NULL)
     146           0 :             goto nomem;
     147          23 :         lm->mod_bvalues[1] = NULL;
     148          23 :         lm->mod_bvalues[0]->bv_len = PyBytes_Size(list);
     149          23 :         lm->mod_bvalues[0]->bv_val = PyBytes_AsString(list);
     150           7 :     } else if (PySequence_Check(list)) {
     151           7 :         nstrs = PySequence_Length(list);
     152           7 :         lm->mod_bvalues = PyMem_NEW(struct berval *, nstrs + 1);
     153           7 :         if (lm->mod_bvalues == NULL)
     154           0 :             goto nomem;
     155          15 :         for (i = 0; i < nstrs; i++) {
     156           8 :           lm->mod_bvalues[i] = PyMem_NEW(struct berval, 1);
     157           8 :           if (lm->mod_bvalues[i] == NULL)
     158           0 :               goto nomem;
     159           8 :           lm->mod_bvalues[i+1] = NULL;
     160           8 :           item = PySequence_GetItem(list, i);
     161           8 :           if (item == NULL)
     162           0 :               goto error;
     163           8 :           if (!PyBytes_Check(item)) {
     164           0 :               LDAPerror_TypeError("expected a byte string in the list", item);
     165           0 :               goto error;
     166             :           }
     167           8 :           lm->mod_bvalues[i]->bv_len = PyBytes_Size(item);
     168           8 :           lm->mod_bvalues[i]->bv_val = PyBytes_AsString(item);
     169           8 :           Py_DECREF(item);
     170             :         }
     171           7 :         if (nstrs == 0)
     172           0 :             lm->mod_bvalues[0] = NULL;
     173             :     }
     174             : 
     175          30 :     return lm;
     176             : 
     177           0 : nomem:
     178           0 :     PyErr_NoMemory();
     179           0 : error:
     180           0 :     if (lm) 
     181           0 :         LDAPMod_DEL(lm);
     182             : 
     183           0 :     return NULL;
     184             : }
     185             : 
     186             : /* free the structure allocated in List_to_LDAPMods() */
     187             : 
     188             : static void
     189          15 : LDAPMods_DEL( LDAPMod** lms ) {
     190             :     LDAPMod** lmp;
     191          45 :     for ( lmp = lms; *lmp; lmp++ )
     192          30 :         LDAPMod_DEL( *lmp );
     193          15 :     PyMem_DEL(lms);
     194          15 : }
     195             : 
     196             : /* 
     197             :  * convert a list of tuples into a LDAPMod*[] array structure 
     198             :  * NOTE: list of tuples must live longer than the LDAPMods
     199             :  */
     200             : 
     201             : static LDAPMod**
     202          15 : List_to_LDAPMods( PyObject *list, int no_op ) {
     203             : 
     204             :     Py_ssize_t i, len;
     205             :     LDAPMod** lms;
     206             :     PyObject *item;
     207             : 
     208          15 :     if (!PySequence_Check(list)) {
     209           0 :         LDAPerror_TypeError("expected list of tuples", list);
     210           0 :         return NULL;
     211             :     }
     212             : 
     213          15 :     len = PySequence_Length(list);
     214             : 
     215          15 :     if (len < 0) {
     216           0 :         LDAPerror_TypeError("expected list of tuples", list);
     217           0 :         return NULL;
     218             :     }
     219             : 
     220          15 :     lms = PyMem_NEW(LDAPMod *, len + 1);
     221          15 :     if (lms == NULL) 
     222           0 :         goto nomem;
     223             : 
     224          45 :     for (i = 0; i < len; i++) {
     225          30 :         lms[i] = NULL;
     226          30 :         item = PySequence_GetItem(list, i);
     227          30 :         if (item == NULL) 
     228           0 :             goto error;
     229          30 :         lms[i] = Tuple_to_LDAPMod(item, no_op);
     230          30 :         Py_DECREF(item);
     231          30 :         if (lms[i] == NULL)
     232           0 :             goto error;
     233             :     }
     234          15 :     lms[len] = NULL;
     235          15 :     return lms;
     236             : 
     237           0 : nomem:
     238           0 :     PyErr_NoMemory();
     239           0 : error:
     240           0 :     if (lms)
     241           0 :         LDAPMods_DEL(lms);
     242           0 :     return NULL;
     243             : }
     244             : 
     245             : /*
     246             :  * convert a python list of strings into an attr list (char*[]).
     247             :  * returns 1 if successful, 0 if not (with exception set)
     248             :  */
     249             : 
     250             : int
     251          48 : attrs_from_List( PyObject *attrlist, char***attrsp, PyObject** seq) {
     252             : 
     253          48 :     char **attrs = NULL;
     254             :     Py_ssize_t i, len;
     255             :     PyObject *item;
     256             : 
     257          48 :     *seq = NULL;
     258             : 
     259          48 :     if (attrlist == Py_None) {
     260             :         /* None means a NULL attrlist */
     261             : #if PY_MAJOR_VERSION == 2
     262             :     } else if (PyBytes_Check(attrlist)) {
     263             : #else
     264          23 :     } else if (PyUnicode_Check(attrlist)) {
     265             : #endif
     266             :         /* caught by John Benninghoff <johnb@netscape.com> */
     267           0 :         LDAPerror_TypeError(
     268             :             "expected *list* of strings, not a string", attrlist);
     269           0 :         goto error;
     270             :     } else {
     271          23 :         *seq = PySequence_Fast(attrlist, "expected list of strings or None");
     272          23 :         if (*seq == NULL)
     273           0 :             goto error;
     274             : 
     275          23 :         len = PySequence_Length(attrlist);
     276             : 
     277          23 :         attrs = PyMem_NEW(char *, len + 1);
     278          23 :         if (attrs == NULL)
     279           0 :                 goto nomem;
     280             : 
     281          61 :         for (i = 0; i < len; i++) {
     282          40 :             attrs[i] = NULL;
     283          40 :             item = PySequence_Fast_GET_ITEM(*seq, i);
     284          40 :             if (item == NULL)
     285           0 :                 goto error;
     286             : #if PY_MAJOR_VERSION == 2
     287             :             /* Encoded by Python to UTF-8 */
     288             :             if (!PyBytes_Check(item)) {
     289             :                 LDAPerror_TypeError("expected bytes in list", item);
     290             :                 goto error;
     291             :             }
     292             :             attrs[i] = PyBytes_AsString(item);
     293             : #else
     294          40 :             if (!PyUnicode_Check(item)) {
     295           2 :                 LDAPerror_TypeError("expected string in list", item);
     296           2 :                 goto error;
     297             :             }
     298          38 :             attrs[i] = PyUnicode_AsUTF8(item);
     299             : #endif
     300             :         }
     301          21 :         attrs[len] = NULL;
     302             :     }
     303             : 
     304          46 :     *attrsp = attrs;
     305          94 :     return 1;
     306             : 
     307           0 : nomem:
     308           0 :     PyErr_NoMemory();
     309           2 : error:
     310           2 :     free_attrs(&attrs, *seq);
     311           2 :     return 0;
     312             : }
     313             : 
     314             : /* free memory allocated from above routine */
     315             : 
     316             : static void
     317          48 : free_attrs( char*** attrsp, PyObject* seq ) {
     318          48 :     char **attrs = *attrsp;
     319             : 
     320          48 :     if (attrs != NULL) {
     321          23 :         PyMem_DEL(attrs);
     322          23 :         *attrsp = NULL;
     323             :     }
     324             : 
     325          48 :     Py_XDECREF(seq);
     326          48 : }
     327             : 
     328             : /*------------------------------------------------------------
     329             :  * methods
     330             :  */
     331             : 
     332             : /* ldap_unbind_ext */
     333             : 
     334             : static PyObject*
     335          25 : l_ldap_unbind_ext( LDAPObject* self, PyObject* args )
     336             : {
     337          25 :     PyObject *serverctrls = Py_None;
     338          25 :     PyObject *clientctrls = Py_None;
     339          25 :     LDAPControl** server_ldcs = NULL;
     340          25 :     LDAPControl** client_ldcs = NULL;
     341             : 
     342             :     int ldaperror;
     343             : 
     344          50 :     if (!PyArg_ParseTuple( args, "|OO", &serverctrls, &clientctrls)) return NULL;
     345          25 :     if (not_valid(self)) return NULL;
     346             : 
     347          24 :     if (!PyNone_Check(serverctrls)) {
     348           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
     349           1 :             return NULL;
     350             :     }
     351             : 
     352          23 :     if (!PyNone_Check(clientctrls)) {
     353           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
     354           1 :             LDAPControl_List_DEL( server_ldcs );
     355           1 :             return NULL;
     356             :         }
     357             :     }
     358             : 
     359          22 :     LDAP_BEGIN_ALLOW_THREADS( self );
     360          22 :     ldaperror = ldap_unbind_ext( self->ldap, server_ldcs, client_ldcs );
     361          22 :     LDAP_END_ALLOW_THREADS( self );
     362             : 
     363          22 :     LDAPControl_List_DEL( server_ldcs );
     364          22 :     LDAPControl_List_DEL( client_ldcs );
     365             : 
     366          22 :     if ( ldaperror!=LDAP_SUCCESS )
     367           0 :         return LDAPerror( self->ldap, "ldap_unbind_ext" );
     368             : 
     369          22 :     self->valid = 0;
     370          22 :     Py_INCREF(Py_None);
     371          22 :     return Py_None;
     372             : }
     373             : 
     374             : /* ldap_abandon_ext */
     375             : 
     376             : static PyObject*
     377           5 : l_ldap_abandon_ext( LDAPObject* self, PyObject* args )
     378             : {
     379             :     int msgid;
     380           5 :     PyObject *serverctrls = Py_None;
     381           5 :     PyObject *clientctrls = Py_None;
     382           5 :     LDAPControl** server_ldcs = NULL;
     383           5 :     LDAPControl** client_ldcs = NULL;
     384             : 
     385             :     int ldaperror;
     386             : 
     387          10 :     if (!PyArg_ParseTuple( args, "i|OO", &msgid, &serverctrls, &clientctrls)) return NULL;
     388           5 :     if (not_valid(self)) return NULL;
     389             : 
     390           5 :     if (!PyNone_Check(serverctrls)) {
     391           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
     392           1 :             return NULL;
     393             :     }
     394             : 
     395           4 :     if (!PyNone_Check(clientctrls)) {
     396           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
     397           1 :             LDAPControl_List_DEL( server_ldcs );
     398           1 :             return NULL;
     399             :         }
     400             :     }
     401             : 
     402           3 :     LDAP_BEGIN_ALLOW_THREADS( self );
     403           3 :     ldaperror = ldap_abandon_ext( self->ldap, msgid, server_ldcs, client_ldcs );
     404           3 :     LDAP_END_ALLOW_THREADS( self );
     405             : 
     406           3 :     LDAPControl_List_DEL( server_ldcs );
     407           3 :     LDAPControl_List_DEL( client_ldcs );
     408             : 
     409           3 :     if ( ldaperror!=LDAP_SUCCESS )
     410           0 :         return LDAPerror( self->ldap, "ldap_abandon_ext" );
     411             : 
     412           3 :     Py_INCREF(Py_None);
     413           3 :     return Py_None;
     414             : }
     415             : 
     416             : /* ldap_add_ext */
     417             : 
     418             : static PyObject *
     419          10 : l_ldap_add_ext( LDAPObject* self, PyObject *args )
     420             : {
     421             :     char *dn;
     422             :     PyObject *modlist;
     423          10 :     PyObject *serverctrls = Py_None;
     424          10 :     PyObject *clientctrls = Py_None;
     425          10 :     LDAPControl** server_ldcs = NULL;
     426          10 :     LDAPControl** client_ldcs = NULL;
     427             : 
     428             :     int msgid;
     429             :     int ldaperror;
     430             :     LDAPMod **mods;
     431             : 
     432          20 :     if (!PyArg_ParseTuple( args, "sO|OO", &dn, &modlist, &serverctrls, &clientctrls )) return NULL;
     433          10 :     if (not_valid(self)) return NULL;
     434             : 
     435          10 :     mods = List_to_LDAPMods( modlist, 1 );
     436          10 :     if (mods == NULL)
     437           0 :         return NULL;
     438             : 
     439          10 :     if (!PyNone_Check(serverctrls)) {
     440           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs)) {
     441           1 :             LDAPMods_DEL( mods );
     442           1 :             return NULL;
     443             :         }
     444             :     }
     445             : 
     446           9 :     if (!PyNone_Check(clientctrls)) {
     447           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
     448           1 :             LDAPMods_DEL( mods );
     449           1 :             LDAPControl_List_DEL( server_ldcs );
     450           1 :             return NULL;
     451             :         }
     452             :     }
     453             : 
     454           8 :     LDAP_BEGIN_ALLOW_THREADS( self );
     455           8 :     ldaperror = ldap_add_ext( self->ldap, dn, mods, server_ldcs, client_ldcs, &msgid);
     456           8 :     LDAP_END_ALLOW_THREADS( self );
     457           8 :     LDAPMods_DEL( mods );
     458           8 :     LDAPControl_List_DEL( server_ldcs );
     459           8 :     LDAPControl_List_DEL( client_ldcs );
     460             : 
     461           8 :     if ( ldaperror!=LDAP_SUCCESS )
     462           0 :         return LDAPerror( self->ldap, "ldap_add_ext" );
     463             : 
     464           8 :     return PyInt_FromLong(msgid);
     465             : }
     466             : 
     467             : /* ldap_simple_bind */
     468             : 
     469             : static PyObject*
     470          95 : l_ldap_simple_bind( LDAPObject* self, PyObject* args )
     471             : {
     472             :     char *who;
     473             :     int msgid;
     474             :     int ldaperror;
     475             :     Py_ssize_t cred_len;
     476          95 :     PyObject *serverctrls = Py_None;
     477          95 :     PyObject *clientctrls = Py_None;
     478          95 :     LDAPControl** server_ldcs = NULL;
     479          95 :     LDAPControl** client_ldcs = NULL;
     480             :     struct berval cred;
     481             : 
     482         190 :     if (!PyArg_ParseTuple( args, "ss#|OO", &who, &cred.bv_val, &cred_len, &serverctrls, &clientctrls )) return NULL;
     483          94 :     cred.bv_len = (ber_len_t) cred_len;
     484             : 
     485          94 :     if (not_valid(self)) return NULL;
     486             : 
     487          94 :     if (!PyNone_Check(serverctrls)) {
     488           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
     489           1 :             return NULL;
     490             :     }
     491             : 
     492          93 :     if (!PyNone_Check(clientctrls)) {
     493           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
     494           1 :             LDAPControl_List_DEL( server_ldcs );
     495           1 :             return NULL;
     496             :         }
     497             :     }
     498             : 
     499          92 :     LDAP_BEGIN_ALLOW_THREADS( self );
     500          92 :     ldaperror = ldap_sasl_bind( self->ldap, who, LDAP_SASL_SIMPLE, &cred, server_ldcs, client_ldcs, &msgid);
     501          92 :     LDAP_END_ALLOW_THREADS( self );
     502             : 
     503          92 :     LDAPControl_List_DEL( server_ldcs );
     504          92 :     LDAPControl_List_DEL( client_ldcs );
     505             : 
     506          92 :     if ( ldaperror!=LDAP_SUCCESS )
     507           4 :         return LDAPerror( self->ldap, "ldap_simple_bind" );
     508             : 
     509          88 :     return PyInt_FromLong( msgid );
     510             : }
     511             : 
     512             : 
     513             : #ifdef HAVE_SASL
     514             : /* The following functions implement SASL binds. A new method
     515             :    sasl_interactive_bind_s(bind_dn, sasl_mechanism) has been introduced.
     516             : 
     517             :    * The bind_dn argument will be passed to the c library; however,
     518             :      normally it is not needed and should be an empty string.
     519             : 
     520             :    * The sasl_mechanism argument is an instance of a class that
     521             :      implements a callback interface. For convenience, it should be
     522             :      derived from the sasl class (which lives in the ldap.sasl module).
     523             :      See the module documentation for more information.
     524             : 
     525             :      Check your /usr/lib/sasl/ directory for locally installed SASL
     526             :      auth modules ("mechanisms"), or try
     527             : 
     528             :        ldapsearch   -b "" -s base -LLL -x  supportedSASLMechanisms
     529             :      
     530             :      (perhaps with an additional -h and -p argument for ldap host and
     531             :      port). The latter will show you which SASL mechanisms are known
     532             :      to the LDAP server. If you do not want to set up Kerberos, you
     533             :      can still use SASL binds. Your authentication data should then be
     534             :      stored in /etc/sasldb (see saslpasswd(8)). If the LDAP server
     535             :      does not find the sasldb, it wont allow for DIGEST-MD5 and
     536             :      CRAM-MD5. One important thing to get started with sasldb: you
     537             :      should first add a dummy user (saslpasswd -c dummy), and this
     538             :      will give you some strange error messages. Then delete the dummy
     539             :      user (saslpasswd -d dummy), and now you can start adding users to
     540             :      your sasldb (again, use the -c switch). Strange, eh?
     541             : 
     542             :    * The sasl_mechanism object must implement a method, which will be
     543             :      called by the sasl lib several times. The prototype of the
     544             :      callback looks like this: callback(id, challenge, prompt,
     545             :      defresult) has to return a string (or maybe None). The id
     546             :      argument specifies, which information should be passed back to
     547             :      the SASL lib (see SASL_CB_xxx in sasl.h)
     548             : */
     549           9 : static int interaction ( unsigned flags, 
     550             :                          sasl_interact_t *interact,
     551             :                          PyObject* SASLObject )
     552             : {
     553             : /*  const char *dflt = interact->defresult; */
     554             :   PyObject *result;
     555             :   char *c_result;
     556           9 :   result = PyObject_CallMethod(SASLObject,
     557             :                                "callback",
     558             :                                "isss",
     559             :                                interact->id,  /* see sasl.h */
     560             :                                interact->challenge,
     561             :                                interact->prompt,   
     562             :                                interact->defresult);
     563             : 
     564           9 :   if (result == NULL) 
     565             :     /*searching for a better error code */
     566           0 :     return LDAP_OPERATIONS_ERROR; 
     567           9 :   c_result = PyBytes_AsString(result); /*xxx Error checking?? */
     568             :   
     569             :   /* according to the sasl docs, we should malloc() the returned
     570             :      string only for calls where interact->id == SASL_CB_PASS, so we
     571             :      probably leak a few bytes per ldap bind. However, if I restrict
     572             :      the strdup() to this case, I get segfaults. Should probably be
     573             :      fixed sometimes.
     574             :   */
     575           9 :   interact->result = strdup( c_result );
     576           9 :   if (interact->result == NULL)
     577           0 :     return LDAP_OPERATIONS_ERROR;
     578           9 :   interact->len = strlen(c_result);
     579             :   /* We _should_ overwrite the python string buffer for security
     580             :      reasons, however we may not (api/stringObjects.html). Any ideas?
     581             :   */
     582             :   
     583           9 :   Py_DECREF(result); /*not needed any longer */
     584           9 :   result = NULL;
     585             :   
     586           9 :   return LDAP_SUCCESS;
     587             : }
     588             : 
     589             : 
     590             : /* 
     591             :   This function will be called by ldap_sasl_interactive_bind(). The
     592             :   "*in" is an array of sasl_interact_t's (see sasl.h for a
     593             :   reference). The last interact in the array has an interact->id of
     594             :   SASL_CB_LIST_END.
     595             : 
     596             : */
     597             : 
     598           9 : int py_ldap_sasl_interaction(   LDAP *ld, 
     599             :                                 unsigned flags, 
     600             :                                 void *defaults,
     601             :                                 void *in )
     602             : {
     603             :   /* These are just typecasts */
     604           9 :   sasl_interact_t *interact = (sasl_interact_t *) in;
     605           9 :   PyObject *SASLObject = (PyObject *) defaults;
     606             :   /* Loop over the array of sasl_interact_t structs */
     607          27 :   while( interact->id != SASL_CB_LIST_END ) {
     608           9 :     int rc = 0;
     609           9 :     rc = interaction( flags, interact, SASLObject );
     610           9 :     if( rc )  return rc;
     611           9 :     interact++;
     612             :   }
     613           9 :   return LDAP_SUCCESS;
     614             : }
     615             : 
     616             : static PyObject*
     617           2 : l_ldap_sasl_bind_s( LDAPObject* self, PyObject* args )
     618             : {
     619             :     const char *dn;
     620             :     const char *mechanism;
     621             :     struct berval cred;
     622             :     Py_ssize_t cred_len;
     623             : 
     624           2 :     PyObject *serverctrls = Py_None;
     625           2 :     PyObject *clientctrls = Py_None;
     626           2 :     LDAPControl** server_ldcs = NULL;
     627           2 :     LDAPControl** client_ldcs = NULL;
     628             : 
     629             :     struct berval *servercred;
     630             :     int ldaperror;
     631             : 
     632           2 :     if (!PyArg_ParseTuple(args, "zzz#OO", &dn, &mechanism, &cred.bv_val, &cred_len, &serverctrls, &clientctrls ))
     633           2 :         return NULL;
     634             : 
     635           2 :     if (not_valid(self)) return NULL;
     636             : 
     637           2 :     cred.bv_len = cred_len;
     638             : 
     639           2 :     if (!PyNone_Check(serverctrls)) {
     640           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
     641           1 :             return NULL;
     642             :     }
     643           1 :     if (!PyNone_Check(clientctrls)) {
     644           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
     645           1 :             LDAPControl_List_DEL( server_ldcs );
     646           1 :             return NULL;
     647             :         }
     648             :     }
     649             : 
     650           0 :     LDAP_BEGIN_ALLOW_THREADS( self );
     651           0 :     ldaperror = ldap_sasl_bind_s(self->ldap,
     652             :                                  dn,
     653             :                                  mechanism,
     654           0 :                                  cred.bv_val ? &cred : NULL,
     655             :                                  (LDAPControl**) server_ldcs, 
     656             :                                  (LDAPControl**) client_ldcs,
     657             :                                  &servercred);
     658           0 :     LDAP_END_ALLOW_THREADS( self );
     659             : 
     660           0 :     LDAPControl_List_DEL( server_ldcs );
     661           0 :     LDAPControl_List_DEL( client_ldcs );
     662             : 
     663           0 :     if (ldaperror == LDAP_SASL_BIND_IN_PROGRESS) {
     664           0 :         if (servercred && servercred->bv_val && *servercred->bv_val)
     665           0 :             return PyBytes_FromStringAndSize( servercred->bv_val, servercred->bv_len );
     666           0 :     } else if (ldaperror != LDAP_SUCCESS)
     667           0 :         return LDAPerror( self->ldap, "l_ldap_sasl_bind_s" );
     668           0 :     return PyInt_FromLong( ldaperror );
     669             : }
     670             : 
     671             : static PyObject* 
     672          11 : l_ldap_sasl_interactive_bind_s( LDAPObject* self, PyObject* args )
     673             : {
     674             :     char *c_mechanism;
     675             :     char *who;
     676             : 
     677          11 :     PyObject *serverctrls = Py_None;
     678          11 :     PyObject *clientctrls = Py_None;
     679          11 :     LDAPControl** server_ldcs = NULL;
     680          11 :     LDAPControl** client_ldcs = NULL;
     681             : 
     682          11 :     PyObject       *SASLObject = NULL;
     683          11 :     PyObject *mechanism = NULL;
     684             :     int msgid;
     685             : 
     686             :     static unsigned sasl_flags = LDAP_SASL_QUIET;
     687             : 
     688             :     /* 
     689             :      * In Python 2.3+, a "I" format argument indicates that we're either converting
     690             :      * the Python object into a long or an unsigned int. In versions prior to that,
     691             :      * it will always convert to a long. Since the sasl_flags variable is an
     692             :      * unsigned int, we need to use the "I" flag if we're running Python 2.3+ and a
     693             :      * "i" otherwise. 
     694             :      */
     695             : #if (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION < 3)
     696             :     if (!PyArg_ParseTuple(args, "sOOOi", &who, &SASLObject, &serverctrls, &clientctrls, &sasl_flags ))
     697             : #else
     698          11 :     if (!PyArg_ParseTuple(args, "sOOOI", &who, &SASLObject, &serverctrls, &clientctrls, &sasl_flags ))
     699             : #endif
     700          11 :       return NULL;
     701             : 
     702          11 :     if (not_valid(self)) return NULL;
     703             : 
     704          11 :     if (!PyNone_Check(serverctrls)) {
     705           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
     706           1 :             return NULL;
     707             :     }
     708             : 
     709          10 :     if (!PyNone_Check(clientctrls)) {
     710           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
     711           1 :             LDAPControl_List_DEL( server_ldcs );
     712           1 :             return NULL;
     713             :         }
     714             :     }
     715             : 
     716             :     /* now we extract the sasl mechanism from the SASL Object */
     717           9 :     mechanism = PyObject_GetAttrString(SASLObject, "mech");
     718           9 :     if (mechanism == NULL) return NULL;
     719           9 :     c_mechanism = PyBytes_AsString(mechanism);
     720           9 :     Py_DECREF(mechanism);
     721           9 :     mechanism = NULL;
     722             : 
     723             :     /* Don't know if it is the "intended use" of the defaults
     724             :        parameter of ldap_sasl_interactive_bind_s when we pass the
     725             :        Python object SASLObject, but passing it through some
     726             :        static variable would destroy thread safety, IMHO.
     727             :      */
     728           9 :     msgid = ldap_sasl_interactive_bind_s(self->ldap, 
     729             :                                          who, 
     730             :                                          c_mechanism, 
     731             :                                          (LDAPControl**) server_ldcs, 
     732             :                                          (LDAPControl**) client_ldcs,
     733             :                                          sasl_flags, 
     734             :                                          py_ldap_sasl_interaction, 
     735             :                                          SASLObject);
     736             : 
     737           9 :     LDAPControl_List_DEL( server_ldcs );
     738           9 :     LDAPControl_List_DEL( client_ldcs );
     739             : 
     740           9 :     if (msgid != LDAP_SUCCESS)
     741           1 :         return LDAPerror( self->ldap, "ldap_sasl_interactive_bind_s" );
     742           8 :     return PyInt_FromLong( msgid );
     743             : }
     744             : #endif
     745             : 
     746             : 
     747             : #ifdef LDAP_API_FEATURE_CANCEL
     748             : 
     749             : /* ldap_cancel */
     750             : 
     751             : static PyObject*
     752           3 : l_ldap_cancel( LDAPObject* self, PyObject* args )
     753             : {
     754             :     int msgid;
     755             :     int cancelid;
     756           3 :     PyObject *serverctrls = Py_None;
     757           3 :     PyObject *clientctrls = Py_None;
     758           3 :     LDAPControl** server_ldcs = NULL;
     759           3 :     LDAPControl** client_ldcs = NULL;
     760             : 
     761             :     int ldaperror;
     762             : 
     763           6 :     if (!PyArg_ParseTuple( args, "i|OO", &cancelid, &serverctrls, &clientctrls)) return NULL;
     764           3 :     if (not_valid(self)) return NULL;
     765             : 
     766           3 :     if (!PyNone_Check(serverctrls)) {
     767           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
     768           1 :             return NULL;
     769             :     }
     770             : 
     771           2 :     if (!PyNone_Check(clientctrls)) {
     772           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
     773           1 :             LDAPControl_List_DEL( server_ldcs );
     774           1 :             return NULL;
     775             :         }
     776             :     }
     777             : 
     778           1 :     LDAP_BEGIN_ALLOW_THREADS( self );
     779           1 :     ldaperror = ldap_cancel( self->ldap, cancelid, server_ldcs, client_ldcs, &msgid );
     780           1 :     LDAP_END_ALLOW_THREADS( self );
     781             : 
     782           1 :     LDAPControl_List_DEL( server_ldcs );
     783           1 :     LDAPControl_List_DEL( client_ldcs );
     784             : 
     785           1 :     if ( ldaperror!=LDAP_SUCCESS )
     786           0 :         return LDAPerror( self->ldap, "ldap_cancel" );
     787             : 
     788           1 :     return PyInt_FromLong( msgid );
     789             : }
     790             : 
     791             : #endif
     792             : 
     793             : /* ldap_compare_ext */
     794             : 
     795             : static PyObject *
     796           5 : l_ldap_compare_ext( LDAPObject* self, PyObject *args )
     797             : {
     798             :     char *dn, *attr;
     799           5 :     PyObject *serverctrls = Py_None;
     800           5 :     PyObject *clientctrls = Py_None;
     801           5 :     LDAPControl** server_ldcs = NULL;
     802           5 :     LDAPControl** client_ldcs = NULL;
     803             : 
     804             :     int msgid;
     805             :     int ldaperror;
     806             :     Py_ssize_t value_len;
     807             :     struct berval value;
     808             : 
     809          10 :     if (!PyArg_ParseTuple( args, "sss#|OO", &dn, &attr, &value.bv_val, &value_len, &serverctrls, &clientctrls )) return NULL;
     810           5 :     value.bv_len = (ber_len_t) value_len;
     811             : 
     812           5 :     if (not_valid(self)) return NULL;
     813             : 
     814           5 :     if (!PyNone_Check(serverctrls)) {
     815           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
     816           1 :             return NULL;
     817             :     }
     818             : 
     819           4 :     if (!PyNone_Check(clientctrls)) {
     820           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
     821           1 :             LDAPControl_List_DEL( server_ldcs );
     822           1 :             return NULL;
     823             :         }
     824             :     }
     825             : 
     826           3 :     LDAP_BEGIN_ALLOW_THREADS( self );
     827           3 :     ldaperror = ldap_compare_ext( self->ldap, dn, attr, &value, server_ldcs, client_ldcs, &msgid );
     828           3 :     LDAP_END_ALLOW_THREADS( self );
     829             : 
     830           3 :     LDAPControl_List_DEL( server_ldcs );
     831           3 :     LDAPControl_List_DEL( client_ldcs );
     832             : 
     833           3 :     if ( ldaperror!=LDAP_SUCCESS )
     834           0 :         return LDAPerror( self->ldap, "ldap_compare_ext" );
     835             : 
     836           3 :     return PyInt_FromLong( msgid );
     837             : }
     838             : 
     839             : 
     840             : /* ldap_delete_ext */
     841             : 
     842             : static PyObject *
     843           5 : l_ldap_delete_ext( LDAPObject* self, PyObject *args )
     844             : {
     845             :     char *dn;
     846           5 :     PyObject *serverctrls = Py_None;
     847           5 :     PyObject *clientctrls = Py_None;
     848           5 :     LDAPControl** server_ldcs = NULL;
     849           5 :     LDAPControl** client_ldcs = NULL;
     850             : 
     851             :     int msgid;
     852             :     int ldaperror;
     853             : 
     854          10 :     if (!PyArg_ParseTuple( args, "s|OO", &dn, &serverctrls, &clientctrls )) return NULL;
     855           5 :     if (not_valid(self)) return NULL;
     856             : 
     857           5 :     if (!PyNone_Check(serverctrls)) {
     858           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
     859           1 :             return NULL;
     860             :     }
     861             : 
     862           4 :     if (!PyNone_Check(clientctrls)) {
     863           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
     864           1 :             LDAPControl_List_DEL( server_ldcs );
     865           1 :             return NULL;
     866             :         }
     867             :     }
     868             : 
     869           3 :     LDAP_BEGIN_ALLOW_THREADS( self );
     870           3 :     ldaperror = ldap_delete_ext( self->ldap, dn, server_ldcs, client_ldcs, &msgid );
     871           3 :     LDAP_END_ALLOW_THREADS( self );
     872             : 
     873           3 :     LDAPControl_List_DEL( server_ldcs );
     874           3 :     LDAPControl_List_DEL( client_ldcs );
     875             : 
     876           3 :     if ( ldaperror!=LDAP_SUCCESS )
     877           0 :         return LDAPerror( self->ldap, "ldap_delete_ext" );
     878             : 
     879           3 :     return PyInt_FromLong(msgid);
     880             : }
     881             : 
     882             : 
     883             : /* ldap_modify_ext */
     884             : 
     885             : static PyObject *
     886           5 : l_ldap_modify_ext( LDAPObject* self, PyObject *args )
     887             : {
     888             :     char *dn;
     889             :     PyObject *modlist;
     890           5 :     PyObject *serverctrls = Py_None;
     891           5 :     PyObject *clientctrls = Py_None;
     892           5 :     LDAPControl** server_ldcs = NULL;
     893           5 :     LDAPControl** client_ldcs = NULL;
     894             : 
     895             :     int msgid;
     896             :     int ldaperror;
     897             :     LDAPMod **mods;
     898             : 
     899          10 :     if (!PyArg_ParseTuple( args, "sO|OO", &dn, &modlist, &serverctrls, &clientctrls )) return NULL;
     900           5 :     if (not_valid(self)) return NULL;
     901             : 
     902           5 :     mods = List_to_LDAPMods( modlist, 0 );
     903           5 :     if (mods == NULL)
     904           0 :         return NULL;
     905             : 
     906           5 :     if (!PyNone_Check(serverctrls)) {
     907           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs)) {
     908           1 :             LDAPMods_DEL( mods );
     909           1 :             return NULL;
     910             :         }
     911             :     }
     912             : 
     913           4 :     if (!PyNone_Check(clientctrls)) {
     914           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
     915           1 :             LDAPMods_DEL( mods );
     916           1 :             LDAPControl_List_DEL( server_ldcs );
     917           1 :             return NULL;
     918             :         }
     919             :     }
     920             : 
     921           3 :     LDAP_BEGIN_ALLOW_THREADS( self );
     922           3 :     ldaperror = ldap_modify_ext( self->ldap, dn, mods, server_ldcs, client_ldcs, &msgid );
     923           3 :     LDAP_END_ALLOW_THREADS( self );
     924             : 
     925           3 :     LDAPMods_DEL( mods );
     926           3 :     LDAPControl_List_DEL( server_ldcs );
     927           3 :     LDAPControl_List_DEL( client_ldcs );
     928             : 
     929           3 :     if ( ldaperror!=LDAP_SUCCESS )
     930           0 :         return LDAPerror( self->ldap, "ldap_modify_ext" );
     931             : 
     932           3 :     return PyInt_FromLong( msgid );
     933             : }
     934             : 
     935             : 
     936             : /* ldap_rename */
     937             : 
     938             : static PyObject *
     939           4 : l_ldap_rename( LDAPObject* self, PyObject *args )
     940             : {
     941             :     char *dn, *newrdn;
     942           4 :     char *newSuperior = NULL;
     943           4 :     int delold = 1;
     944           4 :     PyObject *serverctrls = Py_None;
     945           4 :     PyObject *clientctrls = Py_None;
     946           4 :     LDAPControl** server_ldcs = NULL;
     947           4 :     LDAPControl** client_ldcs = NULL;
     948             : 
     949             :     int msgid;
     950             :     int ldaperror;
     951             : 
     952           4 :     if (!PyArg_ParseTuple( args, "ss|ziOO", &dn, &newrdn, &newSuperior, &delold, &serverctrls, &clientctrls ))
     953           4 :         return NULL;
     954           4 :     if (not_valid(self)) return NULL;
     955             : 
     956           4 :     if (!PyNone_Check(serverctrls)) {
     957           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
     958           1 :             return NULL;
     959             :     }
     960             : 
     961           3 :     if (!PyNone_Check(clientctrls)) {
     962           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
     963           1 :             LDAPControl_List_DEL( server_ldcs );
     964           1 :             return NULL;
     965             :         }
     966             :     }
     967             : 
     968           2 :     LDAP_BEGIN_ALLOW_THREADS( self );
     969           2 :     ldaperror = ldap_rename( self->ldap, dn, newrdn, newSuperior, delold, server_ldcs, client_ldcs, &msgid );
     970           2 :     LDAP_END_ALLOW_THREADS( self );
     971             : 
     972           2 :     LDAPControl_List_DEL( server_ldcs );
     973           2 :     LDAPControl_List_DEL( client_ldcs );
     974             : 
     975           2 :     if ( ldaperror!=LDAP_SUCCESS )
     976           0 :         return LDAPerror( self->ldap, "ldap_rename" );
     977             : 
     978           2 :     return PyInt_FromLong( msgid );
     979             : }
     980             : 
     981             : 
     982             : /* ldap_result4 */
     983             : 
     984             : static PyObject *
     985         177 : l_ldap_result4( LDAPObject* self, PyObject *args )
     986             : {
     987         177 :     int msgid = LDAP_RES_ANY;
     988         177 :     int all = 1;
     989         177 :     double timeout = -1.0;
     990         177 :     int add_ctrls = 0;
     991         177 :     int add_intermediates = 0;
     992         177 :     int add_extop = 0;
     993             :     struct timeval tv;
     994             :     struct timeval* tvp;
     995             :     int res_type;
     996         177 :     LDAPMessage *msg = NULL;
     997         177 :     PyObject *result_str, *retval, *pmsg, *pyctrls = 0;
     998         177 :     int res_msgid = 0;
     999         177 :     char *retoid = 0;
    1000         177 :     PyObject *valuestr = NULL;
    1001         177 :     int result = LDAP_SUCCESS;
    1002         177 :     char **refs = NULL;
    1003         177 :     LDAPControl **serverctrls = 0;
    1004             : 
    1005         177 :     if (!PyArg_ParseTuple( args, "|iidiii", &msgid, &all, &timeout, &add_ctrls, &add_intermediates, &add_extop ))
    1006         177 :         return NULL;
    1007         177 :     if (not_valid(self)) return NULL;
    1008             :     
    1009         177 :     if (timeout >= 0) {
    1010          58 :         tvp = &tv;
    1011          58 :         set_timeval_from_double( tvp, timeout );
    1012             :     } else {
    1013         119 :         tvp = NULL;
    1014             :     }
    1015             : 
    1016         177 :     LDAP_BEGIN_ALLOW_THREADS( self );
    1017         177 :     res_type = ldap_result( self->ldap, msgid, all, tvp, &msg );
    1018         177 :     LDAP_END_ALLOW_THREADS( self );
    1019             : 
    1020         177 :     if (res_type < 0)   /* LDAP or system error */
    1021           0 :         return LDAPerror( self->ldap, "ldap_result4" );
    1022             : 
    1023         177 :     if (res_type == 0) {
    1024             :         /* Polls return (None, None, None, None); timeouts raise an exception */
    1025           4 :         if (timeout == 0) {
    1026           0 :             if (add_extop) {
    1027           0 :                 return Py_BuildValue("(OOOOOO)", Py_None, Py_None, Py_None, Py_None, Py_None, Py_None);
    1028             :             } else {
    1029           0 :                 return Py_BuildValue("(OOOO)", Py_None, Py_None, Py_None, Py_None);
    1030             :             }
    1031             :         }
    1032             :         else
    1033           4 :             return LDAPerr(LDAP_TIMEOUT);
    1034             :     }
    1035             : 
    1036         173 :     if (msg)
    1037         173 :         res_msgid = ldap_msgid(msg);
    1038             : 
    1039         173 :     if (res_type == LDAP_RES_SEARCH_ENTRY) {
    1040             :         /* LDAPmessage_to_python will parse entries and read the controls for each entry */
    1041         144 :     } else if (res_type == LDAP_RES_SEARCH_REFERENCE) {
    1042             :         /* LDAPmessage_to_python will parse refs and read the controls for each res */
    1043         144 :     } else if (res_type == LDAP_RES_INTERMEDIATE) {
    1044             :         /* LDAPmessage_to_python will parse intermediates and controls */
    1045             :     } else {
    1046             :         int rc;
    1047         141 :         if (res_type == LDAP_RES_EXTENDED) {
    1048           2 :             struct berval *retdata = 0;
    1049           2 :             LDAP_BEGIN_ALLOW_THREADS( self );
    1050           2 :             rc = ldap_parse_extended_result( self->ldap, msg, &retoid, &retdata, 0 );
    1051           2 :             LDAP_END_ALLOW_THREADS( self );
    1052             :             /* handle error rc!=0 here? */
    1053           2 :             if (rc == LDAP_SUCCESS) {
    1054           2 :                 valuestr = LDAPberval_to_object(retdata);
    1055             :             }
    1056           2 :             ber_bvfree( retdata );
    1057             :         }
    1058             :             
    1059         141 :         LDAP_BEGIN_ALLOW_THREADS( self );
    1060         141 :         rc = ldap_parse_result( self->ldap, msg, &result, NULL, NULL, &refs,
    1061             :                                 &serverctrls, 0 );
    1062         141 :         LDAP_END_ALLOW_THREADS( self );
    1063             :     }
    1064             : 
    1065         173 :     if (result != LDAP_SUCCESS) {               /* result error */
    1066             :         char *e, err[1024];
    1067          15 :         if (result == LDAP_REFERRAL && refs && refs[0]) {
    1068           0 :             snprintf(err, sizeof(err), "Referral:\n%s", refs[0]);
    1069           0 :             e = err;
    1070             :         } else
    1071          15 :             e = "ldap_parse_result";
    1072          15 :         ldap_msgfree(msg);
    1073          15 :         Py_XDECREF(valuestr);
    1074          15 :         return LDAPerror( self->ldap, e );
    1075             :     }
    1076             : 
    1077         158 :     if (!(pyctrls = LDAPControls_to_List(serverctrls))) {
    1078           0 :         int err = LDAP_NO_MEMORY;
    1079           0 :         LDAP_BEGIN_ALLOW_THREADS( self );
    1080           0 :         ldap_set_option(self->ldap, LDAP_OPT_ERROR_NUMBER, &err);
    1081           0 :         LDAP_END_ALLOW_THREADS( self );
    1082           0 :         ldap_msgfree(msg);
    1083           0 :         Py_XDECREF(valuestr);
    1084           0 :         return LDAPerror(self->ldap, "LDAPControls_to_List");
    1085             :     }
    1086         158 :     ldap_controls_free(serverctrls);
    1087             : 
    1088         158 :     pmsg = LDAPmessage_to_python( self->ldap, msg, add_ctrls, add_intermediates );
    1089             : 
    1090         158 :     if (res_type == 0) {
    1091           0 :         result_str = Py_None;
    1092           0 :         Py_INCREF(Py_None);
    1093             :     } else {
    1094         158 :         result_str = PyInt_FromLong( res_type );
    1095             :     }
    1096             : 
    1097         158 :     if (pmsg == NULL) {
    1098           0 :             retval = NULL;
    1099             :     } else {
    1100             :         /* s handles NULL, but O does not */
    1101         158 :         if (add_extop) {
    1102           0 :             retval = Py_BuildValue("(OOiOsO)", result_str, pmsg, res_msgid,
    1103             :                                    pyctrls, retoid, valuestr ? valuestr : Py_None);
    1104             :         } else {
    1105         158 :             retval = Py_BuildValue("(OOiO)", result_str, pmsg, res_msgid, pyctrls);
    1106             :         }
    1107             : 
    1108         158 :         if (pmsg != Py_None) {
    1109         158 :         Py_DECREF(pmsg);
    1110             :         }
    1111             :     }
    1112         158 :     Py_XDECREF(valuestr);
    1113         158 :     Py_XDECREF(pyctrls);
    1114         158 :     Py_DECREF(result_str);
    1115         158 :     return retval;
    1116             : }
    1117             : 
    1118             : 
    1119             : /* ldap_search_ext */
    1120             : 
    1121             : static PyObject*
    1122          52 : l_ldap_search_ext( LDAPObject* self, PyObject* args )
    1123             : {
    1124             :     char *base;
    1125             :     int scope;
    1126             :     char *filter;
    1127          52 :     PyObject *attrlist = Py_None;
    1128             :     char **attrs;
    1129          52 :     int attrsonly = 0;
    1130             : 
    1131          52 :     PyObject *serverctrls = Py_None;
    1132          52 :     PyObject *clientctrls = Py_None;
    1133          52 :     PyObject *attrs_seq = NULL;
    1134          52 :     LDAPControl** server_ldcs = NULL;
    1135          52 :     LDAPControl** client_ldcs = NULL;
    1136             : 
    1137          52 :     double timeout = -1.0;
    1138             :     struct timeval tv;
    1139             :     struct timeval* tvp;
    1140             : 
    1141          52 :     int sizelimit = 0;
    1142             : 
    1143             :     int msgid;
    1144             :     int ldaperror;
    1145             : 
    1146          52 :     if (!PyArg_ParseTuple( args, "sis|OiOOdi",
    1147             :                            &base, &scope, &filter, &attrlist, &attrsonly,
    1148          56 :                            &serverctrls, &clientctrls, &timeout, &sizelimit )) return NULL;
    1149          48 :     if (not_valid(self)) return NULL;
    1150             : 
    1151          48 :     if (!attrs_from_List( attrlist, &attrs, &attrs_seq ))
    1152           2 :          return NULL;
    1153             : 
    1154          46 :     if (timeout >= 0) {
    1155           0 :         tvp = &tv;
    1156           0 :         set_timeval_from_double( tvp, timeout );
    1157             :     } else {
    1158          46 :         tvp = NULL;
    1159             :     }
    1160             : 
    1161          46 :     if (!PyNone_Check(serverctrls)) {
    1162           7 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs)) {
    1163           1 :             free_attrs( &attrs,  attrs_seq);
    1164           1 :             return NULL;
    1165             :         }
    1166             :     }
    1167             : 
    1168          45 :     if (!PyNone_Check(clientctrls)) {
    1169           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
    1170           1 :             free_attrs( &attrs,  attrs_seq);
    1171           1 :             LDAPControl_List_DEL( server_ldcs );
    1172           1 :             return NULL;
    1173             :         }
    1174             :     }
    1175             : 
    1176          44 :     LDAP_BEGIN_ALLOW_THREADS( self );
    1177          44 :     ldaperror = ldap_search_ext( self->ldap, base, scope, filter, attrs, attrsonly,
    1178             :                              server_ldcs, client_ldcs, tvp, sizelimit, &msgid );
    1179          44 :     LDAP_END_ALLOW_THREADS( self );
    1180             : 
    1181          44 :     free_attrs( &attrs,  attrs_seq);
    1182          44 :     LDAPControl_List_DEL( server_ldcs );
    1183          44 :     LDAPControl_List_DEL( client_ldcs );
    1184             : 
    1185          44 :     if ( ldaperror!=LDAP_SUCCESS )
    1186           2 :         return LDAPerror( self->ldap, "ldap_search_ext" );
    1187             : 
    1188          42 :     return PyInt_FromLong( msgid );
    1189             : }       
    1190             : 
    1191             : 
    1192             : /* ldap_whoami_s (available since OpenLDAP 2.1.13) */
    1193             : 
    1194             : static PyObject*
    1195          21 : l_ldap_whoami_s( LDAPObject* self, PyObject* args )
    1196             : {
    1197          21 :     PyObject *serverctrls = Py_None;
    1198          21 :     PyObject *clientctrls = Py_None;
    1199          21 :     LDAPControl** server_ldcs = NULL;
    1200          21 :     LDAPControl** client_ldcs = NULL;
    1201             : 
    1202          21 :     struct berval *bvalue = NULL;
    1203             : 
    1204             :     PyObject *result;
    1205             : 
    1206             :     int ldaperror;
    1207             : 
    1208          42 :     if (!PyArg_ParseTuple( args, "|OO", &serverctrls, &clientctrls)) return NULL;
    1209          21 :     if (not_valid(self)) return NULL;
    1210             : 
    1211          20 :     if (!PyNone_Check(serverctrls)) {
    1212           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
    1213           1 :             return NULL;
    1214             :     }
    1215             : 
    1216          19 :     if (!PyNone_Check(clientctrls)) {
    1217           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
    1218           1 :             LDAPControl_List_DEL( server_ldcs );
    1219           1 :             return NULL;
    1220             :         }
    1221             :     }
    1222             : 
    1223          18 :     LDAP_BEGIN_ALLOW_THREADS( self );
    1224          18 :     ldaperror = ldap_whoami_s( self->ldap, &bvalue, server_ldcs, client_ldcs );
    1225          18 :     LDAP_END_ALLOW_THREADS( self );
    1226             : 
    1227          18 :     LDAPControl_List_DEL( server_ldcs );
    1228          18 :     LDAPControl_List_DEL( client_ldcs );
    1229             : 
    1230          18 :     if ( ldaperror!=LDAP_SUCCESS ) {
    1231           2 :         ber_bvfree(bvalue);
    1232           2 :         return LDAPerror( self->ldap, "ldap_whoami_s" );
    1233             :     }
    1234             : 
    1235          16 :     result = LDAPberval_to_unicode_object(bvalue);
    1236             : #ifdef DEMO_LEAK
    1237             :     /* ldap_whoami_s() allocates memory in bvalue but we are not freeing it */
    1238             : #else
    1239             :     ber_bvfree(bvalue);
    1240             : #endif
    1241             : 
    1242          16 :     return result;
    1243             : }
    1244             : 
    1245             : #ifdef HAVE_TLS
    1246             : /* ldap_start_tls_s */
    1247             : 
    1248             : static PyObject*
    1249           4 : l_ldap_start_tls_s( LDAPObject* self, PyObject* args )
    1250             : {
    1251             :     int ldaperror;
    1252             : 
    1253           8 :     if (!PyArg_ParseTuple( args, "" )) return NULL;
    1254           4 :     if (not_valid(self)) return NULL;
    1255             : 
    1256           4 :     LDAP_BEGIN_ALLOW_THREADS( self );
    1257           4 :     ldaperror = ldap_start_tls_s( self->ldap, NULL, NULL );
    1258           4 :     LDAP_END_ALLOW_THREADS( self );
    1259           4 :     if ( ldaperror != LDAP_SUCCESS ){
    1260           1 :         ldap_set_option(self->ldap, LDAP_OPT_ERROR_NUMBER, &ldaperror);
    1261           1 :         return LDAPerror( self->ldap, "ldap_start_tls_s" );
    1262             :     }
    1263             : 
    1264           3 :     Py_INCREF(Py_None);
    1265           3 :     return Py_None;
    1266             : }
    1267             : 
    1268             : #endif
    1269             : 
    1270             : /* ldap_set_option */
    1271             : 
    1272             : static PyObject*
    1273         198 : l_ldap_set_option(PyObject* self, PyObject *args)
    1274             : {
    1275             :     PyObject *value;
    1276             :     int option;
    1277             : 
    1278         198 :     if (!PyArg_ParseTuple(args, "iO:set_option", &option, &value))
    1279         198 :         return NULL;
    1280         198 :     if (!LDAP_set_option((LDAPObject *)self, option, value))
    1281           7 :         return NULL;
    1282         191 :     Py_INCREF(Py_None);
    1283         191 :     return Py_None;
    1284             : }
    1285             : 
    1286             : 
    1287             : /* ldap_get_option */
    1288             : 
    1289             : static PyObject*
    1290          34 : l_ldap_get_option(PyObject* self, PyObject *args)
    1291             : {
    1292             :     int option;
    1293             : 
    1294          34 :     if (!PyArg_ParseTuple(args, "i:get_option", &option))
    1295          34 :         return NULL;
    1296          34 :     return LDAP_get_option((LDAPObject *)self, option);
    1297             : }
    1298             : 
    1299             : 
    1300             : /* ldap_passwd */
    1301             : 
    1302             : static PyObject *
    1303           4 : l_ldap_passwd( LDAPObject* self, PyObject *args )
    1304             : {
    1305             :     struct berval user;
    1306             :     Py_ssize_t user_len;
    1307             :     struct berval oldpw;
    1308             :     Py_ssize_t oldpw_len;
    1309             :     struct berval newpw;
    1310             :     Py_ssize_t newpw_len;
    1311           4 :     PyObject *serverctrls = Py_None;
    1312           4 :     PyObject *clientctrls = Py_None;
    1313           4 :     LDAPControl** server_ldcs = NULL;
    1314           4 :     LDAPControl** client_ldcs = NULL;
    1315             : 
    1316             :     int msgid;
    1317             :     int ldaperror;
    1318             : 
    1319           4 :     if (!PyArg_ParseTuple( args, "z#z#z#|OO", &user.bv_val, &user_len, &oldpw.bv_val, &oldpw_len, &newpw.bv_val, &newpw_len, &serverctrls, &clientctrls ))
    1320           4 :         return NULL;
    1321             : 
    1322           4 :     user.bv_len = (ber_len_t) user_len;
    1323           4 :     oldpw.bv_len = (ber_len_t) oldpw_len;
    1324           4 :     newpw.bv_len = (ber_len_t) newpw_len;
    1325             :     
    1326           4 :     if (not_valid(self)) return NULL;
    1327             : 
    1328           4 :     if (!PyNone_Check(serverctrls)) {
    1329           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
    1330           1 :             return NULL;
    1331             :     }
    1332             : 
    1333           3 :     if (!PyNone_Check(clientctrls)) {
    1334           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
    1335           1 :             LDAPControl_List_DEL( server_ldcs );
    1336           1 :             return NULL;
    1337             :         }
    1338             :     }
    1339             : 
    1340           2 :     LDAP_BEGIN_ALLOW_THREADS( self );
    1341           8 :     ldaperror = ldap_passwd( self->ldap,
    1342           2 :             user.bv_val != NULL ? &user : NULL,
    1343           2 :             oldpw.bv_val != NULL ? &oldpw : NULL,
    1344           2 :             newpw.bv_val != NULL ? &newpw : NULL,
    1345             :             server_ldcs,
    1346             :             client_ldcs,
    1347             :             &msgid );
    1348           2 :     LDAP_END_ALLOW_THREADS( self );
    1349             :     
    1350           2 :     LDAPControl_List_DEL( server_ldcs );
    1351           2 :     LDAPControl_List_DEL( client_ldcs );
    1352             : 
    1353           2 :     if ( ldaperror!=LDAP_SUCCESS )
    1354           0 :         return LDAPerror( self->ldap, "ldap_passwd" );
    1355             : 
    1356           2 :     return PyInt_FromLong( msgid );
    1357             : }
    1358             : 
    1359             : 
    1360             : /* ldap_extended_operation */
    1361             : 
    1362             : static PyObject *
    1363           2 : l_ldap_extended_operation( LDAPObject* self, PyObject *args )
    1364             : {
    1365           2 :     char *reqoid = NULL;
    1366           2 :     struct berval reqvalue = {0, NULL};
    1367           2 :     PyObject *serverctrls = Py_None;
    1368           2 :     PyObject *clientctrls = Py_None;
    1369           2 :     LDAPControl** server_ldcs = NULL;
    1370           2 :     LDAPControl** client_ldcs = NULL;
    1371             : 
    1372             :     int msgid;
    1373             :     int ldaperror;
    1374             : 
    1375           2 :     if (!PyArg_ParseTuple( args, "sz#|OO", &reqoid, &reqvalue.bv_val, &reqvalue.bv_len, &serverctrls, &clientctrls ))
    1376           2 :         return NULL;
    1377             : 
    1378           2 :     if (not_valid(self)) return NULL;
    1379             : 
    1380           2 :     if (!PyNone_Check(serverctrls)) {
    1381           1 :         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
    1382           1 :             return NULL;
    1383             :     }
    1384             : 
    1385           1 :     if (!PyNone_Check(clientctrls)) {
    1386           1 :         if (!LDAPControls_from_object(clientctrls, &client_ldcs)) {
    1387           1 :             LDAPControl_List_DEL( server_ldcs );
    1388           1 :             return NULL;
    1389             :         }
    1390             :     }
    1391             : 
    1392           0 :     LDAP_BEGIN_ALLOW_THREADS( self );
    1393           0 :     ldaperror = ldap_extended_operation( self->ldap, reqoid,
    1394           0 :             reqvalue.bv_val != NULL ? &reqvalue : NULL,
    1395             :             server_ldcs,
    1396             :             client_ldcs,
    1397             :             &msgid );
    1398           0 :     LDAP_END_ALLOW_THREADS( self );
    1399             :     
    1400           0 :     LDAPControl_List_DEL( server_ldcs );
    1401           0 :     LDAPControl_List_DEL( client_ldcs );
    1402             : 
    1403           0 :     if ( ldaperror!=LDAP_SUCCESS )
    1404           0 :         return LDAPerror( self->ldap, "ldap_extended_operation" );
    1405             : 
    1406           0 :     return PyInt_FromLong( msgid );
    1407             : }
    1408             : 
    1409             : /* methods */
    1410             : 
    1411             : static PyMethodDef methods[] = {
    1412             :     {"unbind_ext",      (PyCFunction)l_ldap_unbind_ext,         METH_VARARGS },
    1413             :     {"abandon_ext",     (PyCFunction)l_ldap_abandon_ext,        METH_VARARGS },
    1414             :     {"add_ext",         (PyCFunction)l_ldap_add_ext,            METH_VARARGS },
    1415             :     {"simple_bind",     (PyCFunction)l_ldap_simple_bind,        METH_VARARGS },
    1416             : #ifdef HAVE_SASL
    1417             :     {"sasl_interactive_bind_s", (PyCFunction)l_ldap_sasl_interactive_bind_s,    METH_VARARGS },
    1418             :     {"sasl_bind_s", (PyCFunction)l_ldap_sasl_bind_s,    METH_VARARGS },
    1419             : #endif
    1420             :     {"compare_ext",     (PyCFunction)l_ldap_compare_ext,        METH_VARARGS },
    1421             :     {"delete_ext",      (PyCFunction)l_ldap_delete_ext,         METH_VARARGS },
    1422             :     {"modify_ext",      (PyCFunction)l_ldap_modify_ext,         METH_VARARGS },
    1423             :     {"rename",          (PyCFunction)l_ldap_rename,             METH_VARARGS },
    1424             :     {"result4",         (PyCFunction)l_ldap_result4,            METH_VARARGS },
    1425             :     {"search_ext",      (PyCFunction)l_ldap_search_ext,         METH_VARARGS },
    1426             : #ifdef HAVE_TLS
    1427             :     {"start_tls_s",     (PyCFunction)l_ldap_start_tls_s,        METH_VARARGS },
    1428             : #endif
    1429             :     {"whoami_s",        (PyCFunction)l_ldap_whoami_s,           METH_VARARGS },
    1430             :     {"passwd",          (PyCFunction)l_ldap_passwd,             METH_VARARGS },
    1431             :     {"set_option",      (PyCFunction)l_ldap_set_option,         METH_VARARGS },
    1432             :     {"get_option",      (PyCFunction)l_ldap_get_option,         METH_VARARGS },
    1433             : #ifdef LDAP_API_FEATURE_CANCEL
    1434             :     {"cancel",          (PyCFunction)l_ldap_cancel,             METH_VARARGS },
    1435             : #endif
    1436             :     {"extop",           (PyCFunction)l_ldap_extended_operation,         METH_VARARGS },
    1437             :     { NULL, NULL }
    1438             : };
    1439             : 
    1440             : /* type entry */
    1441             : 
    1442             : PyTypeObject LDAP_Type = {
    1443             :         PyVarObject_HEAD_INIT(NULL, 0)
    1444             :         "LDAP",                 /*tp_name*/
    1445             :         sizeof(LDAPObject),     /*tp_basicsize*/
    1446             :         0,                      /*tp_itemsize*/
    1447             :         /* methods */
    1448             :         (destructor)dealloc,    /*tp_dealloc*/
    1449             :         0,                      /*tp_print*/
    1450             :         0,                      /*tp_getattr*/
    1451             :         0,                      /*tp_setattr*/
    1452             :         0,                      /*tp_compare*/
    1453             :         0,                      /*tp_repr*/
    1454             :         0,                      /*tp_as_number*/
    1455             :         0,                      /*tp_as_sequence*/
    1456             :         0,                      /*tp_as_mapping*/
    1457             :         0,                      /*tp_hash*/
    1458             :         0,                      /*tp_call*/
    1459             :         0,                      /*tp_str*/
    1460             :         0,                      /*tp_getattro*/
    1461             :         0,                      /*tp_setattro*/
    1462             :         0,                      /*tp_as_buffer*/
    1463             :         0,                      /*tp_flags*/
    1464             :         0,                      /*tp_doc*/
    1465             :         0,                      /*tp_traverse*/
    1466             :         0,                      /*tp_clear*/
    1467             :         0,                      /*tp_richcompare*/
    1468             :         0,                      /*tp_weaklistoffset*/
    1469             :         0,                      /*tp_iter*/
    1470             :         0,                      /*tp_iternext*/
    1471             :         methods,                /*tp_methods*/
    1472             :         0,                      /*tp_members*/
    1473             :         0,                      /*tp_getset*/
    1474             : };

Generated by: LCOV version 1.12