Stig,

I need to use LDAP controls in PHP, including control response from
server to client, so I patched the 5.0.5/HEAD code to add an extra arg
to ldap_parse_result() and ldap_parse_reference().  I'd need this patch
in production at some point, that's why it would be great to see it
merged into the mainstream; however, I'm little familiar with the
internals of PHP, so please excuse me if I missed anything in coding and
in the submission procedure.

The very same patch applies to HEAD and to 5.0.5.  If you don't mind,
I'm posting it to you right now, pending further work.  It also includes
some extra work I did to eliminate some warnings from OpenLDAP 2.3, but
it works fine with 2.2 as well.  All changes specific to OpenLDAP are
protected behind the LDAP_API_FEATURE_X_OPENLDAP macro.  Unfortunately I
have no chances to check it with other APIs right now.  I'm also
including a trivial script I tested with ./sapi/cli/php against the
server resulting from test003 of OpenLDAP 2.3; to reproduce, just 

cd openldap/tests/
../run -k test003
cd php
../sapi/cli/php pagedResults.php

If the code looks fine, I plan to document the new API, which is
completely backwards compatible, and add some facilities to
encode/decode the control values; hopefully, I won't have to get to
writing a complete wrapper around liblber!

My idea is to provide dumb helpers that encode well-known controls
through a trivial API; e.g., for pagedResults:

ldap_control_paged_results($handler, $size, $iscritical[, $cookie])
ldap_control_paged_results_resp($result, &$cookie[, &$iscritical[, &
$estimate]])

for passwdPolicy:

ldap_control_passwd_policy($handler[, $iscritical])
ldap_control_passwd_policy_resp($result, &$warning, &$error)

Please let me know if you need me to do anything else.

Sincerely, p.

-- 
Pierangelo Masarati
mailto:[EMAIL PROTECTED]





Ing. Pierangelo Masarati

Responsabile Open Solution



SysNet s.n.c.

Via Dossi, 8 - 27100 Pavia - ITALIA

http://www.sys-net.it

------------------------------------------

Office:   +39.02.23998309          

Mobile:   +39.333.4963172

Email:    [EMAIL PROTECTED]

------------------------------------------


Index: ext/ldap/ldap.c
===================================================================
RCS file: /repository/php-src/ext/ldap/ldap.c,v
retrieving revision 1.162
diff -u -r1.162 ldap.c
--- ext/ldap/ldap.c	22 Aug 2005 12:22:08 -0000	1.162
+++ ext/ldap/ldap.c	8 Nov 2005 21:04:05 -0000
@@ -191,7 +191,9 @@
 {
 	ldap_linkdata *ld = (ldap_linkdata *)rsrc->ptr;
 
-	ldap_unbind_s(ld->link);
+	/* ldap_unbind_s() is deprecated;
+	 * the distinction between ldap_unbind() and ldap_unbind_s() is moot */
+	ldap_unbind_ext(ld->link, NULL, NULL);
 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
 	if (ld->rebindproc != NULL) {
 		zval_dtor(ld->rebindproc);
@@ -215,6 +217,79 @@
 	efree(entry);
 } 
 
+static int _parse_referrals_resp(char ***lreferralsp, zval **referrals)
+{
+	int	num_referrals = 0;
+
+	if (*lreferralsp != NULL) {
+		char	**refp = *lreferralsp;
+
+		while (*refp) {
+			add_next_index_string(*referrals, *refp, 1);
+			refp++;
+			num_referrals++;
+		}
+#ifdef LDAP_API_FEATURE_X_OPENLDAP
+		ber_memvfree((void **)*lreferralsp);
+#else
+		ldap_value_free(*lreferralsp);
+#endif
+		*lreferralsp = NULL;
+	}
+
+	add_assoc_long(*referrals, "count", num_referrals);
+
+	return num_referrals;
+}
+
+static int _parse_server_controls_resp(LDAPControl ***lserverctrlsp, zval **serverctrls)
+{
+	int	num_serverctrls = 0;
+
+	if (*lserverctrlsp != NULL) {
+		int		error = 0;
+		LDAPControl	**ctrlp = *lserverctrlsp;
+
+		while (*ctrlp) {
+			zval *ctrlval = NULL;
+
+			if ( (*ctrlp)->ldctl_oid == NULL ) {
+				error = 1;
+				break;
+			}
+
+			MAKE_STD_ZVAL(ctrlval);
+			array_init(ctrlval);
+
+			add_assoc_string(ctrlval, "oid", (*ctrlp)->ldctl_oid, 1);
+			if ( (*ctrlp)->ldctl_value.bv_len ) {
+				add_assoc_stringl(ctrlval, "value", (*ctrlp)->ldctl_value.bv_val, (*ctrlp)->ldctl_value.bv_len, 1);
+			}
+			if ((*ctrlp)->ldctl_iscritical) {
+				add_assoc_bool(ctrlval, "iscritical", (*ctrlp)->ldctl_iscritical);
+			}
+
+			add_next_index_zval(*serverctrls, ctrlval);
+
+			num_serverctrls++;
+			ctrlp++;
+		}
+		ldap_controls_free(*lserverctrlsp);
+		*lserverctrlsp = NULL;
+
+		if (error) {
+			/* ... */
+			return -1;
+		}
+	}
+
+	if (num_serverctrls != -1) {
+		add_assoc_long(*serverctrls, "count", num_serverctrls);
+	}
+
+	return num_serverctrls;
+}
+
 /* {{{ PHP_INI_BEGIN
  */
 PHP_INI_BEGIN()
@@ -370,7 +445,11 @@
 {
 	char *host = NULL;
 	int hostlen;
+#ifdef LDAP_API_FEATURE_X_OPENLDAP
+	long port = LDAP_PORT;
+#else
 	long port = 389; /* Default port */
+#endif
 #ifdef HAVE_ORALDAP
 	char *wallet, *walletpasswd;
 	int walletlen, walletpasswdlen;
@@ -406,17 +485,33 @@
 	ld = ecalloc(1, sizeof(ldap_linkdata));
 
 #ifdef LDAP_API_FEATURE_X_OPENLDAP
-	if (host != NULL && strchr(host, '/')) {
-		int rc;
+	/* OpenLDAP provides a specific call to detect valid LDAP URIs */
+	{
+		int	rc;
+		char	*url = host;
+
+		if (!ldap_is_ldap_url(url)) {
+			int	urllen = hostlen + sizeof( "ldap://:65535"; );
+
+			if (port < 0 || port > 65535) {
+				php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid port number: %ld", port);
+				RETURN_FALSE;
+			}
+
+			url = emalloc(urllen);
+			snprintf( url, urllen, "ldap://%s:%ld";, host ? host : "", port ? port : LDAP_PORT );
+		}
 		
-		rc = ldap_initialize(&ldap, host);
+		rc = ldap_initialize(&ldap, url);
 		if (rc != LDAP_SUCCESS) {
 			efree(ld);
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not create session handle: %s", ldap_err2string(rc));
 			RETURN_FALSE;
 		}
-	} else {
-		ldap = ldap_init(host, port);
+
+		if (url != host) {
+			efree(url);
+		}
 	}
 #else
 	ldap = ldap_open(host, port);
@@ -479,7 +574,21 @@
 
 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
 
-	if ((rc = ldap_bind_s(ld->link, ldap_bind_dn, ldap_bind_pw, LDAP_AUTH_SIMPLE)) != LDAP_SUCCESS) {
+#ifdef LDAP_API_FEATURE_X_OPENLDAP
+	{
+		struct berval	cred;
+
+		/* ldap_bind_s() is deprecated; use ldap_sasl_bind_s() instead */
+		cred.bv_val = ldap_bind_pw;
+		cred.bv_len = ldap_bind_pw ? ldap_bind_pwlen : 0;
+		rc = ldap_sasl_bind_s(ld->link, ldap_bind_dn, LDAP_SASL_SIMPLE, &cred,
+				NULL, NULL,	/* no controls right now */
+				NULL);		/* we don't care about the server's credentials */
+	}
+#else
+	rc = ldap_bind_s(ld->link, ldap_bind_dn, ldap_bind_pw, LDAP_AUTH_SIMPLE);
+#endif
+	if ( rc != LDAP_SUCCESS) {
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc));
 		RETURN_FALSE;
 	} else {
@@ -1030,7 +1139,6 @@
 	BerElement *ber;
 	char *attribute;
 	size_t attr_len;
-	char **ldap_value;
 	char *dn;
 
 	if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &link, &result) == FAILURE) {
@@ -1061,16 +1169,18 @@
 		attribute = ldap_first_attribute(ldap, ldap_result_entry, &ber);
 
 		while (attribute != NULL) {
-			ldap_value = ldap_get_values(ldap, ldap_result_entry, attribute);
-			num_values = ldap_count_values(ldap_value);
+			struct berval	**ldap_value;
+			
+			ldap_value = ldap_get_values_len(ldap, ldap_result_entry, attribute);
+			num_values = ldap_count_values_len(ldap_value);
 
 			MAKE_STD_ZVAL(tmp2);
 			array_init(tmp2);
 			add_assoc_long(tmp2, "count", num_values);
 			for (i = 0; i < num_values; i++) {
-				add_index_string(tmp2, i, ldap_value[i], 1);
+				add_index_stringl(tmp2, i, ldap_value[i]->bv_val, ldap_value[i]->bv_len, 1);
 			}	
-			ldap_value_free(ldap_value);
+			ldap_value_free_len(ldap_value);
 
 			attr_len = strlen(attribute);
 			zend_hash_update(Z_ARRVAL_P(tmp1), php_strtolower(attribute, attr_len), attr_len+1, (void *) &tmp2, sizeof(zval *), NULL);
@@ -1177,7 +1287,6 @@
 	ldap_linkdata *ld;
 	ldap_resultentry *resultentry;
 	char *attribute;
-	char **ldap_value;
 	int i, num_values, num_attrib;
 	BerElement *ber;
 
@@ -1193,16 +1302,18 @@
 	
 	attribute = ldap_first_attribute(ld->link, resultentry->data, &ber);
 	while (attribute != NULL) {
-		ldap_value = ldap_get_values(ld->link, resultentry->data, attribute);
-		num_values = ldap_count_values(ldap_value);
+		struct berval	**ldap_value;
+		
+		ldap_value = ldap_get_values_len(ld->link, resultentry->data, attribute);
+		num_values = ldap_count_values_len(ldap_value);
 
 		MAKE_STD_ZVAL(tmp);
 		array_init(tmp);
 		add_assoc_long(tmp, "count", num_values);
 		for (i = 0; i < num_values; i++) {
-			add_index_string(tmp, i, ldap_value[i], 1);
+			add_index_stringl(tmp, i, ldap_value[i]->bv_val, ldap_value[i]->bv_len, 1);
 		}
-		ldap_value_free(ldap_value);
+		ldap_value_free_len(ldap_value);
 
 		zend_hash_update(Z_ARRVAL_P(return_value), attribute, strlen(attribute)+1, (void *) &tmp, sizeof(zval *), NULL);
 		add_index_string(return_value, num_attrib, attribute, 1);
@@ -1231,7 +1342,7 @@
 	ldap_linkdata *ld;
 	ldap_resultentry *resultentry;
 	char *attribute;
-	char **ldap_value;
+	struct berval **ldap_value;
 	int i, num_values;
 
 	if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &link, &result_entry, &attr) == FAILURE) {
@@ -1244,21 +1355,21 @@
 	convert_to_string_ex(attr);
 	attribute = Z_STRVAL_PP(attr);
 
-	if ((ldap_value = ldap_get_values(ld->link, resultentry->data, attribute)) == NULL) {
+	if ((ldap_value = ldap_get_values_len(ld->link, resultentry->data, attribute)) == NULL) {
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot get the value(s) of attribute %s", ldap_err2string(_get_lderrno(ld->link)));
 		RETURN_FALSE;
 	}
 
-	num_values = ldap_count_values(ldap_value);
+	num_values = ldap_count_values_len(ldap_value);
 
 	array_init(return_value);
 
 	for (i = 0; i<num_values; i++) {
-		add_next_index_string(return_value, ldap_value[i], 1);
+		add_next_index_stringl(return_value, ldap_value[i]->bv_val, ldap_value[i]->bv_len, 1);
 	}
 	
 	add_assoc_long(return_value, "count", num_values);
-	ldap_value_free(ldap_value);
+	ldap_value_free_len(ldap_value);
 
 }
 /* }}} */
@@ -1363,7 +1474,11 @@
 		add_index_string(return_value, i, ldap_value[i], 1);
 	}
 
+#ifdef LDAP_API_FEATURE_X_OPENLDAP
+	ber_memvfree((void **)ldap_value);
+#else
 	ldap_value_free(ldap_value);
+#endif
 }
 /* }}} */
 
@@ -1933,14 +2048,15 @@
    Extract information from result */
 PHP_FUNCTION(ldap_parse_result) 
 {
-	zval **link, **result, **errcode, **matcheddn, **errmsg, **referrals;
+	zval **link, **result, **errcode, **matcheddn, **errmsg, **referrals, **serverctrls;
 	ldap_linkdata *ld;
 	LDAPMessage *ldap_result;
-	char **lreferrals, **refp;
+	LDAPControl **lserverctrls;
+	char **lreferrals;
 	char *lmatcheddn, *lerrmsg;
 	int rc, lerrcode, myargcount = ZEND_NUM_ARGS();
 
-	if (myargcount < 3 || myargcount > 6 || zend_get_parameters_ex(myargcount, &link, &result, &errcode, &matcheddn, &errmsg, &referrals) == FAILURE) {
+	if (myargcount < 3 || myargcount > 7 || zend_get_parameters_ex(myargcount, &link, &result, &errcode, &matcheddn, &errmsg, &referrals, &serverctrls) == FAILURE) {
 		WRONG_PARAM_COUNT;
 	}
 
@@ -1951,7 +2067,7 @@
 				myargcount > 3 ? &lmatcheddn : NULL,
 				myargcount > 4 ? &lerrmsg : NULL,
 				myargcount > 5 ? &lreferrals : NULL,
-				NULL /* &serverctrls */,
+				myargcount > 6 ? &lserverctrls : NULL,
 				0);
 	if (rc != LDAP_SUCCESS) {
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse result: %s", ldap_err2string(rc));
@@ -1963,17 +2079,15 @@
 
 	/* Reverse -> fall through */
 	switch (myargcount) {
+		case 7:
+			/* use arg #7 as the array of controls returned by the server */
+			zval_dtor(*serverctrls);
+			array_init(*serverctrls);
+			_parse_server_controls_resp(&lserverctrls, serverctrls);
 		case 6:
 			zval_dtor(*referrals);
 			array_init(*referrals);
-			if (lreferrals != NULL) {
-				refp = lreferrals;
-				while (*refp) {
-					add_next_index_string(*referrals, *refp, 1);
-					refp++;
-				}
-				ldap_value_free(lreferrals);
-			}
+			_parse_referrals_resp(&lreferrals, referrals);
 		case 5:
 			zval_dtor(*errmsg);
 			if (lerrmsg == NULL) {
@@ -2057,32 +2171,38 @@
    Extract information from reference entry */
 PHP_FUNCTION(ldap_parse_reference)
 {
-	zval **link, **result_entry, **referrals;
+	zval **link, **result_entry, **referrals, **serverctrls;
 	ldap_linkdata *ld;
 	ldap_resultentry *resultentry;
-	char **lreferrals, **refp;
+	char **lreferrals;
+	LDAPControl **lserverctrls;
+	int myargcount = ZEND_NUM_ARGS();
 
-	if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &link, &result_entry, &referrals) == FAILURE) {
+	if (myargcount < 3 || myargcount > 4 || zend_get_parameters_ex(4, &link, &result_entry, &referrals, &serverctrls) == FAILURE) {
 		WRONG_PARAM_COUNT;
 	}
 
 	ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
 	ZEND_FETCH_RESOURCE(resultentry, ldap_resultentry *, result_entry, -1, "ldap result entry", le_result_entry);
 
-	if (ldap_parse_reference(ld->link, resultentry->data, &lreferrals, NULL /* &serverctrls */, 0) != LDAP_SUCCESS) {
+	if (ldap_parse_reference(ld->link, resultentry->data, &lreferrals, &lserverctrls, 0) != LDAP_SUCCESS) {
 		RETURN_FALSE;
 	}
 
-	zval_dtor(*referrals);
-	array_init(*referrals);
-	if (lreferrals != NULL) {
-		refp = lreferrals;
-		while (*refp) {
-			add_next_index_string(*referrals, *refp, 1);
-			refp++;
-		}
-		ldap_value_free(lreferrals);
+
+	/* Reverse -> fall through */
+	switch (myargcount) {
+		case 4:
+			/* use arg #4 as the array of controls returned by the server */
+			zval_dtor(*serverctrls);
+			array_init(*serverctrls);
+			_parse_server_controls_resp(&lserverctrls, serverctrls);
+		case 3:
+			zval_dtor(*referrals);
+			array_init(*referrals);
+			_parse_referrals_resp(&lreferrals, referrals);
 	}
+
 	RETURN_TRUE;
 }
 /* }}} */

Attachment: pagedResults.php
Description: application/php

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to