1436 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1436 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* See http://www.python-ldap.org/ for details.
 | |
|  * $Id: LDAPObject.c,v 1.91 2015/05/02 16:19:23 stroeder Exp $ */
 | |
| 
 | |
| #include "common.h"
 | |
| #include "patchlevel.h"
 | |
| 
 | |
| #include <math.h>
 | |
| #include <limits.h>
 | |
| #include "errors.h"
 | |
| #include "constants.h"
 | |
| #include "LDAPObject.h"
 | |
| #include "ldapcontrol.h"
 | |
| #include "message.h"
 | |
| #include "berval.h"
 | |
| #include "options.h"
 | |
| 
 | |
| #ifdef HAVE_SASL
 | |
| #include <sasl.h>
 | |
| #endif
 | |
| 
 | |
| static void free_attrs(char***);
 | |
| 
 | |
| /* constructor */
 | |
| 
 | |
| LDAPObject*
 | |
| newLDAPObject( LDAP* l ) 
 | |
| {
 | |
|     LDAPObject* self = (LDAPObject*) PyObject_NEW(LDAPObject, &LDAP_Type);
 | |
|     if (self == NULL) 
 | |
|         return NULL;
 | |
|     self->ldap = l;
 | |
|     self->_save = NULL;
 | |
|     self->valid = 1;
 | |
|     return self;
 | |
| }
 | |
| 
 | |
| /* destructor */
 | |
| 
 | |
| static void
 | |
| dealloc( LDAPObject* self )
 | |
| {
 | |
|     if (self->ldap) {
 | |
|         if (self->valid) {
 | |
|             LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|             ldap_unbind_ext( self->ldap, NULL, NULL );
 | |
|             LDAP_END_ALLOW_THREADS( self );
 | |
|             self->valid = 0;
 | |
|         }
 | |
|         self->ldap = NULL;
 | |
|     }
 | |
|     PyObject_DEL(self);
 | |
| }
 | |
| 
 | |
| /*------------------------------------------------------------
 | |
|  * utility functions
 | |
|  */
 | |
| 
 | |
| /* 
 | |
|  * check to see if the LDAPObject is valid, 
 | |
|  * ie has been opened, and not closed. An exception is set if not valid.
 | |
|  */
 | |
| 
 | |
| static int
 | |
| not_valid( LDAPObject* l ) {
 | |
|     if (l->valid) {
 | |
|         return 0;
 | |
|     } else {
 | |
|         PyErr_SetString( LDAPexception_class, "LDAP connection invalid" );
 | |
|         return 1;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* free a LDAPMod (complete or partially) allocated in Tuple_to_LDAPMod() */
 | |
| 
 | |
| static void
 | |
| LDAPMod_DEL( LDAPMod* lm )
 | |
| {
 | |
|     Py_ssize_t i;
 | |
| 
 | |
|     if (lm->mod_type)
 | |
|         PyMem_DEL(lm->mod_type);
 | |
|     if (lm->mod_bvalues) {
 | |
|         for (i = 0; lm->mod_bvalues[i]; i++) {
 | |
|             PyMem_DEL(lm->mod_bvalues[i]);
 | |
|         }
 | |
|         PyMem_DEL(lm->mod_bvalues);
 | |
|     }
 | |
|     PyMem_DEL(lm);
 | |
| }
 | |
| 
 | |
| /* 
 | |
|  * convert a tuple of the form (int,str,[str,...]) 
 | |
|  * or (str, [str,...]) if no_op is true, into an LDAPMod structure.
 | |
|  * See ldap_modify(3) for details.
 | |
|  *
 | |
|  * NOTE: the resulting LDAPMod structure has pointers directly into
 | |
|  *       the Python string storage, so LDAPMod structures MUST have a
 | |
|  *       shorter lifetime than the tuple passed in.
 | |
|  */
 | |
| 
 | |
| /* XXX - there is no way to pass complex-structured BER objects in here! */
 | |
| 
 | |
| static LDAPMod*
 | |
| Tuple_to_LDAPMod( PyObject* tup, int no_op ) 
 | |
| {
 | |
|     int op;
 | |
|     char *type;
 | |
|     PyObject *list, *item;
 | |
|     LDAPMod *lm = NULL;
 | |
|     Py_ssize_t i, len, nstrs;
 | |
| 
 | |
|     if (!PyTuple_Check(tup)) {
 | |
|         PyErr_SetObject(PyExc_TypeError, Py_BuildValue("sO",
 | |
|            "expected a tuple", tup));
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (no_op) {
 | |
|         if (!PyArg_ParseTuple( tup, "sO", &type, &list ))
 | |
|                 return NULL;
 | |
|         op = 0;
 | |
|     } else {
 | |
|         if (!PyArg_ParseTuple( tup, "isO", &op, &type, &list ))
 | |
|                 return NULL;
 | |
|     }
 | |
| 
 | |
|     lm = PyMem_NEW(LDAPMod, 1);
 | |
|     if (lm == NULL)
 | |
|         goto nomem;
 | |
| 
 | |
|     lm->mod_op = op | LDAP_MOD_BVALUES;
 | |
|     lm->mod_bvalues = NULL;
 | |
| 
 | |
|     len = strlen(type);
 | |
|     lm->mod_type = PyMem_NEW(char, len + 1);
 | |
|     if (lm->mod_type == NULL)
 | |
|         goto nomem;
 | |
|     memcpy(lm->mod_type, type, len + 1);
 | |
| 
 | |
|     if (list == Py_None) {
 | |
|         /* None indicates a NULL mod_bvals */
 | |
|     } else if (PyBytes_Check(list)) {
 | |
|         /* Single string is a singleton list */
 | |
|         lm->mod_bvalues = PyMem_NEW(struct berval *, 2);
 | |
|         if (lm->mod_bvalues == NULL)
 | |
|             goto nomem;
 | |
|         lm->mod_bvalues[0] = PyMem_NEW(struct berval, 1);
 | |
|         if (lm->mod_bvalues[0] == NULL)
 | |
|             goto nomem;
 | |
|         lm->mod_bvalues[1] = NULL;
 | |
|         lm->mod_bvalues[0]->bv_len = PyBytes_Size(list);
 | |
|         lm->mod_bvalues[0]->bv_val = PyBytes_AsString(list);
 | |
|     } else if (PySequence_Check(list)) {
 | |
|         nstrs = PySequence_Length(list);
 | |
|         lm->mod_bvalues = PyMem_NEW(struct berval *, nstrs + 1);
 | |
|         if (lm->mod_bvalues == NULL)
 | |
|             goto nomem;
 | |
|         for (i = 0; i < nstrs; i++) {
 | |
|           lm->mod_bvalues[i] = PyMem_NEW(struct berval, 1);
 | |
|           if (lm->mod_bvalues[i] == NULL)
 | |
|               goto nomem;
 | |
|           lm->mod_bvalues[i+1] = NULL;
 | |
|           item = PySequence_GetItem(list, i);
 | |
|           if (item == NULL)
 | |
|               goto error;
 | |
|           if (!PyBytes_Check(item)) {
 | |
|               PyErr_SetObject( PyExc_TypeError, Py_BuildValue( "sO",
 | |
|                   "expected a string in the list", item));
 | |
|               Py_DECREF(item);
 | |
|               goto error;
 | |
|           }
 | |
|           lm->mod_bvalues[i]->bv_len = PyBytes_Size(item);
 | |
|           lm->mod_bvalues[i]->bv_val = PyBytes_AsString(item);
 | |
|           Py_DECREF(item);
 | |
|         }
 | |
|         if (nstrs == 0)
 | |
|             lm->mod_bvalues[0] = NULL;
 | |
|     }
 | |
| 
 | |
|     return lm;
 | |
| 
 | |
| nomem:
 | |
|     PyErr_NoMemory();
 | |
| error:
 | |
|     if (lm) 
 | |
|         LDAPMod_DEL(lm);
 | |
| 
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| /* free the structure allocated in List_to_LDAPMods() */
 | |
| 
 | |
| static void
 | |
| LDAPMods_DEL( LDAPMod** lms ) {
 | |
|     LDAPMod** lmp;
 | |
|     for ( lmp = lms; *lmp; lmp++ )
 | |
|         LDAPMod_DEL( *lmp );
 | |
|     PyMem_DEL(lms);
 | |
| }
 | |
| 
 | |
| /* 
 | |
|  * convert a list of tuples into a LDAPMod*[] array structure 
 | |
|  * NOTE: list of tuples must live longer than the LDAPMods
 | |
|  */
 | |
| 
 | |
| static LDAPMod**
 | |
| List_to_LDAPMods( PyObject *list, int no_op ) {
 | |
| 
 | |
|     Py_ssize_t i, len;
 | |
|     LDAPMod** lms;
 | |
|     PyObject *item;
 | |
| 
 | |
|     if (!PySequence_Check(list)) {
 | |
|         PyErr_SetObject( PyExc_TypeError, Py_BuildValue("sO",
 | |
|                         "expected list of tuples", list ));
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     len = PySequence_Length(list);
 | |
| 
 | |
|     if (len < 0) {
 | |
|         PyErr_SetObject( PyExc_TypeError, Py_BuildValue("sO",
 | |
|                          "expected list of tuples", list ));
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     lms = PyMem_NEW(LDAPMod *, len + 1);
 | |
|     if (lms == NULL) 
 | |
|         goto nomem;
 | |
| 
 | |
|     for (i = 0; i < len; i++) {
 | |
|         lms[i] = NULL;
 | |
|         item = PySequence_GetItem(list, i);
 | |
|         if (item == NULL) 
 | |
|             goto error;
 | |
|         lms[i] = Tuple_to_LDAPMod(item, no_op);
 | |
|         Py_DECREF(item);
 | |
|         if (lms[i] == NULL)
 | |
|             goto error;
 | |
|     }
 | |
|     lms[len] = NULL;
 | |
|     return lms;
 | |
| 
 | |
| nomem:
 | |
|     PyErr_NoMemory();
 | |
| error:
 | |
|     if (lms)
 | |
|         LDAPMods_DEL(lms);
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * convert a python list of strings into an attr list (char*[]).
 | |
|  * returns 1 if successful, 0 if not (with exception set)
 | |
|  * XXX the strings should live longer than the resulting attrs pointer.
 | |
|  */
 | |
| 
 | |
| int
 | |
| attrs_from_List( PyObject *attrlist, char***attrsp ) {
 | |
| 
 | |
|     char **attrs = NULL;
 | |
|     Py_ssize_t i, len;
 | |
|     PyObject *item, *bytes;
 | |
| 
 | |
|     if (attrlist == Py_None) {
 | |
|         /* None means a NULL attrlist */
 | |
|     } else if (PyUnicode_Check(attrlist)) {
 | |
|         /* caught by John Benninghoff <johnb@netscape.com> */
 | |
|         PyErr_SetObject( PyExc_TypeError, Py_BuildValue("sO",
 | |
|                   "expected *list* of strings, not a string", attrlist ));
 | |
|         goto error;
 | |
|     } else if (PySequence_Check(attrlist)) {
 | |
|         len = PySequence_Length(attrlist);
 | |
|         attrs = PyMem_NEW(char *, len + 1);
 | |
|         if (attrs == NULL)
 | |
|             goto nomem;
 | |
| 
 | |
|         for (i = 0; i < len; i++) {
 | |
|             attrs[i] = NULL;
 | |
|             item = PySequence_GetItem(attrlist, i);
 | |
|             if (item == NULL)
 | |
|                 goto error;
 | |
|             if (!PyUnicode_Check(item)) {
 | |
|                 PyErr_SetObject(PyExc_TypeError, Py_BuildValue("sO",
 | |
|                                 "expected string in list", item));
 | |
|                 Py_DECREF(item);
 | |
|                 goto error;
 | |
|             }
 | |
|             bytes = PyUnicode_AsUTF8String(item);
 | |
|             attrs[i] = PyBytes_AsString(bytes);
 | |
|             Py_DECREF(item);
 | |
|         }
 | |
|         attrs[len] = NULL;
 | |
|     } else {
 | |
|         PyErr_SetObject( PyExc_TypeError, Py_BuildValue("sO",
 | |
|                          "expected list of strings or None", attrlist ));
 | |
|         goto error;
 | |
|     }
 | |
| 
 | |
|     *attrsp = attrs;
 | |
|     return 1;
 | |
| 
 | |
| nomem:
 | |
|     PyErr_NoMemory();
 | |
| error:
 | |
|     free_attrs(&attrs);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /* free memory allocated from above routine */
 | |
| 
 | |
| static void
 | |
| free_attrs( char*** attrsp ) {
 | |
|     char **attrs = *attrsp;
 | |
| 
 | |
|     if (attrs != NULL) {
 | |
|         PyMem_DEL(attrs);
 | |
|         *attrsp = NULL;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*------------------------------------------------------------
 | |
|  * methods
 | |
|  */
 | |
| 
 | |
| /* ldap_unbind_ext */
 | |
| 
 | |
| static PyObject*
 | |
| l_ldap_unbind_ext( LDAPObject* self, PyObject* args )
 | |
| {
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     int ldaperror;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "|OO", &serverctrls, &clientctrls)) return NULL;
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_unbind_ext( self->ldap, server_ldcs, client_ldcs );
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_unbind_ext" );
 | |
| 
 | |
|     self->valid = 0;
 | |
|     Py_INCREF(Py_None);
 | |
|     return Py_None;
 | |
| }
 | |
| 
 | |
| /* ldap_abandon_ext */
 | |
| 
 | |
| static PyObject*
 | |
| l_ldap_abandon_ext( LDAPObject* self, PyObject* args )
 | |
| {
 | |
|     int msgid;
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     int ldaperror;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "i|OO", &msgid, &serverctrls, &clientctrls)) return NULL;
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_abandon_ext( self->ldap, msgid, server_ldcs, client_ldcs );
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_abandon_ext" );
 | |
| 
 | |
|     Py_INCREF(Py_None);
 | |
|     return Py_None;
 | |
| }
 | |
| 
 | |
| /* ldap_add_ext */
 | |
| 
 | |
| static PyObject *
 | |
| l_ldap_add_ext( LDAPObject* self, PyObject *args )
 | |
| {
 | |
|     char *dn;
 | |
|     PyObject *modlist;
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     int msgid;
 | |
|     int ldaperror;
 | |
|     LDAPMod **mods;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "sO|OO", &dn, &modlist, &serverctrls, &clientctrls )) return NULL;
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     mods = List_to_LDAPMods( modlist, 1 );
 | |
|     if (mods == NULL)
 | |
|         return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_add_ext( self->ldap, dn, mods, server_ldcs, client_ldcs, &msgid);
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
|     LDAPMods_DEL( mods );
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_add_ext" );
 | |
| 
 | |
|     return PyLong_FromLong(msgid);
 | |
| }
 | |
| 
 | |
| /* ldap_simple_bind */
 | |
| 
 | |
| static PyObject*
 | |
| l_ldap_simple_bind( LDAPObject* self, PyObject* args )
 | |
| {
 | |
|     char *who;
 | |
|     int msgid;
 | |
|     int ldaperror;
 | |
|     Py_ssize_t cred_len;
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
|     struct berval cred;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "ss#|OO", &who, &cred.bv_val, &cred_len, &serverctrls, &clientctrls )) return NULL;
 | |
|     cred.bv_len = (ber_len_t) cred_len;
 | |
| 
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_sasl_bind( self->ldap, who, LDAP_SASL_SIMPLE, &cred, server_ldcs, client_ldcs, &msgid);
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_simple_bind" );
 | |
| 
 | |
|     return PyLong_FromLong( msgid );
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifdef HAVE_SASL
 | |
| /* The following functions implement SASL binds. A new method
 | |
|    sasl_interactive_bind_s(bind_dn, sasl_mechanism) has been introduced.
 | |
| 
 | |
|    * The bind_dn argument will be passed to the c library; however,
 | |
|      normally it is not needed and should be an empty string.
 | |
| 
 | |
|    * The sasl_mechanism argument is an instance of a class that
 | |
|      implements a callback interface. For convenience, it should be
 | |
|      derived from the sasl class (which lives in the ldap.sasl module).
 | |
|      See the module documentation for more information.
 | |
| 
 | |
|      Check your /usr/lib/sasl/ directory for locally installed SASL
 | |
|      auth modules ("mechanisms"), or try
 | |
| 
 | |
|        ldapsearch   -b "" -s base -LLL -x  supportedSASLMechanisms
 | |
|      
 | |
|      (perhaps with an additional -h and -p argument for ldap host and
 | |
|      port). The latter will show you which SASL mechanisms are known
 | |
|      to the LDAP server. If you do not want to set up Kerberos, you
 | |
|      can still use SASL binds. Your authentication data should then be
 | |
|      stored in /etc/sasldb (see saslpasswd(8)). If the LDAP server
 | |
|      does not find the sasldb, it wont allow for DIGEST-MD5 and
 | |
|      CRAM-MD5. One important thing to get started with sasldb: you
 | |
|      should first add a dummy user (saslpasswd -c dummy), and this
 | |
|      will give you some strange error messages. Then delete the dummy
 | |
|      user (saslpasswd -d dummy), and now you can start adding users to
 | |
|      your sasldb (again, use the -c switch). Strange, eh?
 | |
| 
 | |
|    * The sasl_mechanism object must implement a method, which will be
 | |
|      called by the sasl lib several times. The prototype of the
 | |
|      callback looks like this: callback(id, challenge, prompt,
 | |
|      defresult) has to return a string (or maybe None). The id
 | |
|      argument specifies, which information should be passed back to
 | |
|      the SASL lib (see SASL_CB_xxx in sasl.h)
 | |
| 
 | |
| 
 | |
|    A nice "Howto get LDAPv3 up and running with Kerberos and SSL" can
 | |
|    be found at http://www.bayour.com/LDAPv3-HOWTO.html.  Instead of
 | |
|    MIT Kerberos, I used Heimdal for my tests (since it is included
 | |
|    with SuSE Linux).
 | |
| 
 | |
|    Todo:
 | |
|    
 | |
|    * Find a better interface than the python callback. This is 
 | |
|      really ugly. Perhaps one could make use of a sasl class, like
 | |
|      in the perl ldap module.
 | |
| 
 | |
|    * Thread safety?
 | |
| 
 | |
|    * Memory Management?
 | |
|    
 | |
|    * Write more docs
 | |
| 
 | |
|    * ...
 | |
| 
 | |
| */
 | |
| static int interaction ( unsigned flags, 
 | |
|                          sasl_interact_t *interact,
 | |
|                          PyObject* SASLObject )
 | |
| {
 | |
| /*  const char *dflt = interact->defresult; */
 | |
|   PyObject *result;
 | |
|   char *c_result;
 | |
|   result = PyObject_CallMethod(SASLObject,
 | |
|                                "callback",
 | |
|                                "isss",
 | |
|                                interact->id,  /* see sasl.h */
 | |
|                                interact->challenge,
 | |
|                                interact->prompt,   
 | |
|                                interact->defresult);
 | |
| 
 | |
|   if (result == NULL) 
 | |
|     /*searching for a better error code */
 | |
|     return LDAP_OPERATIONS_ERROR; 
 | |
|   c_result = PyBytes_AsString(result); /*xxx Error checking?? */
 | |
|   
 | |
|   /* according to the sasl docs, we should malloc() the returned
 | |
|      string only for calls where interact->id == SASL_CB_PASS, so we
 | |
|      probably leak a few bytes per ldap bind. However, if I restrict
 | |
|      the strdup() to this case, I get segfaults. Should probably be
 | |
|      fixed sometimes.
 | |
|   */
 | |
|   interact->result = strdup( c_result );
 | |
|   if (interact->result == NULL)
 | |
|     return LDAP_OPERATIONS_ERROR;
 | |
|   interact->len = strlen(c_result);
 | |
|   /* We _should_ overwrite the python string buffer for security
 | |
|      reasons, however we may not (api/stringObjects.html). Any ideas?
 | |
|   */
 | |
|   
 | |
|   Py_DECREF(result); /*not needed any longer */
 | |
|   result = NULL;
 | |
|   
 | |
|   return LDAP_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* 
 | |
|   This function will be called by ldap_sasl_interactive_bind(). The
 | |
|   "*in" is an array of sasl_interact_t's (see sasl.h for a
 | |
|   reference). The last interact in the array has an interact->id of
 | |
|   SASL_CB_LIST_END.
 | |
| 
 | |
| */
 | |
| 
 | |
| int py_ldap_sasl_interaction(   LDAP *ld, 
 | |
|                                 unsigned flags, 
 | |
|                                 void *defaults,
 | |
|                                 void *in )
 | |
| {
 | |
|   /* These are just typecasts */
 | |
|   sasl_interact_t *interact = (sasl_interact_t *) in;
 | |
|   PyObject *SASLObject = (PyObject *) defaults;
 | |
|   /* Loop over the array of sasl_interact_t structs */
 | |
|   while( interact->id != SASL_CB_LIST_END ) {
 | |
|     int rc = 0;
 | |
|     rc = interaction( flags, interact, SASLObject );
 | |
|     if( rc )  return rc;
 | |
|     interact++;
 | |
|   }
 | |
|   return LDAP_SUCCESS;
 | |
| }
 | |
| 
 | |
| static PyObject*
 | |
| l_ldap_sasl_bind_s( LDAPObject* self, PyObject* args )
 | |
| {
 | |
|     const char *dn;
 | |
|     const char *mechanism;
 | |
|     struct berval cred;
 | |
|     Py_ssize_t cred_len;
 | |
| 
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     struct berval *servercred;
 | |
|     int ldaperror;
 | |
| 
 | |
|     if (!PyArg_ParseTuple(args, "zzz#OO", &dn, &mechanism, &cred.bv_val, &cred_len, &serverctrls, &clientctrls ))
 | |
|         return NULL;
 | |
| 
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     cred.bv_len = cred_len;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_sasl_bind_s(self->ldap,
 | |
|                                  dn,
 | |
|                                  mechanism,
 | |
|                                  cred.bv_val ? &cred : NULL,
 | |
|                                  (LDAPControl**) server_ldcs, 
 | |
|                                  (LDAPControl**) client_ldcs,
 | |
|                                  &servercred);
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if (ldaperror == LDAP_SASL_BIND_IN_PROGRESS) {
 | |
|         if (servercred && servercred->bv_val && *servercred->bv_val)
 | |
|             return PyBytes_FromStringAndSize( servercred->bv_val, servercred->bv_len );
 | |
|     } else if (ldaperror != LDAP_SUCCESS)
 | |
|         return LDAPerror( self->ldap, "l_ldap_sasl_bind_s" );
 | |
|     return PyLong_FromLong( ldaperror );
 | |
| }
 | |
| 
 | |
| static PyObject* 
 | |
| l_ldap_sasl_interactive_bind_s( LDAPObject* self, PyObject* args )
 | |
| {
 | |
|     char *c_mechanism;
 | |
|     char *who;
 | |
| 
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     PyObject       *SASLObject = NULL;
 | |
|     PyObject *mechanism = NULL;
 | |
|     int msgid;
 | |
| 
 | |
|     static unsigned sasl_flags = LDAP_SASL_QUIET;
 | |
| 
 | |
|     /* 
 | |
|      * In Python 2.3+, a "I" format argument indicates that we're either converting
 | |
|      * the Python object into a long or an unsigned int. In versions prior to that,
 | |
|      * it will always convert to a long. Since the sasl_flags variable is an
 | |
|      * unsigned int, we need to use the "I" flag if we're running Python 2.3+ and a
 | |
|      * "i" otherwise. 
 | |
|      */
 | |
| #if (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION < 3)
 | |
|     if (!PyArg_ParseTuple(args, "sOOOi", &who, &SASLObject, &serverctrls, &clientctrls, &sasl_flags ))
 | |
| #else
 | |
|     if (!PyArg_ParseTuple(args, "sOOOI", &who, &SASLObject, &serverctrls, &clientctrls, &sasl_flags ))
 | |
| #endif
 | |
|       return NULL;
 | |
| 
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     /* now we extract the sasl mechanism from the SASL Object */
 | |
|     mechanism = PyObject_GetAttrString(SASLObject, "mech");
 | |
|     if (mechanism == NULL) return NULL;
 | |
|     c_mechanism = PyBytes_AsString(mechanism);
 | |
|     Py_DECREF(mechanism);
 | |
|     mechanism = NULL;
 | |
| 
 | |
|     /* Don't know if it is the "intended use" of the defaults
 | |
|        parameter of ldap_sasl_interactive_bind_s when we pass the
 | |
|        Python object SASLObject, but passing it through some
 | |
|        static variable would destroy thread safety, IMHO.
 | |
|      */
 | |
|     msgid = ldap_sasl_interactive_bind_s(self->ldap, 
 | |
|                                          who, 
 | |
|                                          c_mechanism, 
 | |
|                                          (LDAPControl**) server_ldcs, 
 | |
|                                          (LDAPControl**) client_ldcs,
 | |
|                                          sasl_flags, 
 | |
|                                          py_ldap_sasl_interaction, 
 | |
|                                          SASLObject);
 | |
| 
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if (msgid != LDAP_SUCCESS)
 | |
|         return LDAPerror( self->ldap, "ldap_sasl_interactive_bind_s" );
 | |
|     return PyLong_FromLong( msgid );
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 
 | |
| #ifdef LDAP_API_FEATURE_CANCEL
 | |
| 
 | |
| /* ldap_cancel */
 | |
| 
 | |
| static PyObject*
 | |
| l_ldap_cancel( LDAPObject* self, PyObject* args )
 | |
| {
 | |
|     int msgid;
 | |
|     int cancelid;
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     int ldaperror;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "i|OO", &cancelid, &serverctrls, &clientctrls)) return NULL;
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_cancel( self->ldap, cancelid, server_ldcs, client_ldcs, &msgid );
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_cancel" );
 | |
| 
 | |
|     return PyLong_FromLong( msgid );
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| /* ldap_compare_ext */
 | |
| 
 | |
| static PyObject *
 | |
| l_ldap_compare_ext( LDAPObject* self, PyObject *args )
 | |
| {
 | |
|     char *dn, *attr;
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     int msgid;
 | |
|     int ldaperror;
 | |
|     Py_ssize_t value_len;
 | |
|     struct berval value;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "sss#|OO", &dn, &attr, &value.bv_val, &value_len, &serverctrls, &clientctrls )) return NULL;
 | |
|     value.bv_len = (ber_len_t) value_len;
 | |
| 
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_compare_ext( self->ldap, dn, attr, &value, server_ldcs, client_ldcs, &msgid );
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_compare_ext" );
 | |
| 
 | |
|     return PyLong_FromLong( msgid );
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ldap_delete_ext */
 | |
| 
 | |
| static PyObject *
 | |
| l_ldap_delete_ext( LDAPObject* self, PyObject *args )
 | |
| {
 | |
|     char *dn;
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     int msgid;
 | |
|     int ldaperror;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "s|OO", &dn, &serverctrls, &clientctrls )) return NULL;
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_delete_ext( self->ldap, dn, server_ldcs, client_ldcs, &msgid );
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_delete_ext" );
 | |
| 
 | |
|     return PyLong_FromLong(msgid);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ldap_modify_ext */
 | |
| 
 | |
| static PyObject *
 | |
| l_ldap_modify_ext( LDAPObject* self, PyObject *args )
 | |
| {
 | |
|     char *dn;
 | |
|     PyObject *modlist;
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     int msgid;
 | |
|     int ldaperror;
 | |
|     LDAPMod **mods;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "sO|OO", &dn, &modlist, &serverctrls, &clientctrls )) return NULL;
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     mods = List_to_LDAPMods( modlist, 0 );
 | |
|     if (mods == NULL)
 | |
|         return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_modify_ext( self->ldap, dn, mods, server_ldcs, client_ldcs, &msgid );
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     LDAPMods_DEL( mods );
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_modify_ext" );
 | |
| 
 | |
|     return PyLong_FromLong( msgid );
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ldap_rename */
 | |
| 
 | |
| static PyObject *
 | |
| l_ldap_rename( LDAPObject* self, PyObject *args )
 | |
| {
 | |
|     char *dn, *newrdn;
 | |
|     char *newSuperior = NULL;
 | |
|     int delold = 1;
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     int msgid;
 | |
|     int ldaperror;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "ss|ziOO", &dn, &newrdn, &newSuperior, &delold, &serverctrls, &clientctrls ))
 | |
|         return NULL;
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_rename( self->ldap, dn, newrdn, newSuperior, delold, server_ldcs, client_ldcs, &msgid );
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_rename" );
 | |
| 
 | |
|     return PyLong_FromLong( msgid );
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ldap_result4 */
 | |
| 
 | |
| static PyObject *
 | |
| l_ldap_result4( LDAPObject* self, PyObject *args )
 | |
| {
 | |
|     int msgid = LDAP_RES_ANY;
 | |
|     int all = 1;
 | |
|     double timeout = -1.0;
 | |
|     int add_ctrls = 0;
 | |
|     int add_intermediates = 0;
 | |
|     int add_extop = 0;
 | |
|     struct timeval tv;
 | |
|     struct timeval* tvp;
 | |
|     int res_type;
 | |
|     LDAPMessage *msg = NULL;
 | |
|     PyObject *result_str, *retval, *pmsg, *pyctrls = 0;
 | |
|     int res_msgid = 0;
 | |
|     char *retoid = 0;
 | |
|     PyObject *valuestr = 0;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "|iidiii", &msgid, &all, &timeout, &add_ctrls, &add_intermediates, &add_extop ))
 | |
|         return NULL;
 | |
|     if (not_valid(self)) return NULL;
 | |
|     
 | |
|     if (timeout >= 0) {
 | |
|         tvp = &tv;
 | |
|         set_timeval_from_double( tvp, timeout );
 | |
|     } else {
 | |
|         tvp = NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     res_type = ldap_result( self->ldap, msgid, all, tvp, &msg );
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     if (res_type < 0)   /* LDAP or system error */
 | |
|         return LDAPerror( self->ldap, "ldap_result4" );
 | |
| 
 | |
|     if (res_type == 0) {
 | |
|         /* Polls return (None, None, None, None); timeouts raise an exception */
 | |
|         if (timeout == 0) {
 | |
|             if (add_extop) {
 | |
|                 return Py_BuildValue("(OOOOOO)", Py_None, Py_None, Py_None, Py_None, Py_None, Py_None);
 | |
|             } else {
 | |
|                 return Py_BuildValue("(OOOO)", Py_None, Py_None, Py_None, Py_None);
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|             return LDAPerr(LDAP_TIMEOUT);
 | |
|     }
 | |
| 
 | |
|     if (msg)
 | |
|         res_msgid = ldap_msgid(msg);
 | |
| 
 | |
|     int result = LDAP_SUCCESS;
 | |
|     char **refs = NULL;
 | |
|     LDAPControl **serverctrls = 0;
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     if (res_type == LDAP_RES_SEARCH_ENTRY) {
 | |
|         /* LDAPmessage_to_python will parse entries and read the controls for each entry */
 | |
|     } else if (res_type == LDAP_RES_SEARCH_REFERENCE) {
 | |
|         /* LDAPmessage_to_python will parse refs and read the controls for each res */
 | |
|     } else if (res_type == LDAP_RES_INTERMEDIATE) {
 | |
|         /* LDAPmessage_to_python will parse intermediates and controls */
 | |
|     } else {
 | |
|         int rc;
 | |
|         if (res_type == LDAP_RES_EXTENDED) {
 | |
|             struct berval *retdata = 0;
 | |
|             rc = ldap_parse_extended_result( self->ldap, msg, &retoid, &retdata, 0 );
 | |
|             /* handle error rc!=0 here? */
 | |
|             if (rc == LDAP_SUCCESS) {
 | |
|                 valuestr = LDAPberval_to_object(retdata);
 | |
|             }
 | |
|             ber_bvfree( retdata );
 | |
|         }
 | |
|             
 | |
|         rc = ldap_parse_result( self->ldap, msg, &result, NULL, NULL, &refs,
 | |
|                                 &serverctrls, 0 );
 | |
|     }
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     if (result != LDAP_SUCCESS) {               /* result error */
 | |
|         char *e, err[1024];
 | |
|         if (result == LDAP_REFERRAL && refs && refs[0]) {
 | |
|             snprintf(err, sizeof(err), "Referral:\n%s", refs[0]);
 | |
|             e = err;
 | |
|         } else
 | |
|             e = "ldap_parse_result";
 | |
|         ldap_msgfree(msg);
 | |
|         return LDAPerror( self->ldap, e );
 | |
|     }
 | |
| 
 | |
|     if (!(pyctrls = LDAPControls_to_List(serverctrls))) {
 | |
|         int err = LDAP_NO_MEMORY;
 | |
|         ldap_set_option(self->ldap, LDAP_OPT_ERROR_NUMBER, &err);
 | |
|         ldap_msgfree(msg);
 | |
|         return LDAPerror(self->ldap, "LDAPControls_to_List");
 | |
|     }
 | |
|     ldap_controls_free(serverctrls);
 | |
| 
 | |
|     pmsg = LDAPmessage_to_python( self->ldap, msg, add_ctrls, add_intermediates );
 | |
| 
 | |
|     result_str = LDAPconstant( res_type );
 | |
| 
 | |
|     if (pmsg == NULL) {
 | |
|             retval = NULL;
 | |
|     } else {
 | |
|         /* s handles NULL, but O does not */
 | |
|         if (add_extop) {
 | |
|             retval = Py_BuildValue("(OOiOsO)", result_str, pmsg, res_msgid,
 | |
|                                    pyctrls, retoid, valuestr ? valuestr : Py_None);
 | |
|         } else {
 | |
|             retval = Py_BuildValue("(OOiO)", result_str, pmsg, res_msgid, pyctrls);
 | |
|         }
 | |
| 
 | |
|         if (pmsg != Py_None) {
 | |
|         Py_DECREF(pmsg);
 | |
|         }
 | |
|     }
 | |
|     if (valuestr) {
 | |
|         Py_DECREF(valuestr);
 | |
|     }
 | |
|     Py_XDECREF(pyctrls);
 | |
|     Py_DECREF(result_str);
 | |
|     return retval;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ldap_search_ext */
 | |
| 
 | |
| static PyObject*
 | |
| l_ldap_search_ext( LDAPObject* self, PyObject* args )
 | |
| {
 | |
|     char *base;
 | |
|     int scope;
 | |
|     char *filter;
 | |
|     PyObject *attrlist = Py_None;
 | |
|     char **attrs;
 | |
|     int attrsonly = 0;
 | |
| 
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     double timeout = -1.0;
 | |
|     struct timeval tv;
 | |
|     struct timeval* tvp;
 | |
| 
 | |
|     int sizelimit = 0;
 | |
| 
 | |
|     int msgid;
 | |
|     int ldaperror;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "sis|OiOOdi",
 | |
|                            &base, &scope, &filter, &attrlist, &attrsonly,
 | |
|                            &serverctrls, &clientctrls, &timeout, &sizelimit )) return NULL;
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     if (!attrs_from_List( attrlist, &attrs )) 
 | |
|          return NULL;
 | |
| 
 | |
|     if (timeout >= 0) {
 | |
|         tvp = &tv;
 | |
|         set_timeval_from_double( tvp, timeout );
 | |
|     } else {
 | |
|         tvp = NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_search_ext( self->ldap, base, scope, filter, attrs, attrsonly,
 | |
|                              server_ldcs, client_ldcs, tvp, sizelimit, &msgid );
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     free_attrs( &attrs );
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_search_ext" );
 | |
| 
 | |
|     return PyLong_FromLong( msgid );
 | |
| }       
 | |
| 
 | |
| 
 | |
| /* ldap_whoami_s (available since OpenLDAP 2.1.13) */
 | |
| 
 | |
| static PyObject*
 | |
| l_ldap_whoami_s( LDAPObject* self, PyObject* args )
 | |
| {
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     struct berval *bvalue = NULL;
 | |
| 
 | |
|     PyObject *result;
 | |
| 
 | |
|     int ldaperror;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "|OO", &serverctrls, &clientctrls)) return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_whoami_s( self->ldap, &bvalue, server_ldcs, client_ldcs );
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
| 
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_whoami_s" );
 | |
| 
 | |
|     result = LDAPberval_to_unicode_object(bvalue);
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| #ifdef HAVE_TLS
 | |
| /* ldap_start_tls_s */
 | |
| 
 | |
| static PyObject*
 | |
| l_ldap_start_tls_s( LDAPObject* self, PyObject* args )
 | |
| {
 | |
|     int result;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "" )) return NULL;
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     result = ldap_start_tls_s( self->ldap, NULL, NULL );
 | |
|     if ( result != LDAP_SUCCESS ){
 | |
|         ldap_set_option(self->ldap, LDAP_OPT_ERROR_NUMBER, &result);
 | |
|         return LDAPerror( self->ldap, "ldap_start_tls_s" );
 | |
|     }
 | |
| 
 | |
|     Py_INCREF(Py_None);
 | |
|     return Py_None;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| /* ldap_set_option */
 | |
| 
 | |
| static PyObject*
 | |
| l_ldap_set_option(PyObject* self, PyObject *args)
 | |
| {
 | |
|     PyObject *value;
 | |
|     int option;
 | |
| 
 | |
|     if (!PyArg_ParseTuple(args, "iO:set_option", &option, &value))
 | |
|         return NULL;
 | |
|     if (LDAP_set_option((LDAPObject *)self, option, value) == -1)
 | |
|         return NULL;
 | |
|     Py_INCREF(Py_None);
 | |
|     return Py_None;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ldap_get_option */
 | |
| 
 | |
| static PyObject*
 | |
| l_ldap_get_option(PyObject* self, PyObject *args)
 | |
| {
 | |
|     int option;
 | |
| 
 | |
|     if (!PyArg_ParseTuple(args, "i:get_option", &option))
 | |
|         return NULL;
 | |
|     return LDAP_get_option((LDAPObject *)self, option);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ldap_passwd */
 | |
| 
 | |
| static PyObject *
 | |
| l_ldap_passwd( LDAPObject* self, PyObject *args )
 | |
| {
 | |
|     struct berval user;
 | |
|     Py_ssize_t user_len;
 | |
|     struct berval oldpw;
 | |
|     Py_ssize_t oldpw_len;
 | |
|     struct berval newpw;
 | |
|     Py_ssize_t newpw_len;
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     int msgid;
 | |
|     int ldaperror;
 | |
| 
 | |
|     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 ))
 | |
|         return NULL;
 | |
| 
 | |
|     user.bv_len = (ber_len_t) user_len;
 | |
|     oldpw.bv_len = (ber_len_t) oldpw_len;
 | |
|     newpw.bv_len = (ber_len_t) newpw_len;
 | |
|     
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_passwd( self->ldap,
 | |
|             user.bv_val != NULL ? &user : NULL,
 | |
|             oldpw.bv_val != NULL ? &oldpw : NULL,
 | |
|             newpw.bv_val != NULL ? &newpw : NULL,
 | |
|             server_ldcs,
 | |
|             client_ldcs,
 | |
|             &msgid );
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
|     
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_passwd" );
 | |
| 
 | |
|     return PyLong_FromLong( msgid );
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ldap_extended_operation */
 | |
| 
 | |
| static PyObject *
 | |
| l_ldap_extended_operation( LDAPObject* self, PyObject *args )
 | |
| {
 | |
|     char *reqoid = NULL;
 | |
|     struct berval reqvalue = {0, NULL};
 | |
|     PyObject *serverctrls = Py_None;
 | |
|     PyObject *clientctrls = Py_None;
 | |
|     LDAPControl** server_ldcs = NULL;
 | |
|     LDAPControl** client_ldcs = NULL;
 | |
| 
 | |
|     int msgid;
 | |
|     int ldaperror;
 | |
| 
 | |
|     if (!PyArg_ParseTuple( args, "sz#|OO", &reqoid, &reqvalue.bv_val, &reqvalue.bv_len, &serverctrls, &clientctrls ))
 | |
|         return NULL;
 | |
| 
 | |
|     if (not_valid(self)) return NULL;
 | |
| 
 | |
|     if (!PyNone_Check(serverctrls)) {
 | |
|         if (!LDAPControls_from_object(serverctrls, &server_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     if (!PyNone_Check(clientctrls)) {
 | |
|         if (!LDAPControls_from_object(clientctrls, &client_ldcs))
 | |
|             return NULL;
 | |
|     }
 | |
| 
 | |
|     LDAP_BEGIN_ALLOW_THREADS( self );
 | |
|     ldaperror = ldap_extended_operation( self->ldap, reqoid,
 | |
|             reqvalue.bv_val != NULL ? &reqvalue : NULL,
 | |
|             server_ldcs,
 | |
|             client_ldcs,
 | |
|             &msgid );
 | |
|     LDAP_END_ALLOW_THREADS( self );
 | |
|     
 | |
|     LDAPControl_List_DEL( server_ldcs );
 | |
|     LDAPControl_List_DEL( client_ldcs );
 | |
| 
 | |
|     if ( ldaperror!=LDAP_SUCCESS )
 | |
|         return LDAPerror( self->ldap, "ldap_extended_operation" );
 | |
| 
 | |
|     return PyLong_FromLong( msgid );
 | |
| }
 | |
| 
 | |
| /* methods */
 | |
| 
 | |
| static PyMethodDef methods[] = {
 | |
|     {"unbind_ext",      (PyCFunction)l_ldap_unbind_ext,         METH_VARARGS },
 | |
|     {"abandon_ext",     (PyCFunction)l_ldap_abandon_ext,        METH_VARARGS },
 | |
|     {"add_ext",         (PyCFunction)l_ldap_add_ext,            METH_VARARGS },
 | |
|     {"simple_bind",     (PyCFunction)l_ldap_simple_bind,        METH_VARARGS },
 | |
| #ifdef HAVE_SASL
 | |
|     {"sasl_interactive_bind_s", (PyCFunction)l_ldap_sasl_interactive_bind_s,    METH_VARARGS },
 | |
|     {"sasl_bind_s", (PyCFunction)l_ldap_sasl_bind_s,    METH_VARARGS },
 | |
| #endif
 | |
|     {"compare_ext",     (PyCFunction)l_ldap_compare_ext,        METH_VARARGS },
 | |
|     {"delete_ext",      (PyCFunction)l_ldap_delete_ext,         METH_VARARGS },
 | |
|     {"modify_ext",      (PyCFunction)l_ldap_modify_ext,         METH_VARARGS },
 | |
|     {"rename",          (PyCFunction)l_ldap_rename,             METH_VARARGS },
 | |
|     {"result4",         (PyCFunction)l_ldap_result4,            METH_VARARGS },
 | |
|     {"search_ext",      (PyCFunction)l_ldap_search_ext,         METH_VARARGS },
 | |
| #ifdef HAVE_TLS
 | |
|     {"start_tls_s",     (PyCFunction)l_ldap_start_tls_s,        METH_VARARGS },
 | |
| #endif
 | |
|     {"whoami_s",        (PyCFunction)l_ldap_whoami_s,           METH_VARARGS },
 | |
|     {"passwd",          (PyCFunction)l_ldap_passwd,             METH_VARARGS },
 | |
|     {"set_option",      (PyCFunction)l_ldap_set_option,         METH_VARARGS },
 | |
|     {"get_option",      (PyCFunction)l_ldap_get_option,         METH_VARARGS },
 | |
| #ifdef LDAP_API_FEATURE_CANCEL
 | |
|     {"cancel",          (PyCFunction)l_ldap_cancel,             METH_VARARGS },
 | |
| #endif
 | |
|     {"extop",           (PyCFunction)l_ldap_extended_operation,         METH_VARARGS },
 | |
|     { NULL, NULL }
 | |
| };
 | |
| 
 | |
| /* type entry */
 | |
| 
 | |
| PyTypeObject LDAP_Type = {
 | |
| #if defined(MS_WINDOWS) || defined(__CYGWIN__)
 | |
|         /* see http://www.python.org/doc/FAQ.html#3.24 */
 | |
|         PyVarObject_HEAD_INIT(NULL, 0)
 | |
| #else /* ! MS_WINDOWS */
 | |
|         PyVarObject_HEAD_INIT(&PyType_Type, 0)
 | |
| #endif /* MS_WINDOWS */
 | |
|         "LDAP",                 /*tp_name*/
 | |
|         sizeof(LDAPObject),     /*tp_basicsize*/
 | |
|         0,                      /*tp_itemsize*/
 | |
|         /* methods */
 | |
|         (destructor)dealloc,    /*tp_dealloc*/
 | |
|         0,                      /*tp_print*/
 | |
|         0,                      /*tp_getattr*/
 | |
|         0,                      /*tp_setattr*/
 | |
|         0,                      /*tp_compare*/
 | |
|         0,                      /*tp_repr*/
 | |
|         0,                      /*tp_as_number*/
 | |
|         0,                      /*tp_as_sequence*/
 | |
|         0,                      /*tp_as_mapping*/
 | |
|         0,                      /*tp_hash*/
 | |
|         0,                      /*tp_call*/
 | |
|         0,                      /*tp_str*/
 | |
|         0,                      /*tp_getattro*/
 | |
|         0,                      /*tp_setattro*/
 | |
|         0,                      /*tp_as_buffer*/
 | |
|         0,                      /*tp_flags*/
 | |
|         0,                      /*tp_doc*/
 | |
|         0,                      /*tp_traverse*/
 | |
|         0,                      /*tp_clear*/
 | |
|         0,                      /*tp_richcompare*/
 | |
|         0,                      /*tp_weaklistoffset*/
 | |
|         0,                      /*tp_iter*/
 | |
|         0,                      /*tp_iternext*/
 | |
|         methods,                /*tp_methods*/
 | |
|         0,                      /*tp_members*/
 | |
|         0,                      /*tp_getset*/
 | |
| };
 | 
