1383 lines
38 KiB
C
1383 lines
38 KiB
C
/* See http://www.python-ldap.org/ for details.
|
|
* $Id: LDAPObject.c,v 1.90 2011/04/11 11:29:59 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 (PyString_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 = PyString_Size(list);
|
|
lm->mod_bvalues[0]->bv_val = PyString_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 (!PyString_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 = PyString_Size(item);
|
|
lm->mod_bvalues[i]->bv_val = PyString_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;
|
|
|
|
if (attrlist == Py_None) {
|
|
/* None means a NULL attrlist */
|
|
} else if (PyString_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 (!PyString_Check(item)) {
|
|
PyErr_SetObject(PyExc_TypeError, Py_BuildValue("sO",
|
|
"expected string in list", item));
|
|
Py_DECREF(item);
|
|
goto error;
|
|
}
|
|
attrs[i] = PyString_AsString(item);
|
|
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 PyInt_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 PyInt_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 = PyString_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_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 = PyString_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 PyInt_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 PyInt_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 PyInt_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 PyInt_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 PyInt_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 PyInt_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 PyInt_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_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 PyInt_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 PyInt_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 },
|
|
#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 }
|
|
};
|
|
|
|
/* get attribute */
|
|
|
|
static PyObject*
|
|
getattr(LDAPObject* self, char* name)
|
|
{
|
|
return Py_FindMethod(methods, (PyObject*)self, name);
|
|
}
|
|
|
|
/* set attribute */
|
|
|
|
static int
|
|
setattr(LDAPObject* self, char* name, PyObject* value)
|
|
{
|
|
PyErr_SetString(PyExc_AttributeError, name);
|
|
return -1;
|
|
}
|
|
|
|
/* type entry */
|
|
|
|
PyTypeObject LDAP_Type = {
|
|
#if defined(MS_WINDOWS) || defined(__CYGWIN__)
|
|
/* see http://www.python.org/doc/FAQ.html#3.24 */
|
|
PyObject_HEAD_INIT(NULL)
|
|
#else /* ! MS_WINDOWS */
|
|
PyObject_HEAD_INIT(&PyType_Type)
|
|
#endif /* MS_WINDOWS */
|
|
0, /*ob_size*/
|
|
"LDAP", /*tp_name*/
|
|
sizeof(LDAPObject), /*tp_basicsize*/
|
|
0, /*tp_itemsize*/
|
|
/* methods */
|
|
(destructor)dealloc, /*tp_dealloc*/
|
|
0, /*tp_print*/
|
|
(getattrfunc)getattr, /*tp_getattr*/
|
|
(setattrfunc)setattr, /*tp_setattr*/
|
|
0, /*tp_compare*/
|
|
0, /*tp_repr*/
|
|
0, /*tp_as_number*/
|
|
0, /*tp_as_sequence*/
|
|
0, /*tp_as_mapping*/
|
|
0, /*tp_hash*/
|
|
};
|