compiling against OpenLDAP 2.0.11

Konstantin Chuguev Konstantin.Chuguev at dante.org.uk
Tue Jul 10 10:59:59 CEST 2001


Hi Michael,

Michael Ströder wrote:

> David was working to incorporate your patches but did not commit
> anything so far. The diffs based on your work he sent me does not
> seem to work with recent OpenLDAP 2.0.11. It seems to me that the

Yes, OpenLDAP-2.0.11 and especially recent changes in python-ldap CVS
repository require a new version of patches. I've attached them.
The patches don't change the behaviour of python-ldap when compiled
against OpenLDAPv1, but create an alternative code when used with
OpenLDAPv2. Here are the differences between python-ldap compiled
against OpenLDAPv1 and v2 using the patches (seen from the point of view
of a programmer using python-ldap):

   * new constants added for v2 (see constants.c.patch);
   * new errors/exceptions added for v2 (see errors.c.patch);
   * a set of LDAP session attributes changed:
        o only in v1: lberoptions (rw), refhoplimit (rw), options (rw),
          valid (ro);
        o only in v2: version (rw), referrals (rw), restart (rw);
        o in both versions: deref (rw), timelimit (rw), sizelimit (rw),
          errno (ro), error (ro), matched (ro).
   * new type of data added to the Python dictionary returned as a
     result of ldap_result:
     Dictionary keys are DNs, values are entry objects. If the key is
     empty, the value is the list of referrals (URL text strings).

>
> OpenLDAP 2 API is still subject to minor changes (e.g.
> ldap_set_rebind_proc()). Unfortunately David is not available to

I haven't touched set_rebind_proc in python-ldap yet, because that would
change its API. At the moment you'll get a compile time warning and
possible crash if you use rebind_proc with python-ldap + OpenLDAPv2. It
is impossible to use the v1 set_rebind_proc syntax in v2. It is
theoretically possible to use the OpenLDAPv2 syntax of the function with
the OpenLDAPv1 library, using an internal conversion function. It would
require some programming and (needs your approval) a change to the
python-ldap API. Suggestions?

Regards,
    Konstantin.

--
          * *        Konstantin Chuguev - Application Engineer
       *      *              Francis House, 112 Hills Road
     *                       Cambridge CB2 1PQ, United Kingdom
 D  A  N  T  E       WWW:    http://www.dante.net


-------------- next part --------------
--- constants.c.orig	Sat May 12 09:05:09 2001
+++ constants.c	Mon Jun 11 11:05:12 2001
@@ -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) */
 
-------------- next part --------------
--- errors.c.orig	Mon Aug 14 23:37:37 2000
+++ errors.c	Tue Jun  5 11:43:59 2001
@@ -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
 }
-------------- next part --------------
--- LDAPObject.c.orig	Thu Jun  7 00:40:04 2001
+++ LDAPObject.c	Mon Jun 11 10:57:59 2001
@@ -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,28 +1239,49 @@
     	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);
+    if (pmsg == NULL) {
+    	retval = NULL;
     } else {
-	PyObject *pmsg = LDAPmessage_to_python( self->ldap, msg );
-	if (pmsg == NULL) 
-	    retval = NULL;
-	else
-	    retval = Py_BuildValue("(OO)", result_str, pmsg);
-        Py_DECREF(pmsg);
+	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,6 +1558,8 @@
 "\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 */
 
 /* ldap_url_search */
@@ -1631,7 +1657,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 +1714,11 @@
     {"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},	
+#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 +1794,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 +1867,7 @@
 		return PyInt_FromLong(self->valid);
 
 	return Py_FindMethod( methods, (PyObject*)self, name );
+#endif /* LDAP_API_VERSION >= 2000 */
 }
 
 /* set attribute */
@@ -1805,7 +1875,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 +1896,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 +1947,7 @@
 	/* it fell through to here */
 	PyErr_SetString( PyExc_NameError, "cannot set that field" );
 	return -1;
+#endif /* LDAP_API_VERSION >= 2000 */
 }
 
 /* type entry */
-------------- next part --------------
--- message.c.orig	Fri Aug 18 01:21:46 2000
+++ message.c	Tue Jun  5 09:59:29 2001
@@ -114,6 +114,40 @@
 	 PyList_Append(result, entrytuple);
 	 Py_DECREF(entrytuple);
      }
+#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