php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #61853
Patch patch_61853_and_61921.patch revision 2013-02-24 17:05 UTC by etienne at lamaisondebarbie dot ch
revision 2013-02-24 16:52 UTC by etienne at lamaisondebarbie dot ch
Patch php_ldap_do-ifdef.patch revision 2012-04-26 10:14 UTC by etienne at lamaisondebarbie dot ch
revision 2012-04-26 10:09 UTC by etienne at lamaisondebarbie dot ch
Patch php_ldap_do_modify.patch revision 2012-04-26 08:06 UTC by etienne at lamaisondebarbie dot ch
Patch php_ldap_do_search.patch revision 2012-04-25 20:52 UTC by etienne at lamaisondebarbie dot ch
revision 2012-04-25 20:38 UTC by etienne at lamaisondebarbie dot ch

Patch patch_61853_and_61921.patch for LDAP related Bug #61853

Patch version 2013-02-24 17:05 UTC

Return to Bug #61853 | Download this patch
This patch renders other patches obsolete

Obsolete patches:

Patch Revisions:

Developer: etienne@lamaisondebarbie.ch

From 4fc6ae12d72b0be83813535d448d3b445e0708e7 Mon Sep 17 00:00:00 2001
From: Etienne Bagnoud <tchetch@i-james.com>
Date: Sun, 24 Feb 2013 17:40:58 +0100
Subject: [PATCH 1/3] Bug #61853 and #61921

---
 ext/ldap/ldap_dev_utils.c |   87 +++++++++++++++++++++++++++++++++++++++++++++
 ext/ldap/ldap_dev_utils.h |   34 ++++++++++++++++++
 2 files changed, 121 insertions(+)
 create mode 100644 ext/ldap/ldap_dev_utils.c
 create mode 100644 ext/ldap/ldap_dev_utils.h

diff --git a/ext/ldap/ldap_dev_utils.c b/ext/ldap/ldap_dev_utils.c
new file mode 100644
index 0000000..0a8d109
--- /dev/null
+++ b/ext/ldap/ldap_dev_utils.c
@@ -0,0 +1,87 @@
+#include <string.h>
+#include "ldap_dev_utils.h"
+
+struct berval * ldu_ber_dupbv(struct berval * dst, struct berval * src)
+{
+	struct berval * new = NULL;
+
+	if(src != NULL) {
+		if(dst == NULL) {
+			new = LDU_MALLOC(sizeof(*dst));
+		} else {
+			new = dst;
+		}
+		if(new != NULL) {
+			if(src->bv_val == NULL) {
+				new->bv_val = NULL;
+				new->bv_len = 0;
+			} else {
+				new->bv_val = LDU_MALLOC(src->bv_len + 1);
+				if(new->bv_val == NULL) {
+					if(dst == NULL) {
+						LDU_FREE(new);
+					}
+					new = NULL;
+				} else {
+					memcpy(new->bv_val, src->bv_val, src->bv_len);
+					new->bv_val[src->bv_len] = '\0';
+					new->bv_len = src->bv_len;
+				}
+			}
+		}
+	}
+
+	return new;
+}
+
+LDAPControl * ldu_ldap_control_create(const char * oid, int iscritical,
+		struct berval * value)
+{
+	LDAPControl * ctrl = NULL;
+
+	if(oid != NULL) {
+		ctrl = LDU_CALLOC(sizeof(*ctrl), 1);
+		if(ctrl != NULL) {
+			ctrl->ldctl_iscritical = iscritical ? 1 : 0;
+
+			if(value != NULL && ! BER_BVISNULL(value)) {
+				ldu_ber_dupbv( &(ctrl->ldctl_value), value);
+			}
+
+			ctrl->ldctl_oid = LDU_STRDUP(oid);
+			if(ctrl->ldctl_oid == NULL) {
+				ldu_ldap_control_free(ctrl);
+				ctrl = NULL;
+			}
+		}
+	}
+
+	return ctrl;
+}
+
+void ldu_ldap_controls_free(LDAPControl ** ctrls)
+{
+	LDAPControl ** orig = ctrls;
+
+	if(ctrls != NULL) {
+		while(*ctrls != NULL) {
+			ldu_ldap_control_free(*ctrls);
+			ctrls++;
+		}
+		LDU_FREE(orig);
+	}
+}
+
+void ldu_ldap_control_free(LDAPControl * ctrl)
+{
+	if(ctrl != NULL) {
+		if(ctrl->ldctl_value.bv_val != NULL) {
+			LDU_FREE(ctrl->ldctl_value.bv_val);
+		}
+		if(ctrl->ldctl_oid != NULL) {
+			LDU_FREE(ctrl->ldctl_oid);
+		}
+	
+		LDU_FREE(ctrl);
+	}
+}
diff --git a/ext/ldap/ldap_dev_utils.h b/ext/ldap/ldap_dev_utils.h
new file mode 100644
index 0000000..2591698
--- /dev/null
+++ b/ext/ldap/ldap_dev_utils.h
@@ -0,0 +1,34 @@
+#ifndef LDAP_DEV_UTILS_H__
+#define LDAP_DEV_UTILS_H__
+
+#include <ldap.h>
+#include "php.h"
+
+
+#ifndef BER_BVISNULL
+#define BER_BVISNULL(bv)			((bv)->bv_val == NULL)
+#endif /* BER_BVISNULL */
+
+
+#ifndef LDU_MALLOC
+#define LDU_MALLOC	emalloc
+#endif
+
+#ifndef LDU_CALLOC
+#define LDU_CALLOC	ecalloc
+#endif
+
+#ifndef LDU_FREE
+#define LDU_FREE efree
+#endif
+
+#ifndef LDU_STRDUP
+#define LDU_STRDUP estrdup	
+#endif
+
+struct berval * ldu_ber_dupbv(struct berval * dst, struct berval * src);
+LDAPControl * ldu_ldap_control_create(const char * oid, int iscritical,
+		struct berval * value);
+void ldu_ldap_controls_free(LDAPControl ** ctrls);
+void ldu_ldap_control_free(LDAPControl * ctrl);
+#endif /* LDAP_DEV_UTILS_H__ */
-- 
1.7.10.4


From 0b2f50ed43bf212c53b3d077b5033022cf76ee96 Mon Sep 17 00:00:00 2001
From: Etienne Bagnoud <tchetch@i-james.com>
Date: Sun, 24 Feb 2013 17:45:42 +0100
Subject: [PATCH 2/3] Bugs correction

---
 ext/ldap/config.m4  |    2 +-
 ext/ldap/config.w32 |    5 +-
 ext/ldap/ldap.c     |  668 ++++++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 643 insertions(+), 32 deletions(-)

diff --git a/ext/ldap/config.m4 b/ext/ldap/config.m4
index 58d994c..069680c 100644
--- a/ext/ldap/config.m4
+++ b/ext/ldap/config.m4
@@ -70,7 +70,7 @@ PHP_ARG_WITH(ldap-sasl,for LDAP Cyrus SASL support,
 
 if test "$PHP_LDAP" != "no"; then
 
-  PHP_NEW_EXTENSION(ldap, ldap.c, $ext_shared,,-DLDAP_DEPRECATED=1)
+  PHP_NEW_EXTENSION(ldap, ldap.c ldap_dev_utils.c, $ext_shared,,)
 
   if test "$PHP_LDAP" = "yes"; then
     for i in /usr/local /usr; do
diff --git a/ext/ldap/config.w32 b/ext/ldap/config.w32
index 2fa05f4..98bbe0c 100644
--- a/ext/ldap/config.w32
+++ b/ext/ldap/config.w32
@@ -13,15 +13,14 @@ if (PHP_LDAP != "no") {
 			CHECK_LIB("oldap32_a.lib", "ldap", PHP_LDAP) &&
 			CHECK_LIB("olber32_a.lib", "ldap", PHP_LDAP)&&
 			CHECK_LIB("libsasl.lib", "ldap", PHP_LDAP)) {
-		EXTENSION('ldap', 'ldap.c');
-
+		EXTENSION('ldap', 'ldap.c ldap_dev_utils.c');
+		
 		AC_DEFINE('HAVE_LDAP_PARSE_RESULT', 1);
 		AC_DEFINE('HAVE_LDAP_PARSE_REFERENCE', 1);
 		AC_DEFINE('HAVE_LDAP_START_TLS_S', 1);
 		AC_DEFINE('HAVE_LDAP', 1);
 		AC_DEFINE('HAVE_LDAP_SASL', 1);
 		AC_DEFINE('HAVE_LDAP_SASL_SASL_H', 1);
-		AC_DEFINE('LDAP_DEPRECATED', 1);
 
 	} else {
 		WARNING("ldap not enabled; libraries and headers not found");
diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c
index 3cfa209..c7d0512 100644
--- a/ext/ldap/ldap.c
+++ b/ext/ldap/ldap.c
@@ -67,6 +67,8 @@
 #include <sasl/sasl.h>
 #endif
 
+#include "ldap_dev_utils.h"
+
 typedef struct {
 	LDAP *link;
 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
@@ -125,6 +127,435 @@ static void _free_ldap_result_entry(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{
 } 
 /* }}} */
 
+/* {{{ _php_ber_to_array_recursive
+   Convert 'struct berval' to an indexed array. This function does the work
+   recursively as BER is a recursive data structure.
+ */
+static int _php_ber_to_array_recursive(BerElement * element, zval * array)
+{
+	int error_count = 0;
+	zval *new = NULL, *value = NULL, *root = NULL;
+	char *cookie = NULL;
+	ber_tag_t tag = LBER_ERROR;
+	ber_len_t len = 0, bitstring_len = 0, bitstring_len_bytes = 0;
+	ber_int_t int_value = 0;
+	struct berval * berval_value = NULL;
+	char * char_value = NULL;
+	div_t bits_to_bytes = {0, 0};
+
+	if(element != NULL && array != NULL) {
+		for(
+				tag = ber_first_element(element, &len, &cookie);
+				tag != LBER_ERROR;
+				tag = ber_next_element(element, &len, cookie))
+		{
+			switch(tag) {
+				case LBER_BOOLEAN:
+					if( LBER_ERROR != ber_scanf(element, "b" ,&int_value)) {
+						ALLOC_INIT_ZVAL(value);
+						array_init(value);
+
+						add_assoc_string(value, "type", "boolean", 1);
+						add_assoc_bool(value, "value", int_value ? 1 : 0);
+
+						add_next_index_zval(array, value);
+						value = NULL;
+					} else {
+						error_count++;
+					}
+					break;
+				case LBER_INTEGER:
+					if( LBER_ERROR != ber_scanf(element, "i", &int_value)) {
+						ALLOC_INIT_ZVAL(value);
+						array_init(value);
+
+						add_assoc_string(value, "type", "integer", 1);
+						add_assoc_long(value, "value", int_value);
+
+						add_next_index_zval(array, value);
+						value = NULL;
+					} else {
+						add_next_index_null(array);
+						error_count++;
+					}
+					break;
+				case LBER_BITSTRING:
+					if( LBER_ERROR != ber_scanf(
+								element,
+								"B",
+								&char_value,
+								&bitstring_len)) {
+						ALLOC_INIT_ZVAL(value);
+						array_init(value);
+
+						/* bitstrings length is in bits. We calculate enough
+						   space for the whole bitstring.
+						 */
+						bits_to_bytes = div(abs(bitstring_len), 8);
+						bitstring_len_bytes = bits_to_bytes.quot;
+						if(bits_to_bytes.rem > 0) bitstring_len_bytes++;
+
+						add_assoc_string(value, "type", "bitstring", 1);
+						add_assoc_stringl(
+								value,
+								"value",
+								char_value,
+								bitstring_len_bytes,
+								1);
+						add_assoc_long(value, "lenght", bitstring_len);
+
+						add_next_index_zval(array, value);
+						value = NULL;
+
+						ber_memfree(char_value);
+						char_value=NULL;
+					} else {
+						error_count++;
+					}
+					break;
+				case LBER_OCTETSTRING:
+					if( LBER_ERROR != ber_scanf(element, "O", &berval_value)) {
+						ALLOC_INIT_ZVAL(value);
+						array_init(value);
+
+						add_assoc_string(value, "type", "octetstring", 1);
+						add_assoc_stringl(
+								value,
+								"value",
+								berval_value->bv_val,
+								berval_value->bv_len,
+								1);
+						add_assoc_long(value, "length", berval_value->bv_len);
+						
+						add_next_index_zval(array, value);
+						value = NULL;
+
+						ber_bvfree(berval_value);
+						char_value = NULL;
+					} else {
+						add_next_index_null(array);
+						error_count++;
+					}
+					break;
+				case LBER_NULL:
+					if( LBER_ERROR != ber_scanf(element, "n")) {
+						ALLOC_INIT_ZVAL(value);
+						array_init(value);
+
+						add_assoc_string(value, "type", "null", 1);
+						add_assoc_null(value, "value");
+
+						add_next_index_zval(array, value);
+						value = NULL;
+					} else {
+						add_next_index_null(array);
+						error_count++;
+					}
+					break;
+				case LBER_ENUMERATED:
+					if( LBER_ERROR != ber_scanf(element, "e", &int_value)) {
+						ALLOC_INIT_ZVAL(value);
+						array_init(value);
+
+						add_assoc_string(value, "type", "enumerated", 1);
+						add_assoc_long(value, "value", int_value);
+
+						add_next_index_zval(array, value);
+					} else {
+						add_next_index_null(array);
+						error_count++;
+					}
+					break;
+				/* Recursive call for sequence and set */
+				case LBER_SEQUENCE:
+				case LBER_SET:
+					if(LBER_SEQUENCE == ber_scanf(element, "}") ||
+							LBER_SET == ber_scanf(element, "]")) {
+						return error_count;
+					}
+
+					ALLOC_INIT_ZVAL(value);
+					array_init(value);
+					
+					if(tag == LBER_SEQUENCE) {
+						add_assoc_string(value, "type", "sequence", 1);
+					} else {
+						add_assoc_string(value, "type", "set", 1);
+					}
+
+					ALLOC_INIT_ZVAL(new);
+					array_init(new);
+					error_count+=_php_ber_to_array_recursive(element, new);
+					
+					add_assoc_zval(value, "value", new);
+
+					add_next_index_zval(array, value);
+					new = NULL;
+					break;
+				default: break;	
+			}
+
+		}
+	}
+	
+	return error_count;
+}
+/* }}}
+ */
+
+/* {{{ _php_ber_to_array
+   Convert 'struct berval' to an indexed array. Does some initialization then
+   call _php_ber_to_array_recursive.
+ */
+static int _php_ber_to_array(struct berval * ber, zval ** array) 
+{
+	int error_count = -1;
+	ber_tag_t tag = LBER_DEFAULT;
+	ber_len_t len = 0;
+	BerElement *element = NULL;
+	zval *new = NULL, *root = NULL;
+
+	if(array != NULL) {
+		if(	ber == NULL) {
+			*array=NULL;
+		} else {
+			element = ber_init(ber);
+			if(element == NULL) {
+				*array=NULL;
+			} else {
+				/* First ber element is either a set or a sequence but libler
+				   skips this firts one. We add it now. If it's not a sequence
+				   or a set, we add a sequence anyway.
+				   LBER_DEFAULT is returned if something's wrong.
+		 		 */
+				ALLOC_INIT_ZVAL(root);
+				array_init(root);
+
+				tag = ber_peek_tag(element, &len);
+				if(tag == LBER_SET) {
+					add_assoc_string(root, "type", "set", 1);
+				} else {
+					add_assoc_string(root, "type", "sequence", 1);
+				}
+				
+				ALLOC_INIT_ZVAL(new);
+				array_init(new);
+				error_count = _php_ber_to_array_recursive(element, new);
+				
+				add_assoc_zval(root, "value", new);
+
+				*array=root;
+				ber_memfree(element);
+				element = NULL;
+			}
+		}
+	}
+
+	return error_count;
+}
+/* }}}
+ */
+
+/* {{{ _php_ber_from_array_recursive
+ */
+static int _php_ber_from_array_recursive(HashTable * array, BerElement ** pelement) 
+{
+	zval **data = NULL, **type = NULL, **value = NULL, **length=NULL;
+	HashPosition p;
+	HashTable * sub = NULL;
+	int i = 0, error_count = 0;
+	BerElement * element = NULL;
+	ber_tag_t tag = LBER_DEFAULT;
+
+	if(pelement != NULL) {
+		element = *pelement;
+	} else {
+		return -1;
+	}
+
+	if(array != NULL && element != NULL) {
+		if(zend_hash_find(array, "type", sizeof("type"), (void **) &type) != FAILURE) {
+			if(zend_hash_find(array, "value", sizeof("value"), (void **) &value) != FAILURE) {
+				convert_to_string_ex(type);
+				if(strncmp(Z_STRVAL_PP(type), "null", Z_STRLEN_PP(type)) == 0) {
+					if(LBER_ERROR == ber_printf(element, "n")) {
+						error_count++;
+					}
+				} else if(strncmp(
+							Z_STRVAL_PP(type),
+							"boolean",
+							Z_STRLEN_PP(type))==0) {
+					convert_to_long_ex(value);
+					if(LBER_ERROR == ber_printf(
+								element,
+								"b",
+								(ber_int_t)Z_LVAL_PP(value) ? 1 : 0)) {
+						error_count++;
+					}
+				} else if(strncmp(
+							Z_STRVAL_PP(type),
+							"integer",
+							Z_STRLEN_PP(type))==0) {
+					convert_to_long_ex(value);
+					if(LBER_ERROR == ber_printf(
+								element,
+								"i",
+								(ber_int_t)Z_LVAL_PP(value))) {
+						error_count++;
+					}
+				} else if(strncmp(
+							Z_STRVAL_PP(type),
+							"bitstring",
+							Z_STRLEN_PP(type))==0) {
+					
+					convert_to_string_ex(value);
+					if(FAILURE != zend_hash_find(
+								array,
+								"length",
+								sizeof("length"), 
+								(void **) &length)) {
+						convert_to_long_ex(length);
+						
+						if(LBER_ERROR == ber_printf(
+									element,
+									"B",
+									Z_STRVAL_PP(value),
+									(ber_len_t)Z_LVAL_PP(length))) {
+							error_count++;
+						}
+					} else {
+						if(LBER_ERROR == ber_printf(
+									element,
+									"B",
+									Z_STRVAL_PP(value),
+									/* bistrings require number of _bits_ */
+									(ber_len_t)(Z_STRLEN_PP(value) * 8))) {
+							error_count++;
+						}
+					}
+				} else if(strncmp(
+							Z_STRVAL_PP(type),
+							"octetstring",
+							Z_STRLEN_PP(type))==0) {
+					convert_to_string_ex(value);
+					
+					if(FAILURE != zend_hash_find(
+								array,
+								"length",
+								sizeof("length"), 
+								(void **) &length)) {
+						convert_to_long_ex(length);
+
+						if(LBER_ERROR == ber_printf(
+									element,
+									"o",
+									Z_STRVAL_PP(value),
+									(ber_len_t)Z_LVAL_PP(length))) {
+							error_count++;
+						}
+					} else {
+						if(LBER_ERROR == ber_printf(
+									element,
+									"o",
+									Z_STRVAL_PP(value),
+									(ber_len_t)Z_STRLEN_PP(value))) {
+							error_count++;
+						}
+					}
+				} else if(strncmp(
+							Z_STRVAL_PP(type),
+							"enumerated",
+							Z_STRLEN_PP(type)) == 0) {
+					convert_to_long_ex(value);
+					if(LBER_ERROR == ber_printf(
+								element,
+								"e",
+								(ber_int_t)Z_LVAL_PP(value))) {
+						error_count++;
+					}
+				} else if(
+						(strncmp(Z_STRVAL_PP(type), "sequence", Z_STRLEN_PP(type)) == 0) ||
+						(strncmp(Z_STRVAL_PP(type), "set", Z_STRLEN_PP(type)) == 0)) {
+					if(Z_TYPE_PP(value) == IS_ARRAY) {
+						if(strncmp(Z_STRVAL_PP(type), "set", Z_STRLEN_PP(type)) == 0) {
+							tag = ber_printf(element, "[");
+						} else {
+							tag = ber_printf(element, "{");
+						}
+						if(LBER_ERROR != tag) {
+							for(
+									zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(value), &p);
+									zend_hash_get_current_data_ex(Z_ARRVAL_PP(value), (void **) &data, &p) == SUCCESS;
+									zend_hash_move_forward_ex(Z_ARRVAL_PP(value), &p)) {
+								if(Z_TYPE_PP(data) == IS_ARRAY) {
+									sub = Z_ARRVAL_PP(data);
+									error_count+=_php_ber_from_array_recursive(
+											sub,
+											&element);
+								}
+							}
+							
+							if(strncmp(Z_STRVAL_PP(type), "set", Z_STRLEN_PP(type)) == 0) {
+								tag = ber_printf(element, "]");
+							} else {
+								tag = ber_printf(element, "}");
+							}
+							if(LBER_ERROR == tag) {
+								error_count++;
+							}
+						} else {
+							error_count++;
+						}
+					} else {
+						error_count++;
+					}
+				} else {
+					error_count++;
+				}
+			} else {
+				error_count++;
+			}
+		} else {
+			error_count++;
+		}
+	}
+	*pelement = element;
+
+	return error_count;
+}
+/* }}}
+ */
+
+/* {{{ _php_ber_from_array
+ */
+static int _php_ber_from_array(HashTable * array, struct berval ** ber)
+{
+	BerElement * new = NULL;
+	int error_count = -1;
+	
+	if(array != NULL && ber != NULL) {
+		new = ber_alloc_t(LBER_USE_DER);
+		
+		error_count=_php_ber_from_array_recursive(array, &new);
+
+		if(error_count == 0) {
+			if(LBER_ERROR == ber_flatten(new, ber)) {
+				*ber = NULL;
+			}
+		} else {
+			*ber = NULL;
+		}
+
+		ber_memfree(new);
+	}
+	return error_count;
+}
+/* }}}
+ */
+
+
+
+
 /* {{{ PHP_INI_BEGIN
  */
 PHP_INI_BEGIN()
@@ -546,6 +977,10 @@ PHP_FUNCTION(ldap_unbind)
 
 /* {{{ php_set_opts
  */
+#if LDAP_API_VERSION > 2000
+static void php_set_opts(LDAP *ldap, int timelimit, int deref, int *old_timelimit, int *old_deref)
+{
+#else
 static void php_set_opts(LDAP *ldap, int sizelimit, int timelimit, int deref, int *old_sizelimit, int *old_timelimit, int *old_deref)
 {
 	/* sizelimit */
@@ -558,7 +993,7 @@ static void php_set_opts(LDAP *ldap, int sizelimit, int timelimit, int deref, in
 		ldap->ld_sizelimit = sizelimit; 
 #endif
 	}
-
+#endif
 	/* timelimit */
 	if (timelimit > -1) {
 #if (LDAP_API_VERSION >= 2004) || HAVE_NSLDAP || HAVE_ORALDAP_10
@@ -592,6 +1027,9 @@ static void php_ldap_do_search(INTERNAL_FUNCTION_PARAMETERS, int scope)
 	char *ldap_base_dn = NULL, *ldap_filter = NULL, **ldap_attrs = NULL; 
 	ldap_linkdata *ld = NULL;
 	LDAPMessage *ldap_res;
+#if LDAP_API_VERSION > 2000
+	LDAPControl **clientctrl = NULL, ** serverctrl = NULL;
+#endif
 	int ldap_attrsonly = 0, ldap_sizelimit = -1, ldap_timelimit = -1, ldap_deref = -1;	 
 	int old_ldap_sizelimit = -1, old_ldap_timelimit = -1, old_ldap_deref = -1;	 
 	int num_attribs = 0, ret = 1, i, errno, argcount = ZEND_NUM_ARGS();
@@ -706,11 +1144,46 @@ static void php_ldap_do_search(INTERNAL_FUNCTION_PARAMETERS, int scope)
 				ldap_filter = Z_STRVAL_PP(entry);
 			}
 
-			php_set_opts(ld->link, ldap_sizelimit, ldap_timelimit, ldap_deref, &old_ldap_sizelimit, &old_ldap_timelimit, &old_ldap_deref);
+#if LDAP_API_VERSION > 2000
+			php_set_opts(ld->link, ldap_timelimit, ldap_deref, &old_ldap_timelimit, &old_ldap_deref);
+			/* Fill controls.
+			   Discouraged by documentation but there's no way to pass 
+			   controls yet. Better than nothing
+			 */
+			if(LDAP_OPT_SUCCESS != ldap_get_option(
+						ld->link,
+						LDAP_OPT_CLIENT_CONTROLS,
+						&clientctrl)) {
+				clientctrl = NULL;
+			}
+			if(LDAP_OPT_SUCCESS != ldap_get_option(
+						ld->link,
+						LDAP_OPT_SERVER_CONTROLS,
+						&serverctrl)) {
+				serverctrl = NULL;
+			}
 
 			/* Run the actual search */	
+			if(LDAP_OPT_SUCCESS != ldap_search_ext(
+					ld->link,
+					ldap_base_dn,
+					scope,
+					ldap_filter,
+					ldap_attrs,
+					ldap_attrsonly,
+					serverctrl,
+					clientctrl,
+					NULL, /* timeval not defined, see ldap.h */
+					ldap_sizelimit,
+					&(rcs[i]))) {
+				rcs[i] = -1;
+			}
+#else
+			php_set_opts(ld->link, ldap_sizelimit, ldap_timelimit, ldap_deref, &old_ldap_sizelimit, &old_ldap_timelimit, &old_ldap_deref);
 			rcs[i] = ldap_search(ld->link, ldap_base_dn, scope, ldap_filter, ldap_attrs, ldap_attrsonly);
+#endif
 			lds[i] = ld;
+			
 			zend_hash_move_forward(Z_ARRVAL_P(link));
 		}
 		
@@ -748,11 +1221,44 @@ cleanup_parallel:
 			goto cleanup;
 		}
 
-		php_set_opts(ld->link, ldap_sizelimit, ldap_timelimit, ldap_deref, &old_ldap_sizelimit, &old_ldap_timelimit, &old_ldap_deref);
+#if LDAP_API_VERSION > 2000
+		php_set_opts(ld->link, ldap_timelimit, ldap_deref, &old_ldap_timelimit, &old_ldap_deref);
+
+		/* Fill controls.
+		   Discouraged by documentation but there's no way to pass 
+		   controls yet. Better than nothing
+		 */
+		if(LDAP_OPT_SUCCESS != ldap_get_option(
+					ld->link,
+					LDAP_OPT_CLIENT_CONTROLS,
+					&clientctrl)) {
+			clientctrl = NULL;
+		}
+		if(LDAP_OPT_SUCCESS != ldap_get_option(
+					ld->link,
+					LDAP_OPT_SERVER_CONTROLS,
+					&serverctrl)) {
+			serverctrl = NULL;
+		}
 
 		/* Run the actual search */	
+		errno = ldap_search_ext_s(
+				ld->link,
+				ldap_base_dn,
+				scope,
+				ldap_filter,
+				ldap_attrs,
+				ldap_attrsonly,
+				serverctrl,
+				clientctrl,
+				NULL, /* timeval not defined, see ldap.h */
+				ldap_sizelimit,
+				&ldap_res);
+#else
+		php_set_opts(ld->link, ldap_sizelimit, ldap_timelimit, ldap_deref, &old_ldap_sizelimit, &old_ldap_timelimit, &old_ldap_deref);
 		errno = ldap_search_s(ld->link, ldap_base_dn, scope, ldap_filter, ldap_attrs, ldap_attrsonly, &ldap_res);
-	
+#endif
+
 		if (errno != LDAP_SUCCESS
 			&& errno != LDAP_SIZELIMIT_EXCEEDED
 #ifdef LDAP_ADMINLIMIT_EXCEEDED
@@ -779,10 +1285,27 @@ cleanup_parallel:
 	}
 
 cleanup:
+#if LDAP_API_VERSION > 2000
+	/* Free controls */
+	if(clientctrl != NULL) {
+		ldap_controls_free(clientctrl);
+		clientctrl = NULL;
+	}
+	if(serverctrl != NULL) {
+		ldap_controls_free(serverctrl);
+		serverctrl = NULL;
+	}
+
+	/* Restoring previous options */
+	if (ld) {
+		php_set_opts(ld->link, old_ldap_timelimit, old_ldap_deref, &ldap_timelimit, &ldap_deref);
+	}
+#else
 	if (ld) {
-		/* Restoring previous options */
 		php_set_opts(ld->link, old_ldap_sizelimit, old_ldap_timelimit, old_ldap_deref, &ldap_sizelimit, &ldap_timelimit, &ldap_deref);
 	}
+#endif
+
 	if (ldap_attrs != NULL) {
 		efree(ldap_attrs);
 	}
@@ -1261,6 +1784,9 @@ static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper)
 	ldap_linkdata *ld;
 	char *dn;
 	LDAPMod **ldap_mods;
+#if LDAP_API_VERSION > 2000
+	LDAPControl **clientctrl = NULL, **serverctrl = NULL;
+#endif
 	int i, j, num_attribs, num_values, dn_len;
 	int *num_berval;
 	char *attribute;
@@ -1344,20 +1870,49 @@ static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper)
 	}
 	ldap_mods[num_attribs] = NULL;
 
+#if LDAP_API_VERSION > 2000
+	if(LDAP_OPT_SUCCESS != ldap_get_option(ld->link, LDAP_OPT_CLIENT_CONTROLS, &clientctrl)) {
+		clientctrl = NULL;
+	}
+	if(LDAP_OPT_SUCCESS != ldap_get_option(ld->link, LDAP_OPT_SERVER_CONTROLS, &serverctrl)) {
+		serverctrl = NULL;
+	}
+#endif
+
 /* check flag to see if do_mod was called to perform full add , gerrit thomson */
 	if (is_full_add == 1) {
+#if LDAP_API_VERSION > 2000
+		if ((i = ldap_add_ext_s(ld->link, dn, ldap_mods, serverctrl, clientctrl)) != LDAP_SUCCESS) {
+#else
 		if ((i = ldap_add_s(ld->link, dn, ldap_mods)) != LDAP_SUCCESS) {
+#endif
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Add: %s", ldap_err2string(i));
 			RETVAL_FALSE;
 		} else RETVAL_TRUE;
 	} else {
-		if ((i = ldap_modify_ext_s(ld->link, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
+#if LDAP_API_VERSION > 2000
+		if ((i = ldap_modify_ext_s(ld->link, dn, ldap_mods, serverctrl, clientctrl)) != LDAP_SUCCESS) {
+#else
+		if ((i = ldap_modify_s(ld->link, dn, ldap_mods)) != LDAP_SUCCESS) {
+#endif
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Modify: %s", ldap_err2string(i));
 			RETVAL_FALSE;
 		} else RETVAL_TRUE;	
 	}
 
 errexit:
+
+#if LDAP_API_VERSION > 2000
+	if(serverctrl != NULL) {
+		ldap_controls_free(serverctrl);
+		serverctrl = NULL;
+	}
+	if(clientctrl != NULL) {
+		ldap_controls_free(clientctrl);
+		clientctrl = NULL;
+	}
+#endif
+
 	for (i = 0; i < num_attribs; i++) {
 		efree(ldap_mods[i]->mod_type);
 		for (j = 0; j < num_berval[i]; j++) {
@@ -1659,7 +2214,10 @@ PHP_FUNCTION(ldap_set_option)
 	ldap_linkdata *ld;
 	LDAP *ldap;
 	long option;
-	
+	struct berval * control_value = NULL;
+	int control_iscritical = 0;
+	char * control_oid = NULL;
+
 	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zlZ", &link, &option, &newval) != SUCCESS) {
 		return;
 	}
@@ -1778,37 +2336,55 @@ PHP_FUNCTION(ldap_set_option)
 					error = 1;
 					break;
 				}
-				ctrl = *ctrlp = emalloc(sizeof(**ctrlp));
+				
 				convert_to_string_ex(val);
-				ctrl->ldctl_oid = Z_STRVAL_PP(val);
+				control_oid = Z_STRVAL_PP(val);
 				if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "value", sizeof("value"), (void **) &val) == SUCCESS) {
-					convert_to_string_ex(val);
-					ctrl->ldctl_value.bv_val = Z_STRVAL_PP(val);
-					ctrl->ldctl_value.bv_len = Z_STRLEN_PP(val);
+					if(Z_TYPE_PP(val) != IS_ARRAY) {
+						convert_to_string_ex(val);
+						control_value = ber_memalloc(sizeof * control_value);
+						if(control_value != NULL) {
+							control_value->bv_val = Z_STRVAL_PP(val);
+							control_value->bv_len = Z_STRLEN_PP(val);
+						}
+					} else {
+						if(_php_ber_from_array(Z_ARRVAL_PP(val), &control_value) != 0) {
+							if(control_value != NULL) {
+								ber_memfree(control_value);
+								control_value = NULL;				
+							}
+						}
+					}
 				} else {
-					ctrl->ldctl_value.bv_val = NULL;
-					ctrl->ldctl_value.bv_len = 0;
+					control_value = NULL;
 				}
 				if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "iscritical", sizeof("iscritical"), (void **) &val) == SUCCESS) {
 					convert_to_boolean_ex(val);
-					ctrl->ldctl_iscritical = Z_BVAL_PP(val);
+					control_iscritical = Z_BVAL_PP(val);
 				} else {
-					ctrl->ldctl_iscritical = 0;
+					control_iscritical = 0;
 				}
 				
-				++ctrlp;
+				if((ctrl = ldu_ldap_control_create(control_oid,
+								control_iscritical, control_value)) != NULL) {
+					*ctrlp = ctrl;
+					++ctrlp;
+				}
+
+				if(control_value != NULL) {
+					ber_memfree(control_value);
+					control_value = NULL;
+				}
+
 				*ctrlp = NULL;
 				zend_hash_move_forward(Z_ARRVAL_PP(newval));
 			}
 			if (!error) {
 				error = ldap_set_option(ldap, option, ctrls);
 			}
-			ctrlp = ctrls;
-			while (*ctrlp) {
-				efree(*ctrlp);
-				ctrlp++;
-			}
-			efree(ctrls);
+
+			ldu_ldap_controls_free(ctrls);
+			
 			if (error) {
 				RETURN_FALSE;
 			}
@@ -1821,18 +2397,19 @@ PHP_FUNCTION(ldap_set_option)
 /* }}} */
 
 #ifdef HAVE_LDAP_PARSE_RESULT
-/* {{{ proto bool ldap_parse_result(resource link, resource result, int errcode, string matcheddn, string errmsg, array referrals)
+/* {{{ proto bool ldap_parse_result(resource link, resource result, int errcode, string matcheddn, string errmsg, array referrals, array serverctrls)
    Extract information from result */
 PHP_FUNCTION(ldap_parse_result) 
 {
-	zval *link, *result, *errcode, *matcheddn, *errmsg, *referrals;
+	zval *link, *result, *errcode, *matcheddn, *errmsg, *referrals, *serverctrls, *ctrl, *php_ber;
 	ldap_linkdata *ld;
 	LDAPMessage *ldap_result;
+	LDAPControl **lserverctrls = NULL, **ctrlp = NULL;
 	char **lreferrals, **refp;
 	char *lmatcheddn, *lerrmsg;
-	int rc, lerrcode, myargcount = ZEND_NUM_ARGS();
+	int rc, lerrcode, myargcount = ZEND_NUM_ARGS(), ber_decode_error_count = -1;
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz|zzz", &link, &result, &errcode, &matcheddn, &errmsg, &referrals) != SUCCESS) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz|zzzz", &link, &result, &errcode, &matcheddn, &errmsg, &referrals, &serverctrls) != SUCCESS) {
 		return; 
 	}
 
@@ -1843,7 +2420,7 @@ PHP_FUNCTION(ldap_parse_result)
 				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));
@@ -1855,6 +2432,40 @@ PHP_FUNCTION(ldap_parse_result)
 
 	/* Reverse -> fall through */
 	switch (myargcount) {
+		case 7:
+			zval_dtor(serverctrls);
+			array_init(serverctrls);
+			if(lserverctrls != NULL) {
+				ctrlp = lserverctrls;
+				while (*ctrlp) {
+					ALLOC_INIT_ZVAL(ctrl);
+					array_init(ctrl);
+
+					add_assoc_bool(
+							ctrl,
+							"critical",
+							(*ctrlp)->ldctl_iscritical ? 1 : 0);
+
+					php_ber = NULL;
+					ber_decode_error_count = _php_ber_to_array(
+							&((*ctrlp)->ldctl_value), 
+							&php_ber);
+					if(php_ber != NULL) {
+						add_assoc_zval(ctrl, "value", php_ber);
+					} else {
+						add_assoc_null(ctrl, "value");
+					}
+					add_assoc_long(
+							ctrl,
+							"ber_error_count",
+							ber_decode_error_count);
+					add_assoc_string(ctrl, "oid", (*ctrlp)->ldctl_oid, 1);	
+
+					add_next_index_zval(serverctrls, ctrl);
+					ctrlp++;
+				}
+				ldap_controls_free(lserverctrls);
+			}
 		case 6:
 			zval_dtor(referrals);
 			array_init(referrals);
@@ -2614,6 +3225,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_parse_result, 0, 0, 3)
 	ZEND_ARG_INFO(1, matcheddn)
 	ZEND_ARG_INFO(1, errmsg)
 	ZEND_ARG_INFO(1, referrals)
+	ZEND_ARG_INFO(1, serverctrls)
 ZEND_END_ARG_INFO()
 #endif
 #endif
-- 
1.7.10.4


From ad7abb214011c638eefa29b40afa961aabd25b43 Mon Sep 17 00:00:00 2001
From: Etienne Bagnoud <tchetch@i-james.com>
Date: Sun, 24 Feb 2013 18:03:16 +0100
Subject: [PATCH 3/3] Added licence text

---
 ext/ldap/ldap_dev_utils.c |   17 +++++++++++++++++
 ext/ldap/ldap_dev_utils.h |   17 +++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/ext/ldap/ldap_dev_utils.c b/ext/ldap/ldap_dev_utils.c
index 0a8d109..78dcb34 100644
--- a/ext/ldap/ldap_dev_utils.c
+++ b/ext/ldap/ldap_dev_utils.c
@@ -1,3 +1,20 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2013 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Etienne Bagnoud      <etienne@lamaisondebarbie.ch>          | 
+   +----------------------------------------------------------------------+
+ */ 
 #include <string.h>
 #include "ldap_dev_utils.h"
 
diff --git a/ext/ldap/ldap_dev_utils.h b/ext/ldap/ldap_dev_utils.h
index 2591698..d24ca7f 100644
--- a/ext/ldap/ldap_dev_utils.h
+++ b/ext/ldap/ldap_dev_utils.h
@@ -1,3 +1,20 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2013 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Etienne Bagnoud      <etienne@lamaisondebarbie.ch>          | 
+   +----------------------------------------------------------------------+
+ */
 #ifndef LDAP_DEV_UTILS_H__
 #define LDAP_DEV_UTILS_H__
 
-- 
1.7.10.4

 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 21:01:28 2024 UTC