Some questions (status,SSL,Unicode)
Michael Ströder
michael at stroeder.com
Sun Nov 11 01:37:32 CET 2001
Jacek Konieczny wrote:
>
> On Thu, Nov 08, 2001 at 03:15:57PM +0100, Michael Ströder wrote:
> > See item 1 on http://python-ldap.sourceforge.net/faq.shtml ;-).
> >
> > > 2. What about SSL/TLS/STARTTLS support? I realy need encrypted
> > > connection to LDAP server.
> >
> > Patches for using StartTLS were provided but not landed in CVS yet.
> > Also the implementation was somewhat incomplete since it lacks
> > support for setting up a local SSL context (trusted root CA certs,
> > CRL handling etc.).
> Could you send me those patches, please?
> So I won't duplicate work when I start doing this.
See attachment.
Ciao, Michael.
-------------- next part --------------
Index: setup.py
===================================================================
RCS file: /cvsroot/python-ldap/python-ldap/setup.py,v
retrieving revision 1.5
diff -u -w -r1.5 setup.py
--- setup.py 2001/05/24 21:07:42 1.5
+++ setup.py 2001/07/15 16:11:10
@@ -13,7 +13,7 @@
library_dirs = [ ]
include_dirs = [ ]
libs = ['ldap', 'lber']
- defines = [('USE_CIDICT', None),
+ defines = [#('USE_CIDICT', None),
#('WITH_KERBEROS', None),
#('HAVE_DES_SETKEY', None),
('LDAP_TYPE_IS_OPAQUE', None),
@@ -25,6 +25,7 @@
('HAVE_LDAP_MODRDN2', None),
('HAVE_LDAP_MODRDN2_S', None),
('HAVE_LDAP_SET_CACHE_OPTIONS', None),
+ ('HAVE_LDAP_START_TLS_S', None),
('HAVE_LDAP_UNCACHE_ENTRY', None),
('HAVE_LDAP_UNCACHE_REQUEST', None),
('HAVE_DISPTMPL_H', None),
Index: Modules/LDAPObject.c
===================================================================
RCS file: /cvsroot/python-ldap/python-ldap/Modules/LDAPObject.c,v
retrieving revision 1.11
diff -u -w -r1.11 LDAPObject.c
--- Modules/LDAPObject.c 2001/06/06 23:40:04 1.11
+++ Modules/LDAPObject.c 2001/07/15 16:11:12
@@ -515,7 +515,7 @@
return Py_None;
}
-#ifdef LDAP_REFERRALS
+#if defined(LDAP_REFERRALS) || LDAP_API_VERSION >= 2000
/* ldap_set_rebind_proc */
@@ -1211,9 +1211,9 @@
double timeout = -1.0;
struct timeval tv;
struct timeval* tvp;
- int res_type, result;
+ int res_type;
LDAPMessage *msg = NULL;
- PyObject *result_str, *retval;
+ PyObject *result_str, *retval, *pmsg;
if (!PyArg_ParseTuple( args, "|iid", &msgid, &all, &timeout ))
return NULL;
@@ -1239,29 +1239,50 @@
return Py_None;
}
- /* thanks to Konstantin Chuguev for this */
- if (res_type != LDAP_RES_SEARCH_ENTRY) {
+ if (res_type == LDAP_RES_SEARCH_ENTRY
+#if LDAP_API_VERSION >= 2000
+ || res_type == LDAP_RES_SEARCH_REFERENCE
+#endif
+ )
+ pmsg = LDAPmessage_to_python( self->ldap, msg );
+ else {
+ int result;
+#if LDAP_API_VERSION >= 2000
+ char **refs = NULL;
+ LDAP_BEGIN_ALLOW_THREADS( self );
+ ldap_parse_result( self->ldap, msg, &result, NULL, NULL, &refs, NULL, 0 );
+#else
LDAP_BEGIN_ALLOW_THREADS( self );
result = ldap_result2error( self->ldap, msg, 0 );
+#endif
LDAP_END_ALLOW_THREADS( self );
if (result != LDAP_SUCCESS) { /* result error */
+#if LDAP_API_VERSION >= 2000
+ 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";
+ return LDAPerror( self->ldap, e );
+#else
return LDAPerror( self->ldap, "ldap_result2error" );
+#endif
}
+ pmsg = Py_None;
}
result_str = LDAPconstant( res_type );
- if (msg == NULL) {
- retval = Py_BuildValue("(OO)", result_str, Py_None);
- } else {
- PyObject *pmsg = LDAPmessage_to_python( self->ldap, msg );
- if (pmsg == NULL)
+ if (pmsg == NULL) {
retval = NULL;
- else
+ } else {
retval = Py_BuildValue("(OO)", result_str, pmsg);
+ if (pmsg != Py_None) {
Py_DECREF(pmsg);
}
+ }
Py_DECREF(result_str);
return retval;
}
@@ -1451,6 +1472,9 @@
/* ldap_search_s == ldap_search_st */
+#if LDAP_API_VERSION < 2000
+/* OpenLDAPv1 */
+
/* ldap_ufn_search_c */
/* ldap_ufn_search_ct */
@@ -1534,8 +1558,39 @@
"\tSee the LDAP library manual pages for more information on these\n"
"\t`user-friendly name' functions.";
+#endif /* LDAP_API_VERSION < 2000 */
+
/* ldap_sort_entries */
+#ifdef HAVE_LDAP_START_TLS_S
+/* 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;
+}
+
+static char doc_start_tls[] =
+"start_tls_s() -> None\n\n"
+"\tNegotiate TLS with server. The `version' attribute must have been\n"
+"\tset to VERSION3 before calling start_tls_s.\n"
+"\tIf TLS could not be started an exception will be raised.\n"
+;
+#endif
+
/* ldap_url_search */
/* ldap_url_search_s */
@@ -1631,7 +1686,7 @@
{"add_s", (PyCFunction)l_ldap_add_s, METH_VARARGS, doc_add},
{"bind", (PyCFunction)l_ldap_bind, METH_VARARGS, doc_bind},
{"bind_s", (PyCFunction)l_ldap_bind_s, METH_VARARGS, doc_bind},
-#ifdef LDAP_REFERRALS
+#if defined(LDAP_REFERRALS) || LDAP_API_VERSION >= 2000
{"set_rebind_proc", (PyCFunction)l_ldap_set_rebind_proc, METH_VARARGS, doc_set_rebind_proc},
#endif /* LDAP_REFERRALS */
{"simple_bind", (PyCFunction)l_ldap_simple_bind, METH_VARARGS, doc_bind},
@@ -1688,9 +1743,14 @@
{"search", (PyCFunction)l_ldap_search, METH_VARARGS, doc_search},
{"search_s", (PyCFunction)l_ldap_search_st, METH_VARARGS, doc_search},
{"search_st", (PyCFunction)l_ldap_search_st, METH_VARARGS, doc_search},
+#ifdef HAVE_LDAP_START_TLS_S
+ {"start_tls_s", (PyCFunction)l_ldap_start_tls_s, METH_VARARGS, doc_start_tls},
+#endif
+#if LDAP_API_VERSION < 2000
{"ufn_search_s", (PyCFunction)l_ldap_ufn_search_s, METH_VARARGS, doc_ufn},
{"ufn_setfilter", (PyCFunction)l_ldap_ufn_setfilter, METH_VARARGS, doc_ufn},
{"ufn_setprefix", (PyCFunction)l_ldap_ufn_setprefix, METH_VARARGS, doc_ufn},
+#endif
{"url_search_s", (PyCFunction)l_ldap_url_search_st, METH_VARARGS, doc_url_search},
{"url_search_st", (PyCFunction)l_ldap_url_search_st, METH_VARARGS, doc_url_search},
#if defined(FILENO_SUPPORTED)
@@ -1766,6 +1826,47 @@
getattr( LDAPObject* self, char* name )
{
+#if LDAP_API_VERSION >= 2000
+/* OpenLDAPv2 */
+ int res, option, intval, is_string = 0;
+ char *strval;
+
+ if (streq(name,"version"))
+ option = LDAP_OPT_PROTOCOL_VERSION;
+ else if (streq(name,"deref"))
+ option = LDAP_OPT_DEREF;
+ else if (streq(name,"referrals"))
+ option = LDAP_OPT_REFERRALS;
+ else if (streq(name,"restart"))
+ option = LDAP_OPT_REFERRALS;
+ else if (streq(name,"timelimit"))
+ option = LDAP_OPT_TIMELIMIT;
+ else if (streq(name,"sizelimit"))
+ option = LDAP_OPT_SIZELIMIT;
+ else if (streq(name,"errno"))
+ option = LDAP_OPT_ERROR_NUMBER;
+ else if (streq(name,"error")) {
+ option = LDAP_OPT_ERROR_STRING;
+ is_string = 1;
+ } else if (streq(name,"matched")) {
+ option = LDAP_OPT_MATCHED_DN;
+ is_string = 1;
+ } else
+ return Py_FindMethod( methods, (PyObject*)self, name );
+ LDAP_BEGIN_ALLOW_THREADS( self );
+ res = ldap_get_option(self->ldap, option, is_string ? (void *)&strval
+ : (void *)&intval);
+ LDAP_END_ALLOW_THREADS( self );
+ if (res < 0)
+ return LDAPerror( self->ldap, "ldap_get_option" );
+ if (!is_string)
+ return PyInt_FromLong(intval);
+ if (strval != NULL)
+ return PyString_FromString(strval);
+ Py_INCREF(Py_None);
+ return Py_None;
+#else
+/* OpenLDAPv1 */
#ifndef LDAP_TYPE_IS_OPAQUE
if (streq(name,"lberoptions"))
return PyInt_FromLong(self->ldap->ld_lberoptions);
@@ -1798,6 +1899,7 @@
return PyInt_FromLong(self->valid);
return Py_FindMethod( methods, (PyObject*)self, name );
+#endif /* LDAP_API_VERSION >= 2000 */
}
/* set attribute */
@@ -1805,7 +1907,12 @@
static int
setattr( LDAPObject* self, char* name, PyObject* value )
{
+#if LDAP_API_VERSION >= 2000
+ int res, intval, option;
+ int *intptr = &intval;
+#else
long intval;
+#endif
if (streq(name,"errno") ||
streq(name,"error") ||
@@ -1821,6 +1928,34 @@
return -1;
}
+#if defined(LDAP_API_VERSION)
+/* OpenLDAPv2 */
+ if (streq(name,"deref"))
+ option = LDAP_OPT_DEREF;
+ else if(streq(name,"version"))
+ option = LDAP_OPT_PROTOCOL_VERSION;
+ else if(streq(name,"referrals")) {
+ option = LDAP_OPT_REFERRALS;
+ intptr = (void *)intval;
+ } else if(streq(name,"restart")) {
+ option = LDAP_OPT_RESTART;
+ intptr = (void *)intval;
+ } else if (streq(name,"timelimit"))
+ option = LDAP_OPT_TIMELIMIT;
+ else if (streq(name,"sizelimit"))
+ option = LDAP_OPT_SIZELIMIT;
+ else {
+ PyErr_SetString( PyExc_NameError, "cannot set that field" );
+ return -1;
+ }
+ LDAP_BEGIN_ALLOW_THREADS( self );
+ res = ldap_set_option(self->ldap, option, intptr);
+ LDAP_END_ALLOW_THREADS( self );
+ if (res < 0)
+ return LDAPerror( self->ldap, "ldap_get_option" ), -1;
+ return 0;
+#else
+/* OpenLDAPv1 */
# define set(a,max) \
if (streq(name,#a)) { \
if (intval < 0 || intval > max ) \
@@ -1844,6 +1979,7 @@
/* it fell through to here */
PyErr_SetString( PyExc_NameError, "cannot set that field" );
return -1;
+#endif /* LDAP_API_VERSION >= 2000 */
}
/* type entry */
Index: Modules/constants.c
===================================================================
RCS file: /cvsroot/python-ldap/python-ldap/Modules/constants.c,v
retrieving revision 1.6
diff -u -w -r1.6 constants.c
--- Modules/constants.c 2001/05/12 08:05:09 1.6
+++ Modules/constants.c 2001/07/15 16:11:12
@@ -79,6 +79,27 @@
add_int(d,REQ_COMPARE);
add_int(d,REQ_ABANDON);
+#if LDAP_API_VERSION >= 2000
+ /* OpenLDAPv2 */
+ add_int(d,VERSION3);
+ add_int(d,VERSION_MIN);
+ add_int(d,VERSION_MAX);
+ add_int(d,TAG_LDAPDN);
+ add_int(d,TAG_LDAPCRED);
+ add_int(d,TAG_CONTROLS);
+ add_int(d,TAG_REFERRAL);
+
+ add_int(d,REQ_EXTENDED);
+#endif
+#if LDAP_API_VERSION >= 2004
+ add_int(d,TAG_NEWSUPERIOR);
+ add_int(d,TAG_EXOP_REQ_OID);
+ add_int(d,TAG_EXOP_REQ_VALUE);
+ add_int(d,TAG_EXOP_RES_OID);
+ add_int(d,TAG_EXOP_RES_VALUE);
+ add_int(d,TAG_SASL_RES_CREDS);
+#endif
+
/* reversibles */
zero = PyInt_FromLong( 0 );
@@ -95,6 +116,14 @@
add_int_r(d,RES_COMPARE);
add_int(d,RES_ANY);
+#if LDAP_API_VERSION >= 2000
+ /* OpenLDAPv2 */
+ add_int_r(d,RES_SEARCH_REFERENCE);
+ add_int_r(d,RES_EXTENDED);
+ add_int_r(d,RES_EXTENDED_PARTIAL);
+ add_int_r(d,RES_UNSOLICITED);
+#endif
+
/* non-reversibles */
add_int(d,AUTH_NONE);
@@ -121,6 +150,21 @@
add_int(d,MOD_DELETE);
add_int(d,MOD_REPLACE);
add_int(d,MOD_BVALUES);
+
+#if LDAP_API_VERSION >= 2000
+ /* OpenLDAPv2 */
+ add_int(d,FILTER_EXT);
+ add_int(d,FILTER_EXT_OID);
+ add_int(d,FILTER_EXT_TYPE);
+ add_int(d,FILTER_EXT_VALUE);
+ add_int(d,FILTER_EXT_DNATTRS);
+
+ add_int(d,SCOPE_DEFAULT);
+
+ add_int(d,MSG_ONE);
+ add_int(d,MSG_ALL);
+ add_int(d,MSG_RECEIVED);
+#endif
/* (errors.c contains the error constants) */
Index: Modules/errors.c
===================================================================
RCS file: /cvsroot/python-ldap/python-ldap/Modules/errors.c,v
retrieving revision 1.3
diff -u -w -r1.3 errors.c
--- Modules/errors.c 2000/08/14 22:37:37 1.3
+++ Modules/errors.c 2001/07/15 16:11:12
@@ -17,7 +17,12 @@
/* list of error objects */
+#if LDAP_API_VERSION >= 2000
+ /* OpenLDAPv2 */
+#define NUM_LDAP_ERRORS LDAP_REFERRAL_LIMIT_EXCEEDED+1
+#else
#define NUM_LDAP_ERRORS LDAP_NO_MEMORY+1
+#endif
static PyObject*
errobjects[ NUM_LDAP_ERRORS ];
@@ -30,21 +35,26 @@
PyErr_SetFromErrno( LDAPexception_class );
return NULL;
}
-#ifdef LDAP_TYPE_IS_OPAQUE
+#if defined(LDAP_TYPE_IS_OPAQUE) && LDAP_API_VERSION < 2000
else {
PyErr_SetString(LDAPexception_class,
"unknown error (C API does not expose error)");
return NULL;
}
-#else
+#else /* defined(LDAP_TYPE_IS_OPAQUE) && LDAP_API_VERSION < 2000 */
else {
int errnum;
PyObject *errobj;
PyObject *info;
PyObject *str;
+#if LDAP_API_VERSION >= 2000
+ char *matched, *error;
+ if (ldap_get_option(l, LDAP_OPT_ERROR_NUMBER, &errnum) < 0)
+#else
errnum = l->ld_errno;
if (errnum<0 || errnum>=NUM_LDAP_ERRORS)
+#endif
errobj = LDAPexception_class; /* unknown error XXX */
else
errobj = errobjects[errnum];
@@ -61,6 +71,34 @@
PyDict_SetItemString( info, "desc", str );
Py_XDECREF(str);
+#if LDAP_API_VERSION >= 2000
+ if (ldap_get_option(l, LDAP_OPT_MATCHED_DN, &matched) >= 0
+ && matched != NULL) {
+ if (*matched != '\0') {
+ str = PyString_FromString(matched);
+ if (str)
+ PyDict_SetItemString( info, "matched", str );
+ Py_XDECREF(str);
+ }
+ ldap_memfree(matched);
+ }
+
+ if (errnum == LDAP_REFERRAL) {
+ str = PyString_FromString(msg);
+ if (str)
+ PyDict_SetItemString( info, "info", str );
+ Py_XDECREF(str);
+ } else if (ldap_get_option(l, LDAP_OPT_ERROR_STRING, &error) >= 0
+ && error != NULL) {
+ if (error != '\0') {
+ str = PyString_FromString(error);
+ if (str)
+ PyDict_SetItemString( info, "info", str );
+ Py_XDECREF(str);
+ }
+ ldap_memfree(error);
+ }
+#else /* LDAP_API_VERSION >= 2000 */
if (l->ld_matched != NULL && *l->ld_matched != '\0')
{
str = PyString_FromString(l->ld_matched);
@@ -76,11 +114,12 @@
PyDict_SetItemString( info, "info", str );
Py_XDECREF(str);
}
+#endif /* LDAP_API_VERSION >= 2000 */
PyErr_SetObject( errobj, info );
Py_DECREF(info);
return NULL;
}
-#endif
+#endif /* defined(LDAP_TYPE_IS_OPAQUE) && LDAP_API_VERSION < 2000 */
}
@@ -163,4 +202,20 @@
seterrobj(USER_CANCELLED);
seterrobj(PARAM_ERROR);
seterrobj(NO_MEMORY);
+#if LDAP_API_VERSION >= 2000
+ /* OpenLDAPv2 */
+ seterrobj(REFERRAL);
+ seterrobj(ADMINLIMIT_EXCEEDED);
+ seterrobj(UNAVAILABLE_CRITICAL_EXTENSION);
+ seterrobj(CONFIDENTIALITY_REQUIRED);
+ seterrobj(SASL_BIND_IN_PROGRESS);
+ seterrobj(AFFECTS_MULTIPLE_DSAS);
+ seterrobj(CONNECT_ERROR);
+ seterrobj(NOT_SUPPORTED);
+ seterrobj(CONTROL_NOT_FOUND);
+ seterrobj(NO_RESULTS_RETURNED);
+ seterrobj(MORE_RESULTS_TO_RETURN);
+ seterrobj(CLIENT_LOOP);
+ seterrobj(REFERRAL_LIMIT_EXCEEDED);
+#endif
}
Index: Modules/message.c
===================================================================
RCS file: /cvsroot/python-ldap/python-ldap/Modules/message.c,v
retrieving revision 1.7
diff -u -w -r1.7 message.c
--- Modules/message.c 2001/07/13 10:21:59 1.7
+++ Modules/message.c 2001/07/15 16:11:12
@@ -1,7 +1,7 @@
/* David Leonard <david.leonard at csee.uq.edu.au>, 1999. Public domain. */
/*
* LDAPMessageObject - wrapper around an LDAPMessage*
- * $Id: message.c,v 1.7 2001/07/13 10:21:59 kchuguev Exp $
+ * $Id: message.c,v 1.6 2000/08/18 00:21:46 leonard Exp $
*/
#include "common.h"
@@ -51,7 +51,11 @@
if (attrdict == NULL) {
Py_DECREF(result);
ldap_msgfree( m );
+#if LDAP_API_VERSION >= 2000
+ ldap_memfree(dn);
+#else
free(dn);
+#endif
return NULL;
}
@@ -82,7 +86,12 @@
if (ber != NULL)
ber_free(ber, 0);
ldap_msgfree( m );
+#if LDAP_API_VERSION >= 2000
+ ldap_memfree(attr);
+ ldap_memfree(dn);
+#else
free(dn);
+#endif
return NULL;
}
@@ -102,7 +111,12 @@
if (ber != NULL)
ber_free(ber, 0);
ldap_msgfree( m );
+#if LDAP_API_VERSION >= 2000
+ ldap_memfree(attr);
+ ldap_memfree(dn);
+#else
free(dn);
+#endif
return NULL;
}
Py_DECREF(valuestr);
@@ -110,14 +124,59 @@
ldap_value_free_len(bvals);
}
Py_DECREF( valuelist );
+#if LDAP_API_VERSION >= 2000
+ ldap_memfree(attr);
+#endif
}
entrytuple = Py_BuildValue("(sO)", dn, attrdict);
+#if LDAP_API_VERSION >= 2000
+ ldap_memfree(dn);
+#else
free(dn);
+#endif
Py_DECREF(attrdict);
PyList_Append(result, entrytuple);
Py_DECREF(entrytuple);
+#if ( LDAP_API_VERSION > 2000 )
+ if (ber != NULL)
+ ber_free(ber, 0);
+#endif
+ }
+#if LDAP_API_VERSION >= 2000
+ for(entry = ldap_first_reference(ld,m);
+ entry != NULL;
+ entry = ldap_next_reference(ld,entry))
+ {
+ char **refs = NULL;
+ PyObject* entrytuple;
+ PyObject* reflist = PyList_New(0);
+
+ if (reflist == NULL) {
+ Py_DECREF(result);
+ ldap_msgfree( m );
+ return NULL;
+ }
+ if (ldap_parse_reference(ld, entry, &refs, NULL, 0) != LDAP_SUCCESS) {
+ Py_DECREF(result);
+ ldap_msgfree( m );
+ return LDAPerror( ld, "ldap_parse_reference" );
+ }
+ if (refs) {
+ int i;
+ for (i=0; refs[i] != NULL; i++) {
+ PyObject *refstr = PyString_FromString(refs[i]);
+ PyList_Append(reflist, refstr);
+ Py_DECREF(refstr);
+ }
+ ber_memvfree( (void **) refs );
+ }
+ entrytuple = Py_BuildValue("(sO)", NULL, reflist);
+ Py_DECREF(reflist);
+ PyList_Append(result, entrytuple);
+ Py_DECREF(entrytuple);
}
+#endif
ldap_msgfree( m );
return result;
}
More information about the python-ldap
mailing list