summaryrefslogtreecommitdiff
path: root/databases/php-ldap
diff options
context:
space:
mode:
authormanu <manu>2015-04-13 08:04:17 +0000
committermanu <manu>2015-04-13 08:04:17 +0000
commit2f2e9f7eef587224b0478c72e1e5fdbed6e7c118 (patch)
treeefcfa7959cc49d802b08dd8ccc3bb8f336a03a82 /databases/php-ldap
parent2587053e8dc8224a6c147b43446bd08cc2e23f40 (diff)
downloadpkgsrc-2f2e9f7eef587224b0478c72e1e5fdbed6e7c118.tar.gz
Update the LDAP EXOP support patch for PHP 5.4, 5.5 and 5.6
Diffstat (limited to 'databases/php-ldap')
-rw-r--r--databases/php-ldap/files/ldap-ctrl-exop54.patch2260
-rw-r--r--[-rwxr-xr-x]databases/php-ldap/files/ldap-ctrl-exop55.patch (renamed from databases/php-ldap/files/ldap-ctrl-exop.patch)222
-rw-r--r--databases/php-ldap/files/ldap-ctrl-exop56.patch2263
-rw-r--r--databases/php-ldap/options.mk4
4 files changed, 4636 insertions, 113 deletions
diff --git a/databases/php-ldap/files/ldap-ctrl-exop54.patch b/databases/php-ldap/files/ldap-ctrl-exop54.patch
new file mode 100644
index 00000000000..ca351702540
--- /dev/null
+++ b/databases/php-ldap/files/ldap-ctrl-exop54.patch
@@ -0,0 +1,2260 @@
+--- ext/ldap/ldap.c.orig 2015-03-18 06:33:59.000000000 +0100
++++ ext/ldap/ldap.c 2015-04-13 05:57:02.000000000 +0200
+@@ -66,8 +66,13 @@
+ #elif defined(HAVE_LDAP_SASL_SASL_H)
+ #include <sasl/sasl.h>
+ #endif
+
++/* XXX Not detected by configure... */
++#ifdef LDAP_EXOP_REFRESH
++#define HAVE_LDAP_REFRESH 1
++#endif
++
+ typedef struct {
+ LDAP *link;
+ #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
+ zval *rebindproc;
+@@ -88,31 +93,46 @@
+ #ifdef COMPILE_DL_LDAP
+ ZEND_GET_MODULE(ldap)
+ #endif
+
++
++/* {{{ proto void _close_ldap_link()
++ close a connection and free LDAP resources */
+ static void _close_ldap_link(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
+ {
+ ldap_linkdata *ld = (ldap_linkdata *)rsrc->ptr;
+
+- ldap_unbind_s(ld->link);
+-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
++ /* ldap_unbind_s() is deprecated;
++ * the distinction between ldap_unbind() and ldap_unbind_s() is moot */
++#ifdef LDAP_API_FEATURE_X_OPENLDAP
++ ldap_unbind_ext(ld->link, NULL, NULL);
++#ifdef HAVE_3ARG_SETREBINDPROC
++
+ if (ld->rebindproc != NULL) {
+ zval_dtor(ld->rebindproc);
+ FREE_ZVAL(ld->rebindproc);
+ }
+ #endif
++#else /* ! LDAP_API_FEATURE_X_OPENLDAP */
++ ldap_unbind_s(ld->link);
++#endif /* ! LDAP_API_FEATURE_X_OPENLDAP */
++
+ efree(ld);
+ LDAPG(num_links)--;
+ }
+ /* }}} */
+
++/* {{{ proto void _free_ldap_result()
++ free the result of an LDAP operation */
+ static void _free_ldap_result(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
+ {
+ LDAPMessage *result = (LDAPMessage *)rsrc->ptr;
+ ldap_msgfree(result);
+ }
+ /* }}} */
+
++/* {{{ proto void _free_ldap_result_entry()
++ free an entry resulting from an LDAP search operation */
+ static void _free_ldap_result_entry(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
+ {
+ ldap_resultentry *entry = (ldap_resultentry *)rsrc->ptr;
+
+@@ -203,8 +223,21 @@
+ REGISTER_LONG_CONSTANT("GSLC_SSL_ONEWAY_AUTH", GSLC_SSL_ONEWAY_AUTH, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GSLC_SSL_TWOWAY_AUTH", GSLC_SSL_TWOWAY_AUTH, CONST_PERSISTENT | CONST_CS);
+ #endif
+
++#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
++ REGISTER_LONG_CONSTANT("PP_passwordExpired", PP_passwordExpired, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_accountLocked", PP_accountLocked, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_changeAfterReset", PP_changeAfterReset, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_passwordModNotAllowed", PP_passwordModNotAllowed, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_mustSupplyOldPassword", PP_mustSupplyOldPassword, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_insufficientPasswordQuality", PP_insufficientPasswordQuality, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_passwordTooShort", PP_passwordTooShort, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_passwordTooYoung", PP_passwordTooYoung, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_passwordInHistory", PP_passwordInHistory, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_noError", PP_noError, CONST_PERSISTENT | CONST_CS);
++#endif /* LDAP_CONTROL_PASSWORDPOLICYREQUEST */
++
+ le_link = zend_register_list_destructors_ex(_close_ldap_link, NULL, "ldap link", module_number);
+ le_result = zend_register_list_destructors_ex(_free_ldap_result, NULL, "ldap result", module_number);
+ le_result_entry = zend_register_list_destructors_ex(_free_ldap_result_entry, NULL, "ldap result entry", module_number);
+
+@@ -285,15 +318,176 @@
+ DISPLAY_INI_ENTRIES();
+ }
+ /* }}} */
+
++
++/* {{{ proto int _php_parse_referrals_resp()
++ parse an array of LDAP referrals into a zval array */
++static int _php_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;
++ }
++
++ return num_referrals;
++}
++/* }}} */
++
++/* {{{ proto int _php_parse_controls()
++ parse an array of zvals into an array of LDAP controls */
++static int _php_parse_controls(zval **ctrls, LDAPControl ***lctrlsp)
++{
++ LDAPControl *lctrl, **lctrls, **lctrlp;
++ zval **ctrlval, **val;
++ int ncontrols;
++ char error = 0;
++
++
++ if ((Z_TYPE_PP(ctrls) != IS_ARRAY) || !(ncontrols = zend_hash_num_elements(Z_ARRVAL_PP(ctrls)))) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected non-empty array value");
++ return 0;
++ }
++
++ lctrls = safe_emalloc((1 + ncontrols), sizeof(*lctrls), 0);
++ *lctrls = NULL;
++ lctrlp = lctrls;
++ zend_hash_internal_pointer_reset(Z_ARRVAL_PP(ctrls));
++ while (zend_hash_get_current_data(Z_ARRVAL_PP(ctrls), (void**)&ctrlval) == SUCCESS) {
++ if (Z_TYPE_PP(ctrlval) != IS_ARRAY) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The array value must contain only arrays, where each array is a control");
++ error = 1;
++ break;
++ }
++ if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "oid", sizeof("oid"), (void **) &val) == FAILURE) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Control must have an oid key");
++ error = 1;
++ break;
++ }
++ lctrl = *lctrlp = emalloc(sizeof(**lctrlp));
++ convert_to_string_ex(val);
++ lctrl->ldctl_oid = Z_STRVAL_PP(val);
++ if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "value", sizeof("value"), (void **) &val) == SUCCESS) {
++ convert_to_string_ex(val);
++ lctrl->ldctl_value.bv_val = Z_STRVAL_PP(val);
++ lctrl->ldctl_value.bv_len = Z_STRLEN_PP(val);
++ } else {
++ lctrl->ldctl_value.bv_val = NULL;
++ lctrl->ldctl_value.bv_len = 0;
++ }
++ if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "iscritical", sizeof("iscritical"), (void **) &val) == SUCCESS) {
++ convert_to_boolean_ex(val);
++ lctrl->ldctl_iscritical = Z_BVAL_PP(val);
++ } else {
++ lctrl->ldctl_iscritical = 0;
++ }
++
++ ++lctrlp;
++ *lctrlp = NULL;
++ zend_hash_move_forward(Z_ARRVAL_PP(ctrls));
++ }
++ if (!error) {
++ *lctrlsp = lctrls;
++ }
++ return ncontrols;
++}
++/* }}} */
++
++/* {{{ proto void _php_free_controls()
++ frees an array of LDAP controls as parsed (and malloc'ed) by _php_parse_controls */
++static void _php_free_controls(LDAPControl ***lctrlsp)
++{
++ LDAPControl **lctrlp;
++
++ for (lctrlp = *lctrlsp; *lctrlp; lctrlp++) {
++ efree(*lctrlp);
++ }
++ efree(*lctrlsp);
++ *lctrlsp = NULL;
++}
++/* }}} */
++
++/* {{{ proto void _php_parse_controls_resp()
++ parse an array of LDAP controls into a zval array */
++static int _php_parse_controls_resp(LDAPControl ***lctrlsp, zval **ctrls)
++{
++ int num_ctrls = 0;
++
++ if (*lctrlsp != NULL) {
++ int error = 0;
++ LDAPControl **ctrlp = *lctrlsp;
++
++ 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);
++ }
++
++ /* As per <draft-ietf-ldapbis-protocol>:
++ *
++ * 4.1.11
++
++ The criticality field only has meaning in controls attached to
++ request messages (except UnbindRequest). For controls attached to
++ response messages and the UnbindRequest, the criticality field SHOULD
++ be FALSE, and MUST be ignored by the receiving protocol peer.
++
++ */
++
++ add_next_index_zval(*ctrls, ctrlval);
++
++ num_ctrls++;
++ ctrlp++;
++ }
++ ldap_controls_free(*lctrlsp);
++ *lctrlsp = NULL;
++
++ if (error) {
++ /* ... */
++ return -1;
++ }
++ }
++
++ return num_ctrls;
++}
++/* }}} */
++
+ /* {{{ proto resource ldap_connect([string host [, int port [, string wallet [, string wallet_passwd [, int authmode]]]]])
+ Connect to an LDAP server */
+ PHP_FUNCTION(ldap_connect)
+ {
+ char *host = NULL;
+ int hostlen;
+- long port = 389; /* Default port */
++ int port =
++#ifdef LDAP_API_FEATURE_X_OPENLDAP
++ LDAP_PORT
++#else /* ! LDAP_API_FEATURE_X_OPENLDAP */
++ 389 /* Default port */
++#endif /* ! LDAP_API_FEATURE_X_OPENLDAP */
++ ;
+ #ifdef HAVE_ORALDAP
+ char *wallet = NULL, *walletpasswd = NULL;
+ int walletlen = 0, walletpasswdlen = 0;
+ long authmode = GSLC_SSL_NO_AUTH;
+@@ -327,23 +521,41 @@
+
+ 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;
++ * ldap_init()/ldap_open() is deprecated, use ldap_initialize() instead.
++ */
++ {
++ 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:%d", host ? host : "", 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
++#else /* ! LDAP_API_FEATURE_X_OPENLDAP */
+ ldap = ldap_open(host, port);
+-#endif
++#endif /* ! LDAP_API_FEATURE_X_OPENLDAP */
+
+ if (ldap == NULL) {
+ efree(ld);
+ RETURN_FALSE;
+@@ -429,17 +641,33 @@
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Password contains a null byte");
+ RETURN_FALSE;
+ }
+
+- 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 {
+ RETURN_TRUE;
+ }
+ }
+ /* }}} */
+
++/* {{{ SASL bind stuff */
+ #ifdef HAVE_LDAP_SASL
+ typedef struct {
+ char *mech;
+ char *realm;
+@@ -562,8 +790,9 @@
+ _php_sasl_freedefs(ctx);
+ }
+ /* }}} */
+ #endif /* HAVE_LDAP_SASL */
++/* }}} */
+
+ /* {{{ proto bool ldap_unbind(resource link)
+ Unbind from LDAP directory */
+ PHP_FUNCTION(ldap_unbind)
+@@ -1259,9 +1488,14 @@
+ for (i = 0; i<count; i++) {
+ add_index_string(return_value, i, ldap_value[i], 1);
+ }
+
++#ifdef LDAP_API_FEATURE_X_OPENLDAP
++ /* ldap_value_free() is deprecated */
++ ber_memvfree((void **)ldap_value);
++#else /* ! LDAP_API_FEATURE_X_OPENLDAP */
+ ldap_value_free(ldap_value);
++#endif /* ! LDAP_API_FEATURE_X_OPENLDAP */
+ }
+ /* }}} */
+
+ /* {{{ proto string ldap_dn2ufn(string dn)
+@@ -1292,38 +1526,67 @@
+ /* added to fix use of ldap_modify_add for doing an ldap_add, gerrit thomson. */
+ #define PHP_LD_FULL_ADD 0xff
+ /* {{{ php_ldap_do_modify
+ */
+-static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper)
++static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper, int ext)
+ {
+- zval *link, *entry, **value, **ivalue;
++ zval *link, *entry, **value, **ivalue, **sctrls, **cctrls;
+ ldap_linkdata *ld;
+ char *dn;
+ LDAPMod **ldap_mods;
+ int i, j, num_attribs, num_values, dn_len;
+ int *num_berval;
+ char *attribute;
+ ulong index;
+ int is_full_add=0; /* flag for full add operation so ldap_mod_add can be put back into oper, gerrit THomson */
++ int rc, msgid, myargcount = ZEND_NUM_ARGS();
++ LDAPMessage *ldap_res;
++ LDAPControl **lsctrls = NULL, **lcctrls = NULL;
++ if (ext) {
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsaZZ", &link, &dn, &dn_len, &entry, &sctrls, &cctrls) != SUCCESS)
++ WRONG_PARAM_COUNT;
++ } else {
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa", &link, &dn, &dn_len, &entry) != SUCCESS)
++ WRONG_PARAM_COUNT;
++ }
+
+- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa", &link, &dn, &dn_len, &entry) != SUCCESS) {
+- return;
+- }
++ if (Z_TYPE_PP(&entry) != IS_ARRAY) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected Array as the last element");
++ RETURN_FALSE;
++ }
+
+- ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
+
+- num_attribs = zend_hash_num_elements(Z_ARRVAL_P(entry));
+- ldap_mods = safe_emalloc((num_attribs+1), sizeof(LDAPMod *), 0);
+- num_berval = safe_emalloc(num_attribs, sizeof(int), 0);
+- zend_hash_internal_pointer_reset(Z_ARRVAL_P(entry));
+
+ /* added by gerrit thomson to fix ldap_add using ldap_mod_add */
+ if (oper == PHP_LD_FULL_ADD) {
+ oper = LDAP_MOD_ADD;
+ is_full_add = 1;
+ }
+ /* end additional , gerrit thomson */
+
++ if (myargcount > 3) {
++ if (is_full_add) {
++#ifndef HAVE_LDAP_ADD_EXT_S
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "ldap_add_ext not available");
++ RETURN_FALSE;
++#endif /* ! HAVE_LDAP_ADD_EXT_S */
++
++ } else {
++#ifndef HAVE_LDAP_MODIFY_EXT_S
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "ldap_modify_ext not available");
++ RETURN_FALSE;
++#endif /* ! HAVE_LDAP_MODIFY_EXT_S */
++ }
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
++
++ num_attribs = zend_hash_num_elements(Z_ARRVAL_P(entry));
++ ldap_mods = safe_emalloc((num_attribs+1), sizeof(LDAPMod *), 0);
++ num_berval = safe_emalloc(num_attribs, sizeof(int), 0);
++ zend_hash_internal_pointer_reset(Z_ARRVAL_P(entry));
++
++
+ for (i = 0; i < num_attribs; i++) {
+ ldap_mods[i] = emalloc(sizeof(LDAPMod));
+ ldap_mods[i]->mod_op = oper | LDAP_MOD_BVALUES;
+ ldap_mods[i]->mod_type = NULL;
+@@ -1381,19 +1644,78 @@
+ zend_hash_move_forward(Z_ARRVAL_P(entry));
+ }
+ ldap_mods[num_attribs] = NULL;
+
++ if (ext) {
++ switch (myargcount) {
++ case 5:
++ if (_php_parse_controls(cctrls, &lcctrls) == 0) {
++ RETVAL_FALSE;
++ goto errexit;
++ }
++
++ case 4:
++ if (_php_parse_controls(sctrls, &lsctrls) == 0) {
++ RETVAL_FALSE;
++ goto errexit;
++ }
++ }
++ }
++
+ /* check flag to see if do_mod was called to perform full add , gerrit thomson */
+ if (is_full_add == 1) {
+- if ((i = ldap_add_s(ld->link, dn, ldap_mods)) != LDAP_SUCCESS) {
+- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Add: %s", ldap_err2string(i));
+- RETVAL_FALSE;
+- } else RETVAL_TRUE;
++#ifdef HAVE_LDAP_ADD_EXT_S
++ if (ext) {
++ rc = ldap_add_ext(ld->link, dn, ldap_mods, lsctrls, lcctrls, &msgid);
++
++ } else {
++ rc = ldap_add_ext_s(ld->link, dn, ldap_mods, NULL, NULL);
++ }
++#else /* ! HAVE_LDAP_ADD_EXT_S */
++ rc = ldap_add_s(ld->link, dn, ldap_mods);
++#endif /* ! HAVE_LDAP_ADD_EXT_S */
++
+ } else {
+- if ((i = ldap_modify_ext_s(ld->link, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
+- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Modify: %s", ldap_err2string(i));
+- RETVAL_FALSE;
+- } else RETVAL_TRUE;
++#ifdef HAVE_LDAP_MODIFY_EXT_S
++ if (ext) {
++ rc = ldap_modify_ext(ld->link, dn, ldap_mods, lsctrls, lcctrls, &msgid);
++
++ } else {
++ rc = ldap_modify_ext_s(ld->link, dn, ldap_mods, NULL, NULL);
++ }
++#else /* ! HAVE_LDAP_MODIFY_EXT_S */
++ rc = ldap_modify_s(ld->link, dn, ldap_mods);
++#endif /* ! HAVE_LDAP_MODIFY_EXT_S */
++ }
++
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: %s", is_full_add ? "Add" : "Modify", ldap_err2string(i));
++ RETVAL_FALSE;
++
++ } else {
++ if (ext) {
++ rc = ldap_result(ld->link, msgid, LDAP_MSG_ALL, NULL, &ldap_res);
++ if ((is_full_add && rc != LDAP_RES_ADD) || (!is_full_add && rc != LDAP_RES_MODIFY)) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: unable to collect result", is_full_add ? "Add" : "Modify");
++ RETVAL_FALSE;
++
++ } else {
++ int lerr;
++
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++ rc = ldap_parse_result(ld->link, ldap_res, &lerr, NULL, NULL, NULL, NULL, 0);
++ if (rc == LDAP_SUCCESS) {
++ rc = lerr;
++ }
++
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s failed: %s", is_full_add ? "Add" : "Modify", ldap_err2string(rc));
++ }
++ }
++
++ } else {
++ RETVAL_TRUE;
++ }
+ }
+
+ errexit:
+ for (i = 0; i < num_attribs; i++) {
+@@ -1406,46 +1728,57 @@
+ }
+ efree(num_berval);
+ efree(ldap_mods);
+
++ if (ext) {
++ if (lsctrls) {
++ _php_free_controls(&lsctrls);
++ }
++ if (lcctrls) {
++ _php_free_controls(&lcctrls);
++ }
++ }
++
+ return;
+ }
+ /* }}} */
+
+ /* {{{ proto bool ldap_add(resource link, string dn, array entry)
+ Add entries to LDAP directory */
+ PHP_FUNCTION(ldap_add)
+ {
+- /* use a newly define parameter into the do_modify so ldap_mod_add can be used the way it is supposed to be used , Gerrit THomson */
+- php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_LD_FULL_ADD);
++ /* use a newly define parameter into the do_modify so ldap_mod_add can be used the way it is supposed to be used , Gerrit Thomson */
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_LD_FULL_ADD, 0);
+ }
+ /* }}} */
+
+-/* three functions for attribute base modifications, gerrit Thomson */
++/* {{{ Three functions for attribute base modifications, gerrit Thomson */
+
+ /* {{{ proto bool ldap_mod_replace(resource link, string dn, array entry)
+ Replace attribute values with new ones */
+ PHP_FUNCTION(ldap_mod_replace)
+ {
+- php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_REPLACE);
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_REPLACE, 0);
+ }
+ /* }}} */
+
+ /* {{{ proto bool ldap_mod_add(resource link, string dn, array entry)
+ Add attribute values to current */
+ PHP_FUNCTION(ldap_mod_add)
+ {
+- php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_ADD);
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_ADD, 0);
+ }
+ /* }}} */
+
+ /* {{{ proto bool ldap_mod_del(resource link, string dn, array entry)
++
+ Delete attribute values */
+ PHP_FUNCTION(ldap_mod_del)
+ {
+- php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_DELETE);
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_DELETE, 0);
+ }
+ /* }}} */
++/* }}} */
+
+ /* {{{ proto bool ldap_delete(resource link, string dn)
+ Delete an entry from a directory */
+ PHP_FUNCTION(ldap_delete)
+@@ -1869,38 +2202,109 @@
+ RETURN_STRING(ldap_err2string(ld_errno), 1);
+ }
+ /* }}} */
+
+-/* {{{ proto bool ldap_compare(resource link, string dn, string attr, string value)
+- Determine if an entry has a specific value for one of its attributes */
+-PHP_FUNCTION(ldap_compare)
++/* {{{ proto void php_ldap_do_compare */
++void php_ldap_do_compare(INTERNAL_FUNCTION_PARAMETERS, int ext)
+ {
+- zval *link;
+- char *dn, *attr, *value;
++ zval *link, *dn, *attr, *value, **sctrls, **cctrls;
++ char *ldap_dn, *ldap_attr;
+ int dn_len, attr_len, value_len;
+ ldap_linkdata *ld;
+- int errno;
++ int rc, msgid, lerr, myargcount = ZEND_NUM_ARGS();
++ LDAPMessage *ldap_res;
++ LDAPControl **lsctrls = NULL, **lcctrls = NULL;
+
+- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsss", &link, &dn, &dn_len, &attr, &attr_len, &value, &value_len) != SUCCESS) {
+- return;
++ if (ext) {
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsss|ZZ", &link, &dn, &dn_len, &attr, &attr_len, &value, &value_len, &sctrls, &cctrls) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++ } else {
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsss", &link, &dn, &dn_len, &attr, &attr_len, &value, &value_len) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
+ }
+
+ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
+
+- errno = ldap_compare_s(ld->link, dn, attr, value);
+-
+- switch (errno) {
+- case LDAP_COMPARE_TRUE:
+- RETURN_TRUE;
+- break;
++ if (ext) {
++ struct berval ldap_bvalue;
++ switch (myargcount) {
++ case 6:
++ _php_parse_controls(cctrls, &lcctrls);
++ case 5:
++ _php_parse_controls(sctrls, &lsctrls);
++ }
+
+- case LDAP_COMPARE_FALSE:
++ ldap_bvalue.bv_val = Z_STRVAL_PP(&value);
++ ldap_bvalue.bv_len = Z_STRLEN_PP(&value);
++ rc = ldap_compare_ext(ld->link, ldap_dn, ldap_attr, &ldap_bvalue, lsctrls, lcctrls, &msgid);
++ if (lsctrls) {
++ _php_free_controls(&lsctrls);
++ }
++ if (lcctrls) {
++ _php_free_controls(&lcctrls);
++ }
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Compare: %s", ldap_err2string(rc));
+ RETURN_FALSE;
+- break;
++ }
++
++ rc = ldap_result(ld->link, msgid, LDAP_MSG_ALL, NULL, &ldap_res);
++ if (rc != LDAP_RES_COMPARE) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Compare: unable to get result");
++ RETURN_FALSE;
++ }
++
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++ rc = ldap_parse_result(ld->link, ldap_res, &lerr, NULL, NULL, NULL, NULL, 0);
++ if (rc == LDAP_SUCCESS) {
++ rc = lerr;
++ }
++
++ switch (rc) {
++ case LDAP_COMPARE_TRUE:
++ case LDAP_COMPARE_FALSE:
++ break;
++
++ default:
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Compare failed: %s", ldap_err2string(rc));
++ break;
++ }
++
++ } else {
++#ifdef HAVE_LDAP_COMPARE_EXT_S
++ struct berval ldap_bvalue;
++
++ ldap_bvalue.bv_val = Z_STRVAL_PP(&value);
++ ldap_bvalue.bv_len = Z_STRLEN_PP(&value);
++ rc = ldap_compare_ext_s(ld->link, ldap_dn, ldap_attr, &ldap_bvalue, NULL, NULL);
++#else /* ! HAVE_LDAP_COMPARE_EXT_S */
++ char *ldap_value;
++
++ ldap_value = Z_STRVAL_PP(&value);
++ rc = ldap_compare_s(ld->link, ldap_dn, ldap_attr, ldap_value);
++#endif /* ! HAVE_LDAP_COMPARE_EXT_S */
++
++ switch (rc) {
++ case LDAP_COMPARE_TRUE:
++ RETURN_TRUE;
++ break;
++
++ case LDAP_COMPARE_FALSE:
++ RETURN_FALSE;
++ break;
++ }
++
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Compare: %s", ldap_err2string(rc));
++ RETURN_LONG(-1);
+ }
+-
+- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Compare: %s", ldap_err2string(errno));
+- RETURN_LONG(-1);
++}
++/* {{{ proto bool ldap_compare(resource link, string dn, string attr, string valu)
++ Determine if an entry has a specific value for one of its attributes */
++PHP_FUNCTION(ldap_compare)
++{
++ php_ldap_do_compare(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+ }
+ /* }}} */
+
+ /* {{{ proto bool ldap_sort(resource link, resource result, string sortfilter)
+@@ -1932,59 +2336,233 @@
+ RETURN_TRUE;
+ }
+ /* }}} */
+
+-#if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
+-/* {{{ proto bool ldap_get_option(resource link, int option, mixed retval)
+- Get the current value of various session-wide parameters */
+-PHP_FUNCTION(ldap_get_option)
++/* {{{ Extended API that returns result instead of just bool
++ * to allow further manipulation by the ldap_parse_*() funcs,
++ * Pierangelo Masarati */
++
++/* {{{ proto result ldap_bind_ext(resource link [, string dn, string password])
++ Bind to LDAP directory */
++PHP_FUNCTION(ldap_bind_ext)
+ {
+- zval *link, *retval;
++ zval *link;
++ char *ldap_bind_dn = NULL, *ldap_bind_pw = NULL;
++ int ldap_bind_dnlen, ldap_bind_pwlen;
+ ldap_linkdata *ld;
+- long option;
+-
+- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &link, &option, &retval) != SUCCESS) {
+- return;
++ int rc, msgid, lerr;
++ LDAPMessage *ldap_res;
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ss", &link, &ldap_bind_dn, &ldap_bind_dnlen, &ldap_bind_pw, &ldap_bind_pwlen) == FAILURE) {
++
++ RETURN_FALSE;
+ }
+
+ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
+
+- switch (option) {
+- /* options with int value */
+- case LDAP_OPT_DEREF:
+- case LDAP_OPT_SIZELIMIT:
+- case LDAP_OPT_TIMELIMIT:
+- case LDAP_OPT_PROTOCOL_VERSION:
+- case LDAP_OPT_ERROR_NUMBER:
+- case LDAP_OPT_REFERRALS:
+-#ifdef LDAP_OPT_RESTART
+- case LDAP_OPT_RESTART:
++#ifdef LDAP_API_FEATURE_X_OPENLDAP
++ {
++ struct berval cred;
++
++ /* ldap_bind() is deprecated; use ldap_sasl_bind() instead */
++ cred.bv_val = ldap_bind_pw;
++ cred.bv_len = ldap_bind_pw ? ldap_bind_pwlen : 0;
++
++ rc = ldap_sasl_bind(ld->link, ldap_bind_dn, LDAP_SASL_SIMPLE, &cred,
++ NULL, NULL, /* no controls right now */
++ &msgid);
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind: %s", ldap_err2string(rc));
++ RETURN_FALSE;
++ }
++ }
++#else
++ msgid = ldap_bind(ld->link, ldap_bind_dn, ldap_bind_pw, LDAP_AUTH_SIMPLE);
++ if (msgid == -1) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind");
++ RETURN_FALSE;
++ }
+ #endif
+- {
+- int val;
+
+- if (ldap_get_option(ld->link, option, &val)) {
+- RETURN_FALSE;
+- }
+- zval_dtor(retval);
+- ZVAL_LONG(retval, val);
+- } break;
+-#ifdef LDAP_OPT_NETWORK_TIMEOUT
+- case LDAP_OPT_NETWORK_TIMEOUT:
+- {
+- struct timeval *timeout = NULL;
++ rc = ldap_result(ld->link, msgid, LDAP_MSG_ALL, NULL, &ldap_res);
++ if (rc != LDAP_RES_BIND) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to get bind result: %s", ldap_err2string(rc));
++ RETURN_FALSE;
++ }
+
+- if (ldap_get_option(ld->link, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
+- if (timeout) {
+- ldap_memfree(timeout);
+- }
+- RETURN_FALSE;
+- }
+- if (!timeout) {
+- RETURN_FALSE;
+- }
+- zval_dtor(retval);
+- ZVAL_LONG(retval, timeout->tv_sec);
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++ rc = ldap_parse_result(ld->link, ldap_res, &lerr, NULL, NULL, NULL, NULL, 0);
++ if (rc == LDAP_SUCCESS) {
++ rc = lerr;
++ }
++
++
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc));
++ }
++}
++/* }}} */
++
++/* {{{ proto result ldap_add_ext(resource link, string dn, array entry)
++ Add entries to LDAP directory; returns result */
++PHP_FUNCTION(ldap_add_ext)
++{
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_LD_FULL_ADD, 1);
++}
++/* }}} */
++
++/* {{{ proto result ldap_mod_replace_ext(resource link, string dn, array entry)
++ Replace attribute values with new ones */
++PHP_FUNCTION(ldap_mod_replace_ext)
++{
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_REPLACE, 1);
++}
++/* }}} */
++
++
++/* {{{ proto result ldap_mod_add_ext(resource link, string dn, array entry)
++ Add attribute values to current */
++PHP_FUNCTION(ldap_mod_add_ext)
++{
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_ADD, 1);
++}
++/* }}} */
++
++/* {{{ proto result ldap_mod_del_ext(resource link, string dn, array entry)
++ Delete attribute values */
++PHP_FUNCTION(ldap_mod_del_ext)
++{
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_DELETE, 1);
++}
++/* }}} */
++
++/* {{{ proto result ldap_delete_ext(resource link, string dn)
++ Delete an entry from a directory */
++PHP_FUNCTION(ldap_delete_ext)
++{
++ zval **link, **dn, **sctrls, **cctrls;
++ ldap_linkdata *ld;
++ char *ldap_dn;
++ int rc, dn_len, msgid, lerr, myargcount = ZEND_NUM_ARGS();
++ LDAPMessage *ldap_res;
++ LDAPControl **lsctrls = NULL, **lcctrls = NULL;
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|ZZ", &link, &dn, &dn_len, &sctrls, &cctrls) == FAILURE) {
++ WRONG_PARAM_COUNT;
++ }
++
++ switch (myargcount) {
++ case 4:
++ _php_parse_controls(cctrls, &lcctrls);
++
++ case 3:
++ _php_parse_controls(sctrls, &lsctrls);
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++
++ convert_to_string_ex(dn);
++ ldap_dn = Z_STRVAL_PP(dn);
++
++#ifdef HAVE_LDAP_DELETE_EXT_S
++ rc = ldap_delete_ext_s(ld->link, ldap_dn, NULL, NULL);
++#else /* ! HAVE_LDAP_DELETE_EXT_S */
++ rc = ldap_delete_s(ld->link, ldap_dn);
++#endif /* ! HAVE_LDAP_DELETE_EXT_S */
++ if (lsctrls) {
++ _php_free_controls(&lsctrls);
++ }
++ if (lcctrls) {
++ _php_free_controls(&lcctrls);
++ }
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Delete: %s", ldap_err2string(rc));
++ RETURN_FALSE;
++ }
++
++ rc = ldap_result(ld->link, msgid, LDAP_MSG_ALL, NULL, &ldap_res);
++ if (rc != LDAP_RES_DELETE) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Delete: unable to get result");
++ RETURN_FALSE;
++ }
++
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++ rc = ldap_parse_result(ld->link, ldap_res, &lerr, NULL, NULL, NULL, NULL, 0);
++ if (rc == LDAP_SUCCESS) {
++ rc = lerr;
++ }
++
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Delete failed: %s", ldap_err2string(rc));
++ }
++}
++/* }}} */
++
++/* }}} End of extended API, Pierangelo Masarati */
++
++
++/* {{{ proto result ldap_compare_ext(resource link, string dn, string attr, string value)
++ Determine if an entry has a specific value for one of its attributes */
++PHP_FUNCTION(ldap_compare_ext)
++{
++ php_ldap_do_compare(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
++}
++/* }}} */
++
++/* }}} End of extended API, Pierangelo Masarati */
++
++
++#if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
++/* {{{ proto bool ldap_get_option(resource link, int option, mixed retval)
++ Get the current value of various session-wide parameters */
++PHP_FUNCTION(ldap_get_option)
++{
++ zval *link, *retval;
++ ldap_linkdata *ld;
++ long option;
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &link, &option, &retval) != SUCCESS) {
++ return;
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
++
++ switch (option) {
++ /* options with int value */
++ case LDAP_OPT_DEREF:
++ case LDAP_OPT_SIZELIMIT:
++ case LDAP_OPT_TIMELIMIT:
++ case LDAP_OPT_PROTOCOL_VERSION:
++ case LDAP_OPT_ERROR_NUMBER:
++ case LDAP_OPT_REFERRALS:
++#ifdef LDAP_OPT_RESTART
++ case LDAP_OPT_RESTART:
++#endif
++ {
++ int val;
++
++ if (ldap_get_option(ld->link, option, &val)) {
++ RETURN_FALSE;
++ }
++ zval_dtor(retval);
++ ZVAL_LONG(retval, val);
++ } break;
++#ifdef LDAP_OPT_NETWORK_TIMEOUT
++ case LDAP_OPT_NETWORK_TIMEOUT:
++ {
++ struct timeval *timeout = NULL;
++
++ if (ldap_get_option(ld->link, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
++ if (timeout) {
++ ldap_memfree(timeout);
++ }
++ RETURN_FALSE;
++ }
++ if (!timeout) {
++ RETURN_FALSE;
++ }
++ zval_dtor(retval);
++ ZVAL_LONG(retval, timeout->tv_sec);
+ ldap_memfree(timeout);
+ } break;
+ #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
+ case LDAP_X_OPT_CONNECT_TIMEOUT:
+@@ -2207,21 +2785,23 @@
+ }
+ /* }}} */
+
+ #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;
+ ldap_linkdata *ld;
+ LDAPMessage *ldap_result;
+- char **lreferrals, **refp;
++ LDAPControl **lserverctrls;
++ char **lreferrals;
+ char *lmatcheddn, *lerrmsg;
+ int rc, lerrcode, myargcount = ZEND_NUM_ARGS();
++ /* int matcheddn_len, errmsg_len; */
+
+- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz|zzz", &link, &result, &errcode, &matcheddn, &errmsg, &referrals) != SUCCESS) {
+- return;
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz|zzzz", &link, &result, &errcode, &matcheddn, &errmsg, &referrals, &serverctrls) != SUCCESS) {
++ WRONG_PARAM_COUNT;
+ }
+
+ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
+ ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
+@@ -2229,9 +2809,9 @@
+ rc = ldap_parse_result(ld->link, ldap_result, &lerrcode,
+ 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));
+ RETURN_FALSE;
+@@ -2241,19 +2821,15 @@
+ ZVAL_LONG(errcode, lerrcode);
+
+ /* 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);
++ _php_parse_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);
+- }
++ _php_parse_referrals_resp(&lreferrals, &referrals);
+ case 5:
+ zval_dtor(errmsg);
+ if (lerrmsg == NULL) {
+ ZVAL_EMPTY_STRING(errmsg);
+@@ -2274,8 +2850,142 @@
+ }
+ /* }}} */
+ #endif
+
++/* {{{ Extended operation response parsing, Pierangelo Masarati */
++#ifdef HAVE_LDAP_PARSE_EXTENDED_RESULT
++/* {{{ proto bool ldap_parse_exop(resource link, resource result [, string retoid [, string retdata]])
++ Extract information from extended operation result */
++PHP_FUNCTION(ldap_parse_exop)
++{
++ zval *link, *result, *retoid, *retdata;
++ ldap_linkdata *ld;
++ LDAPMessage *ldap_result;
++ char *lretoid;
++ struct berval *lretdata;
++ int rc, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|zz", &link, &result, &retoid, &retdata) == SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
++ ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
++
++ rc = ldap_parse_extended_result(ld->link, ldap_result,
++ myargcount > 2 ? &lretoid: NULL,
++ myargcount > 3 ? &lretdata: NULL,
++ 0);
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse extended operation result: %s", ldap_err2string(rc));
++ RETURN_FALSE;
++ }
++
++ /* Reverse -> fall through */
++ switch (myargcount) {
++ case 4:
++ /* use arg #4 as the data returned by the server */
++ zval_dtor(retdata);
++ if (lretdata == NULL) {
++ ZVAL_EMPTY_STRING(retdata);
++ } else {
++ ZVAL_STRINGL(retdata, lretdata->bv_val, lretdata->bv_len, 1);
++ ldap_memfree(lretdata->bv_val);
++ ldap_memfree(lretdata);
++ }
++ case 3:
++ zval_dtor(retoid);
++ if (lretoid == NULL) {
++ ZVAL_EMPTY_STRING(retoid);
++ } else {
++ ZVAL_STRING(retoid, lretoid, 1);
++ ldap_memfree(lretoid);
++ }
++ }
++ RETURN_TRUE;
++}
++/* }}} */
++
++#ifdef HAVE_LDAP_PARSE_PASSWD
++/* {{{ proto bool ldap_parse_exop_passwd(resource link, resource result, string newpasswd)
++ Extract information from RFC 3062 password modify extended operation result */
++PHP_FUNCTION(ldap_parse_exop_passwd)
++{
++ zval **link, **result, **newpasswd;
++ ldap_linkdata *ld;
++ LDAPMessage *ldap_result;
++ struct berval lnewpasswd;
++ int rc, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ", &link, &result, &newpasswd) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, result, -1, "ldap result", le_result);
++
++ rc = ldap_parse_passwd(ld->link, ldap_result, &lnewpasswd);
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse passwd modify extended operation result: %s", ldap_err2string(rc));
++ RETURN_FALSE;
++ }
++
++ zval_dtor(*newpasswd);
++ if (lnewpasswd.bv_len == 0) {
++ ZVAL_EMPTY_STRING(*newpasswd);
++ } else {
++ ZVAL_STRINGL(*newpasswd, lnewpasswd.bv_val, lnewpasswd.bv_len, 1);
++ ldap_memfree(lnewpasswd.bv_val);
++ }
++
++ RETURN_TRUE;
++}
++#else
++/* TODO: implement based on ldap_parse_exop() */
++/* }}} */
++#endif
++
++#ifdef HAVE_LDAP_PARSE_WHOAMI
++/* {{{ proto bool ldap_parse_exop_whoami(resource link, resource result, string authzid)
++ Extract information from <draft-zeilenga-ldap-authzid> whoami extended operation result (a Work in Progress) */
++PHP_FUNCTION(ldap_parse_exop_whoami)
++{
++ zval **link, **result, **authzid;
++ ldap_linkdata *ld;
++ LDAPMessage *ldap_result;
++ struct berval *lauthzid;
++ int rc, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ", &link, &result, &authzid) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, result, -1, "ldap result", le_result);
++
++ rc = ldap_parse_whoami(ld->link, ldap_result, &lauthzid );
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse whoami extended operation result: %s", ldap_err2string(rc));
++ RETURN_FALSE;
++ }
++
++ zval_dtor(*authzid);
++ if (lauthzid == NULL) {
++ ZVAL_EMPTY_STRING(*authzid);
++ } else {
++ ZVAL_STRINGL(*authzid, lauthzid->bv_val, lauthzid->bv_len, 1);
++ ldap_memfree(lauthzid->bv_val);
++ ldap_memfree(lauthzid);
++ }
++ RETURN_TRUE;
++}
++#else
++/* TODO: implement based on ldap_parse_extended_result() */
++/* }}} */
++#endif
++/* }}} */
++#endif
++
+ /* {{{ proto resource ldap_first_reference(resource link, resource result)
+ Return first reference */
+ PHP_FUNCTION(ldap_first_reference)
+ {
+@@ -2758,51 +3468,733 @@
+ }
+ /* }}} */
+ #endif
+
+-/* {{{ arginfo */
+-ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_connect, 0, 0, 0)
+- ZEND_ARG_INFO(0, hostname)
+- ZEND_ARG_INFO(0, port)
+-#ifdef HAVE_ORALDAP
+- ZEND_ARG_INFO(0, wallet)
+- ZEND_ARG_INFO(0, wallet_passwd)
+- ZEND_ARG_INFO(0, authmode)
+-#endif
+-ZEND_END_ARG_INFO()
++/* {{{ Extended operations, Pierangelo Masarati */
++#ifdef HAVE_LDAP_EXTENDED_OPERATION_S
++/* {{{ proto ? ldap_exop(resource link, string reqoid [, string reqdata [, string retoid [, string retdata]]])
++ Extended operation */
++PHP_FUNCTION(ldap_exop)
++{
++ zval **link, **reqoid, **reqdata, **retoid, **retdata;
++ char *lreqoid, *lretoid = NULL;
++ struct berval lreqdata, *lretdata = NULL;
++ ldap_linkdata *ld;
++ LDAP *ldap;
++ LDAPMessage *ldap_res;
++ int rc, msgid, myargcount = ZEND_NUM_ARGS();
++ /* int reqoid_len, reqdata_len, retdata_len, retoid_len, retdat_len; */
+
+-ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_resource, 0, 0, 1)
+- ZEND_ARG_INFO(0, link_identifier)
+-ZEND_END_ARG_INFO()
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|ZZZ", &link, &reqoid, &reqdata, &retoid, &retdata) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
+
+-ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_bind, 0, 0, 1)
+- ZEND_ARG_INFO(0, link_identifier)
+- ZEND_ARG_INFO(0, bind_rdn)
+- ZEND_ARG_INFO(0, bind_password)
+-ZEND_END_ARG_INFO()
++ if (Z_TYPE_PP(link) == IS_NULL) {
++ ldap = NULL;
++ } else {
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ldap = ld->link;
++ }
+
+-#ifdef HAVE_LDAP_SASL
+-ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_sasl_bind, 0, 0, 1)
+- ZEND_ARG_INFO(0, link)
+- ZEND_ARG_INFO(0, binddn)
+- ZEND_ARG_INFO(0, password)
+- ZEND_ARG_INFO(0, sasl_mech)
+- ZEND_ARG_INFO(0, sasl_realm)
+- ZEND_ARG_INFO(0, sasl_authz_id)
+- ZEND_ARG_INFO(0, props)
+-ZEND_END_ARG_INFO()
+-#endif
++ switch (myargcount) {
++ case 5:
++ case 4:
++ case 3:
++ convert_to_string_ex(reqdata);
++ lreqdata.bv_val = Z_STRVAL_PP(reqdata);
++ lreqdata.bv_len = Z_STRLEN_PP(reqdata);
++ /* fallthru */
++ case 2:
++ convert_to_string_ex(reqoid);
++ lreqoid = Z_STRVAL_PP(reqoid);
++ }
++
++ if (myargcount > 3) {
++ /* synchronous call */
++ rc = ldap_extended_operation_s(ld->link, lreqoid,
++ lreqdata.bv_len > 0 ? &lreqdata: NULL,
++ NULL,
++ NULL,
++ &lretoid,
++ myargcount > 4 ? &lretdata : NULL );
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Extended operation %s failed: %s (%d)", lreqoid, ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
+
+-ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_read, 0, 0, 3)
+- ZEND_ARG_INFO(0, link_identifier)
+- ZEND_ARG_INFO(0, base_dn)
+- ZEND_ARG_INFO(0, filter)
+- ZEND_ARG_INFO(0, attributes)
+- ZEND_ARG_INFO(0, attrsonly)
+- ZEND_ARG_INFO(0, sizelimit)
+- ZEND_ARG_INFO(0, timelimit)
+- ZEND_ARG_INFO(0, deref)
+-ZEND_END_ARG_INFO()
++ /* Reverse -> fall through */
++ switch (myargcount) {
++ case 5:
++ /* use arg #4 as the data returned by the server */
++ zval_dtor(*retdata);
++ if (lretdata == NULL) {
++ ZVAL_EMPTY_STRING(*retdata);
++ } else {
++ ZVAL_STRINGL(*retdata, lretdata->bv_val, lretdata->bv_len, 1);
++ ldap_memfree(lretdata->bv_val);
++ ldap_memfree(lretdata);
++ }
++ case 4:
++ zval_dtor(*retoid);
++ if (lretoid == NULL) {
++ ZVAL_EMPTY_STRING(*retoid);
++ } else {
++ ZVAL_STRING(*retoid, lretoid, 1);
++ ldap_memfree(lretoid);
++ }
++ }
++
++ RETURN_TRUE;
++ }
++
++ /* asynchronous call */
++ rc = ldap_extended_operation(ld->link, lreqoid,
++ lreqdata.bv_len > 0 ? &lreqdata: NULL,
++ NULL, NULL, &msgid);
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Extended operation %s failed: %s (%d)", lreqoid, ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ rc = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
++ if (rc == -1) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Extended operation %s failed", lreqoid);
++ RETURN_FALSE;
++ }
++
++ /* return a PHP control object */
++ array_init(return_value);
++
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++}
++/* }}} */
++
++#ifdef HAVE_LDAP_PASSWD_S
++/* {{{ proto ? ldap_exop_passwd(resource link [, string user [, string oldpw [, string newpw [, string newpasswd ]]]])
++ Passwd modify extended operation */
++PHP_FUNCTION(ldap_exop_passwd)
++{
++ zval **link, **user, **newpw, **oldpw, **newpasswd;
++ struct berval luser, loldpw, lnewpw, lnewpasswd;
++ ldap_linkdata *ld;
++ LDAP *ldap;
++ LDAPMessage *ldap_res;
++ int rc, msgid, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|ZZZZ", &link, &user, &oldpw, &newpw, &newpasswd) == FAILURE) {
++ WRONG_PARAM_COUNT;
++ }
++
++ if (Z_TYPE_PP(link) == IS_NULL) {
++ ldap = NULL;
++ } else {
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ldap = ld->link;
++ }
++
++ luser.bv_len = 0;
++ loldpw.bv_len = 0;
++ lnewpw.bv_len = 0;
++
++ switch (myargcount) {
++ case 5:
++ case 4:
++ convert_to_string_ex(newpw);
++ lnewpw.bv_val = Z_STRVAL_PP(newpw);
++ lnewpw.bv_len = Z_STRLEN_PP(newpw);
++
++ case 3:
++ convert_to_string_ex(oldpw);
++ loldpw.bv_val = Z_STRVAL_PP(oldpw);
++ loldpw.bv_len = Z_STRLEN_PP(oldpw);
++
++ case 2:
++ convert_to_string_ex(user);
++ luser.bv_val = Z_STRVAL_PP(user);
++ luser.bv_len = Z_STRLEN_PP(user);
++ }
++
++ if (myargcount > 4 || lnewpw.bv_len > 0) {
++ /* synchronous call */
++ rc = ldap_passwd_s(ld->link, &luser,
++ loldpw.bv_len > 0 ? &loldpw : NULL,
++ /* loldpw.bv_len > 0 ? &loldpw : NULL, */
++ lnewpw.bv_len > 0 ? &lnewpw : NULL,
++ &lnewpasswd, NULL, NULL);
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passwd modify extended operation failed: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ if (myargcount > 4) {
++ zval_dtor(*newpasswd);
++ if (lnewpasswd.bv_len == 0) {
++ ZVAL_EMPTY_STRING(*newpasswd);
++ } else {
++ ZVAL_STRINGL(*newpasswd, lnewpasswd.bv_val, lnewpasswd.bv_len, 1);
++ }
++ }
++
++ ldap_memfree(lnewpasswd.bv_val);
++
++ RETURN_TRUE;
++ }
++
++ /* asynchronous call */
++ rc = ldap_passwd(ld->link, &luser,
++ loldpw.bv_len > 0 ? &loldpw : NULL,
++ lnewpw.bv_len > 0 ? &lnewpw : NULL,
++ NULL, NULL, &msgid);
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passwd modify extended operation failed: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ rc = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
++ if (rc == -1) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passwd modify extended operation failed");
++ RETURN_FALSE;
++ }
++
++ /* return a PHP control object */
++ array_init(return_value);
++
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++}
++#else
++/* TODO: implement based on ldap_extended_operation_s() */
++/* }}} */
++#endif
++
++#ifdef HAVE_LDAP_WHOAMI_S
++/* {{{ proto bool ldap_exop_whoami(resource link [, string authzid])
++ Whoami extended operation */
++PHP_FUNCTION(ldap_exop_whoami)
++{
++ zval **link, **authzid;
++ struct berval *lauthzid;
++ ldap_linkdata *ld;
++ LDAP *ldap;
++ LDAPMessage *ldap_res;
++ int rc, msgid, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|Z", &link, &authzid) == FAILURE) {
++ WRONG_PARAM_COUNT;
++ }
++
++ if (Z_TYPE_PP(link) == IS_NULL) {
++ ldap = NULL;
++ } else {
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ldap = ld->link;
++ }
++
++ if (myargcount == 2) {
++ /* synchronous call */
++ rc = ldap_whoami_s(ld->link, &lauthzid, NULL, NULL);
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Whoami extended operation failed: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ zval_dtor(*authzid);
++ if (lauthzid == NULL) {
++ ZVAL_EMPTY_STRING(*authzid);
++ } else {
++ ZVAL_STRINGL(*authzid, lauthzid->bv_val, lauthzid->bv_len, 1);
++ ldap_memfree(lauthzid->bv_val);
++ ldap_memfree(lauthzid);
++ }
++
++ RETURN_TRUE;
++ }
++
++ /* asynchronous call */
++ rc = ldap_whoami(ld->link, NULL, NULL, &msgid);
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Whoami extended operation failed: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ rc = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
++ if (rc == -1) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Whoami extended operation failed");
++ RETURN_FALSE;
++ }
++
++ /* return a PHP control object */
++ array_init(return_value);
++
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++}
++#else
++/* TODO: implement based on ldap_extended_operation_s() */
++#endif
++/* }}} */
++#endif
++/* }}} */
++
++/* {{{ LDAP controls encoding/decoding, Pierangelo Masarati */
++/* {{{ php_set_no_value_server_ctrl
++ */
++void php_set_no_value_server_ctrl(INTERNAL_FUNCTION_PARAMETERS, const char *oid, const char *msg)
++{
++ zval **link, **iscritical;
++ ldap_linkdata *ld;
++ LDAP *ldap;
++ LDAPControl ctrl = { 0 }, *ctrlsp[2];
++ int rc, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|Z", &link, &iscritical) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ if (Z_TYPE_PP(link) == IS_NULL) {
++ ldap = NULL;
++
++ } else {
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ldap = ld->link;
++ }
++
++ if (myargcount == 2) {
++ convert_to_boolean_ex(iscritical);
++ ctrl.ldctl_iscritical = Z_BVAL_PP(iscritical);
++ }
++
++ ctrl.ldctl_oid = (char *)oid;
++
++ if (ldap) {
++ /* directly set the option */
++ ctrlsp[0] = &ctrl;
++ ctrlsp[1] = NULL;
++
++ rc = ldap_set_option(ldap, LDAP_OPT_SERVER_CONTROLS, ctrlsp);
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set %s control: %s (%d)", msg, ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ } else {
++ /* return a PHP control object */
++ array_init(return_value);
++
++ add_assoc_string(return_value, "oid", ctrl.ldctl_oid, 1);
++ if (ctrl.ldctl_iscritical) {
++ add_assoc_bool(return_value, "iscritical", ctrl.ldctl_iscritical);
++ }
++ }
++
++ RETURN_TRUE;
++}
++/* }}} */
++
++#ifdef LDAP_CONTROL_MANAGEDSAIT
++/* {{{ proto bool ldap_ctrl_manageDSAit(resource link [, bool iscritical])
++ Inject manageDSAit control */
++PHP_FUNCTION(ldap_ctrl_manageDSAit)
++{
++ php_set_no_value_server_ctrl(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_CONTROL_MANAGEDSAIT, "manageDSAit");
++}
++/* }}} */
++#endif
++
++#ifdef LDAP_CONTROL_PAGEDRESULTS
++/* {{{ proto bool ldap_ctrl_paged_results(resource link, int pagesize [, bool iscritical [, string cookie]])
++ Inject paged results control*/
++PHP_FUNCTION(ldap_ctrl_paged_results)
++{
++ zval **link, **pagesize, **iscritical, **cookie;
++ int lpagesize = 0;
++ struct berval lcookie = { 0, NULL };
++ ldap_linkdata *ld;
++ LDAP *ldap;
++ BerElement *ber = NULL;
++ LDAPControl ctrl, *ctrlsp[2];
++ int rc, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|ZZ", &link, &pagesize, &iscritical, &cookie) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ if (Z_TYPE_PP(link) == IS_NULL) {
++ ldap = NULL;
++ } else {
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ldap = ld->link;
++ }
++
++ ber = ber_alloc_t(LBER_USE_DER);
++ if (ber == NULL) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to alloc BER encoding resources for paged results control");
++ RETURN_FALSE;
++ }
++
++ ctrl.ldctl_iscritical = 0;
++
++ switch (myargcount) {
++ case 4:
++ convert_to_string_ex(cookie);
++ lcookie.bv_val = Z_STRVAL_PP(cookie);
++ lcookie.bv_len = Z_STRLEN_PP(cookie);
++ /* fallthru */
++ case 3:
++ convert_to_boolean_ex(iscritical);
++ ctrl.ldctl_iscritical = Z_BVAL_PP(iscritical);
++ /* fallthru */
++ }
++ convert_to_long_ex(pagesize);
++ lpagesize = Z_LVAL_PP(pagesize);
++
++ ber_printf(ber, "{iO}", lpagesize, &lcookie );
++ rc = ber_flatten2( ber, &ctrl.ldctl_value, 0 );
++ if ( rc == -1 ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to BER encode paged results control");
++ RETURN_FALSE;
++ }
++
++ ctrl.ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
++
++ if (ldap) {
++ /* directly set the option */
++ ctrlsp[0] = &ctrl;
++ ctrlsp[1] = NULL;
++
++ rc = ldap_set_option(ldap, LDAP_OPT_SERVER_CONTROLS, ctrlsp);
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set paged results control: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ } else {
++ /* return a PHP control object */
++ array_init(return_value);
++
++ add_assoc_string(return_value, "oid", ctrl.ldctl_oid, 1);
++ if ( ctrl.ldctl_value.bv_len ) {
++ add_assoc_stringl(return_value, "value", ctrl.ldctl_value.bv_val, ctrl.ldctl_value.bv_len, 1);
++ }
++ if (ctrl.ldctl_iscritical) {
++ add_assoc_bool(return_value, "iscritical", ctrl.ldctl_iscritical);
++ }
++ }
++
++ if (ber != NULL) {
++ ber_free(ber, 1);
++ }
++}
++/* }}} */
++
++/* {{{ proto bool ldap_ctrl_paged_results_resp(resource link, resource result [, string cookie [, int estimated]])
++ Extract paged results control response */
++PHP_FUNCTION(ldap_ctrl_paged_results_resp)
++{
++ zval **link, **result, **cookie, **estimated;
++ struct berval lcookie;
++ int lestimated;
++ ldap_linkdata *ld;
++ LDAPMessage *ldap_result;
++ LDAPControl **lserverctrls, *lctrl;
++ BerElement *ber;
++ ber_tag_t tag;
++ int rc, lerrcode, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|ZZ", &link, &result, &cookie, &estimated) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, result, -1, "ldap result", le_result);
++
++ rc = ldap_parse_result(ld->link,
++ ldap_result,
++ &lerrcode,
++ NULL, /* matcheddn */
++ NULL, /* errmsg */
++ NULL, /* referrals */
++ &lserverctrls,
++ 0);
++
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse result: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ if (lerrcode != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result is: %s (%d)", ldap_err2string(lerrcode), lerrcode);
++ RETURN_FALSE;
++ }
++
++ if (lserverctrls == NULL) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No server controls in result");
++ RETURN_FALSE;
++ }
++
++ lctrl = ldap_find_control(LDAP_CONTROL_PAGEDRESULTS, lserverctrls);
++ if (lctrl == NULL) {
++ ldap_controls_free(lserverctrls);
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No paged results control response in result");
++ RETURN_FALSE;
++ }
++
++ ber = ber_init(&lctrl->ldctl_value);
++ if (ber == NULL) {
++ ldap_controls_free(lserverctrls);
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to alloc BER decoding resources for paged results control response");
++ RETURN_FALSE;
++ }
++
++ tag = ber_scanf(ber, "{io}", &lestimated, &lcookie );
++ (void)ber_free(ber, 1);
++
++ if (tag == LBER_ERROR) {
++ ldap_controls_free(lserverctrls);
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to decode paged results control response");
++ RETURN_FALSE;
++ }
++
++ if (lestimated < 0) {
++ ldap_controls_free(lserverctrls);
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid paged results control response value");
++ RETURN_FALSE;
++ }
++
++ ldap_controls_free(lserverctrls);
++
++ if (myargcount == 4) {
++ zval_dtor(*estimated);
++ ZVAL_LONG(*estimated, lestimated);
++ }
++
++ zval_dtor(*cookie);
++ if (lcookie.bv_len == 0) {
++ ZVAL_EMPTY_STRING(*cookie);
++ } else {
++ ZVAL_STRINGL(*cookie, lcookie.bv_val, lcookie.bv_len, 1);
++ }
++ ldap_memfree(lcookie.bv_val);
++
++ RETURN_TRUE;
++}
++/* }}} */
++#endif
++
++#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
++/* {{{ proto bool ldap_ctrl_ppolicy(resource link [, bool iscritical])
++ Inject password policy control */
++PHP_FUNCTION(ldap_ctrl_ppolicy)
++{
++ php_set_no_value_server_ctrl(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_CONTROL_PASSWORDPOLICYREQUEST, "passwordPolicy");
++}
++/* }}} */
++
++/* {{{ proto bool ldap_ctrl_ppolicy_resp(resource link, resource result [, expire [, grace [, error[, errmsg]]]])
++ Extract password policy control response */
++PHP_FUNCTION(ldap_ctrl_ppolicy_resp)
++{
++ zval **link, **result, **ppexpire, **ppgrace, **pperror, **pperrmsg;
++ int lexpire, lgrace;
++ LDAPPasswordPolicyError lerror;
++ ldap_linkdata *ld;
++ LDAPMessage *ldap_result;
++ LDAPControl **lserverctrls, *lctrl;
++ int rc, pperrmsg_len, lerrcode, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|ZZZZ", &link, &result, &ppexpire, &ppgrace, &pperror, &pperrmsg) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, result, -1, "ldap result", le_result);
++
++ rc = ldap_parse_result(ld->link,
++ ldap_result,
++ &lerrcode,
++ NULL, /* matcheddn */
++ NULL, /* errmsg */
++ NULL, /* referrals */
++ &lserverctrls,
++ 0);
++
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse result: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ if (lerrcode != LDAP_SUCCESS && lerrcode != LDAP_INVALID_CREDENTIALS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result is: %s (%d)", ldap_err2string(lerrcode), lerrcode);
++ RETURN_FALSE;
++ }
++
++ if (lserverctrls == NULL) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No server controls in result");
++ RETURN_FALSE;
++ }
++
++ lctrl = ldap_find_control(LDAP_CONTROL_PASSWORDPOLICYRESPONSE, lserverctrls);
++ if (lctrl == NULL) {
++ ldap_controls_free(lserverctrls);
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No password policy control response in result");
++ RETURN_FALSE;
++ }
++
++ lerrcode = ldap_parse_passwordpolicy_control(ld->link, lctrl, &lexpire, &lgrace, &lerror);
++ ldap_controls_free(lserverctrls);
++ if (lerrcode != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse password policy control response: %s (%d)", ldap_err2string(lerrcode), lerrcode);
++ RETURN_FALSE;
++ }
++
++ switch (myargcount) {
++ case 6:
++ zval_dtor(*pperrmsg);
++ ZVAL_STRING(*pperrmsg, (char *)ldap_passwordpolicy_err2txt(lerror), 1);
++
++ case 5:
++ zval_dtor(*pperror);
++ ZVAL_LONG(*pperror, (long)lerror);
++
++ case 4:
++ zval_dtor(*ppgrace);
++ ZVAL_LONG(*ppgrace, (long)lgrace);
++ }
++
++ zval_dtor(*ppexpire);
++ ZVAL_LONG(*ppexpire, (long)lexpire);
++
++ RETURN_TRUE;
++}
++/* }}} */
++#endif
++
++#ifdef LDAP_CONTROL_NOOP
++/* {{{ proto bool ldap_ctrl_noop(resource link, bool iscritical)
++ Inject control*/
++PHP_FUNCTION(ldap_ctrl_noop)
++{
++ php_set_no_value_server_ctrl(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_CONTROL_NOOP, "no-op");
++}
++/* }}} */
++#endif
++
++#ifdef LDAP_CONTROL_MANAGEDIT
++/* {{{ proto bool ldap_ctrl_manageDIT(resource link [, bool iscritical])
++ Inject control*/
++PHP_FUNCTION(ldap_ctrl_manageDIT)
++{
++ php_set_no_value_server_ctrl(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_CONTROL_MANAGEDIT, "manageDIT");
++}
++/* }}} */
++#endif
++
++#ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY
++/* {{{ proto bool ldap_ctrl_permissive_modify(resource link [, bool iscritical])
++ Inject control*/
++PHP_FUNCTION(ldap_ctrl_permissive_modify)
++{
++ php_set_no_value_server_ctrl(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_CONTROL_X_PERMISSIVE_MODIFY, "permissive modify");
++}
++/* }}} */
++#endif
++/* }}} */
++
++#ifdef HAVE_LDAP_REFRESH
++/* {{{ proto ? ldap_refresh(resource link , string dn , int ttl, [int *newttl])
++ DDS refresh extended operation */
++PHP_FUNCTION(ldap_refresh)
++{
++ zval **link, **dn, **ttl, **newttl;
++ struct berval ldn;
++ ber_int_t lttl;
++ ber_int_t lnewttl;
++ ldap_linkdata *ld;
++ LDAP *ldap;
++ LDAPMessage *ldap_res;
++ int rc, msgid, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|Z", &link, &dn, &ttl, &newttl) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ if (Z_TYPE_PP(link) == IS_NULL) {
++ ldap = NULL;
++ } else {
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *,
++ link, -1, "ldap link", le_link);
++ ldap = ld->link;
++ }
++
++ ldn.bv_len = 0;
++ convert_to_string_ex(dn);
++ ldn.bv_val = Z_STRVAL_PP(dn);
++ ldn.bv_len = Z_STRLEN_PP(dn);
++
++ convert_to_long_ex(ttl);
++ lttl = (ber_int_t)Z_LVAL_PP(ttl);
++
++ /* asynchronous call */
++ rc = ldap_refresh_s(ld->link, &ldn, lttl, &lnewttl, NULL, NULL);
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING,
++ "Refresh extended operation failed: %s (%d)",
++ ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ if (myargcount == 4) {
++ zval_dtor(*newttl);
++ ZVAL_LONG(*newttl, (long)lnewttl);
++ }
++ RETURN_TRUE;
++}
++#else
++/* TODO: implement based on ldap_extended_operation_s() */
++/* }}} */
++#endif
++
++/* {{{ arginfo */
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_connect, 0, 0, 0)
++ ZEND_ARG_INFO(0, hostname)
++ ZEND_ARG_INFO(0, port)
++#ifdef HAVE_ORALDAP
++ ZEND_ARG_INFO(0, wallet)
++ ZEND_ARG_INFO(0, wallet_passwd)
++ ZEND_ARG_INFO(0, authmode)
++#endif
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_resource, 0, 0, 1)
++ ZEND_ARG_INFO(0, link_identifier)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_bind, 0, 0, 1)
++ ZEND_ARG_INFO(0, link_identifier)
++ ZEND_ARG_INFO(0, bind_rdn)
++ ZEND_ARG_INFO(0, bind_password)
++ZEND_END_ARG_INFO()
++
++#ifdef HAVE_LDAP_SASL
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_sasl_bind, 0, 0, 1)
++ ZEND_ARG_INFO(0, link)
++ ZEND_ARG_INFO(0, binddn)
++ ZEND_ARG_INFO(0, password)
++ ZEND_ARG_INFO(0, sasl_mech)
++ ZEND_ARG_INFO(0, sasl_realm)
++ ZEND_ARG_INFO(0, sasl_authz_id)
++ ZEND_ARG_INFO(0, props)
++ZEND_END_ARG_INFO()
++#endif
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_read, 0, 0, 3)
++ ZEND_ARG_INFO(0, link_identifier)
++ ZEND_ARG_INFO(0, base_dn)
++ ZEND_ARG_INFO(0, filter)
++ ZEND_ARG_INFO(0, attributes)
++ ZEND_ARG_INFO(0, attrsonly)
++ ZEND_ARG_INFO(0, sizelimit)
++ ZEND_ARG_INFO(0, timelimit)
++ ZEND_ARG_INFO(0, deref)
++ZEND_END_ARG_INFO()
+
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_list, 0, 0, 3)
+ ZEND_ARG_INFO(0, link_identifier)
+ ZEND_ARG_INFO(0, base_dn)
+@@ -3007,8 +4399,9 @@
+ ZEND_ARG_INFO(1, errcode)
+ 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
+
+@@ -3027,8 +4420,40 @@
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_8859_to_t61, 0, 0, 1)
+ ZEND_ARG_INFO(0, value)
+ ZEND_END_ARG_INFO()
+ #endif
++
++#ifdef HAVE_LDAP_EXTENDED_OPERATION_S
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_exop, 0, 0, 5)
++ ZEND_ARG_INFO(0, link)
++ ZEND_ARG_INFO(0, reqoid)
++ ZEND_ARG_INFO(1, reqdata)
++ ZEND_ARG_INFO(1, repoid)
++ ZEND_ARG_INFO(1, repdata)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_exop_passwd, 0, 0, 5)
++ ZEND_ARG_INFO(0, link)
++ ZEND_ARG_INFO(1, user)
++ ZEND_ARG_INFO(1, oldpw)
++ ZEND_ARG_INFO(1, newpw)
++ ZEND_ARG_INFO(1, newpasswd)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_exop_whoami, 0, 0, 2)
++ ZEND_ARG_INFO(0, link)
++ ZEND_ARG_INFO(1, authzid)
++ZEND_END_ARG_INFO()
++#endif
++
++#ifdef HAVE_LDAP_REFRESH
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_refresh, 0, 0, 4)
++ ZEND_ARG_INFO(0, link)
++ ZEND_ARG_INFO(0, dn)
++ ZEND_ARG_INFO(1, ttl)
++ ZEND_ARG_INFO(0, newttl)
++ZEND_END_ARG_INFO()
++#endif
+ /* }}} */
+
+ /*
+ This is just a small subset of the functionality provided by the LDAP library. All the
+@@ -3091,9 +4516,22 @@
+ #endif
+ #ifdef HAVE_LDAP_START_TLS_S
+ PHP_FE(ldap_start_tls, arginfo_ldap_resource)
+ #endif
++#ifdef HAVE_LDAP_EXTENDED_OPERATION_S
++ PHP_FE(ldap_exop,
++ arginfo_ldap_exop)
++ PHP_FE(ldap_exop_passwd,
++ arginfo_ldap_exop_passwd)
++ PHP_FE(ldap_exop_whoami,
++ arginfo_ldap_exop_whoami)
++#endif
++#ifdef HAVE_LDAP_REFRESH
++ PHP_FE(ldap_refresh,
++ arginfo_ldap_refresh)
+ #endif
++#endif
++
+
+ #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
+ PHP_FE(ldap_set_rebind_proc, arginfo_ldap_set_rebind_proc)
+ #endif
+@@ -3102,8 +4540,33 @@
+ PHP_FE(ldap_t61_to_8859, arginfo_ldap_t61_to_8859)
+ PHP_FE(ldap_8859_to_t61, arginfo_ldap_8859_to_t61)
+ #endif
+
++/* routines to handle standard track controls, Pierangelo Masarati */
++#ifdef LDAP_CONTROL_MANAGEDSAIT
++ PHP_FE(ldap_ctrl_manageDSAit, NULL)
++#endif
++#ifdef LDAP_CONTROL_PAGEDRESULTS
++ PHP_FE(ldap_ctrl_paged_results, NULL) /* fourth_arg_force_ref */
++ PHP_FE(ldap_ctrl_paged_results_resp, NULL) /* arg3to4of4_force_ref */
++#endif
++#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
++ PHP_FE(ldap_ctrl_ppolicy, NULL)
++ PHP_FE(ldap_ctrl_ppolicy_resp, NULL) /* arg3to6of6_force_ref */
++#endif
++#ifdef LDAP_CONTROL_NOOP
++ PHP_FE(ldap_ctrl_noop, NULL)
++#endif
++#ifdef LDAP_CONTROL_MANAGEDIT
++ PHP_FE(ldap_ctrl_manageDIT, NULL)
++#endif
++#ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY
++ PHP_FE(ldap_ctrl_permissive_modify, NULL)
++#endif
++/* end of ando mod */
++
++
++
+ #ifdef LDAP_CONTROL_PAGEDRESULTS
+ PHP_FE(ldap_control_paged_result, arginfo_ldap_control_paged_result)
+ PHP_FE(ldap_control_paged_result_response, arginfo_ldap_control_paged_result_response)
+ #endif
+@@ -3128,8 +4591,10 @@
+ STANDARD_MODULE_PROPERTIES_EX
+ };
+ /* }}} */
+
++
++
+ /*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+--- ext/ldap/php_ldap.h.orig 2015-03-18 06:33:59.000000000 +0100
++++ ext/ldap/php_ldap.h 2015-04-13 05:57:02.000000000 +0200
+@@ -28,16 +28,148 @@
+ #endif
+
+ #include <ldap.h>
+
++#define HAVE_3ARG_SETREBINDPROC
++#define HAVE_LDAP_ADD_EXT_S
++#define HAVE_LDAP_MODIFY_EXT_S
++#define HAVE_LDAP_COMPARE_EXT_S
++#define HAVE_LDAP_DELETE_EXT_S
++#define HAVE_LDAP_PARSE_EXTENDED_RESULT
++#define HAVE_LDAP_PARSE_PASSWD
++#define HAVE_LDAP_PARSE_WHOAMI
++#define HAVE_LDAP_EXTENDED_OPERATION_S
++#define HAVE_LDAP_PASSWD_S
++#define HAVE_LDAP_WHOAMI_S
++#define HAVE_LDAP_REFRESH
++#define HAVE_LDAP_SASL
++#define HAVE_LDAP_EXTENDED_OPERATION_S
++#define HAVE_LDAP_REFRESH
++#define HAVE_LDAP_EXTENDED_OPERATION_S
++#define HAVE_LDAP_REFRESH
++#define HAVE_LDAP_EXTENDED_OPERATION
++
+ extern zend_module_entry ldap_module_entry;
+ #define ldap_module_ptr &ldap_module_entry
+
+ /* LDAP functions */
+ PHP_MINIT_FUNCTION(ldap);
+ PHP_MSHUTDOWN_FUNCTION(ldap);
+ PHP_MINFO_FUNCTION(ldap);
+
++#ifdef HAVE_LDAP_EXTENDED_OPERATION
++
++#endif
++
++#ifdef LDAP_CONTROL_MANAGEDSAIT
++/* RFC 3296 */
++PHP_FUNCTION(ldap_ctrl_manageDSAit);
++#endif
++#ifdef LDAP_CONTROL_PROXY_AUTHZ
++/* <draft-weltman-ldapv3-proxy> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_proxy_authz);
++#endif
++#ifdef LDAP_CONTROL_SUBENTRIES
++/* RFC 3672 */
++PHP_FUNCTION(ldap_ctrl_subentries);
++#endif
++#ifdef LDAP_CONTROL_VALUESRETURNFILTER
++/* RFC 3876 */
++PHP_FUNCTION(ldap_ctrl_vlv);
++#endif
++#ifdef LDAP_CONTROL_ASSERT
++/* <draft-zeilenga-ldap-assert> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_assert);
++#endif
++#ifdef LDAP_CONTROL_PRE_READ
++/* <draft-zeilenga-ldap-readentry> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_preread);
++PHP_FUNCTION(ldap_ctrl_postread);
++#endif
++#ifdef LDAP_CONTROL_SORTREQUEST
++/* RFC 2891 */
++PHP_FUNCTION(ldap_ctrl_sort);
++PHP_FUNCTION(ldap_ctrl_sort_resp);
++#endif
++#ifdef LDAP_CONTROL_PAGEDRESULTS
++/* RFC 2696 */
++PHP_FUNCTION(ldap_ctrl_paged_results);
++PHP_FUNCTION(ldap_ctrl_paged_results_resp);
++#endif
++#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
++/* <draft-behera-ldap-password-policy> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_ppolicy);
++PHP_FUNCTION(ldap_ctrl_ppolicy_resp);
++#endif
++#ifdef LDAP_CONTROL_NOOP
++/* <draft-zeilenga-ldap-noop> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_noop);
++#endif
++#ifdef LDAP_CONTROL_NO_SUBORDINATES
++/* don't know anything about it */
++#endif
++#ifdef LDAP_CONTROL_MANAGEDIT
++/* no spec; partially implemented in OpenLDAP 2.3 */
++PHP_FUNCTION(ldap_ctrl_manageDIT);
++#endif
++#ifdef LDAP_CONTROL_SLURP
++/* don't know anything about it */
++#endif
++#ifdef LDAP_CONTROL_VALSORT
++/* <> */
++PHP_FUNCTION(ldap_ctrl_valsort);
++#endif
++#ifdef LDAP_CONTROL_SYNC
++/* <draft-zeilenga-ldup-sync> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_sync);
++PHP_FUNCTION(ldap_ctrl_sync_state);
++PHP_FUNCTION(ldap_ctrl_sync_done);
++/* TODO: need to handle the SYNC intermediate response message (LDAPIRM) */
++#endif
++#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
++/* <draft-sermersheim-ldap-chaining> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_chaining);
++#endif
++#ifdef LDAP_CONTROL_X_INCREMENTAL_VALUES
++/* MS Active Directory */
++PHP_FUNCTION(ldap_ctrl_incremental_values);
++#endif
++#ifdef LDAP_CONTROL_X_DOMAIN_SCOPE
++/* MS Active Directory */
++PHP_FUNCTION(ldap_ctrl_domain_scope);
++#endif
++#ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY
++/* MS Active Directory */
++PHP_FUNCTION(ldap_ctrl_permissive_modify);
++#endif
++#ifdef LDAP_CONTROL_X_SEARCH_OPTIONS
++/* MS Active Directory */
++PHP_FUNCTION(ldap_ctrl_search_options);
++#endif
++#ifdef LDAP_CONTROL_X_TREE_DELETE
++/* MS Active Directory */
++PHP_FUNCTION(ldap_ctrl_tree_delete);
++#endif
++#ifdef LDAP_CONTROL_X_EXTENDED_DN
++/* MS Active Directory */
++PHP_FUNCTION(ldap_ctrl_extended_dn);
++#endif
++#ifdef LDAP_CONTROL_DUPENT
++/* <draft-ietf-ldapext-ldapv3-dupent> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_dupent);
++PHP_FUNCTION(ldap_ctrl_dupent_resp);
++PHP_FUNCTION(ldap_ctrl_dupent_done_resp);
++#endif
++#ifdef LDAP_CONTROL_PERSIST_REQUEST
++/* ? */
++#endif
++#ifdef LDAP_CONTROL_VLVREQUEST
++/* <draft-ietf-ldapext-ldapv3-vlv> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_vlv);
++PHP_FUNCTION(ldap_ctrl_vlv_resp);
++#endif
++
++
+ ZEND_BEGIN_MODULE_GLOBALS(ldap)
+ long num_links;
+ long max_links;
+ ZEND_END_MODULE_GLOBALS(ldap)
diff --git a/databases/php-ldap/files/ldap-ctrl-exop.patch b/databases/php-ldap/files/ldap-ctrl-exop55.patch
index 3261200c435..d9569bfa05f 100755..100644
--- a/databases/php-ldap/files/ldap-ctrl-exop.patch
+++ b/databases/php-ldap/files/ldap-ctrl-exop55.patch
@@ -1,7 +1,7 @@
-$NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
+$NetBSD$
/*
* Copyright (c) 2007-2009 Pierangelo Masarati
- * Copyright (c) 2009,2012 Emmanuel Dreyfus
+ * Copyright (c) 2009,2015 Emmanuel Dreyfus
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,23 +24,8 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
---- ext/ldap/config.m4.orig 2012-10-25 10:15:34.000000000 +0200
-+++ ext/ldap/config.m4 2012-10-25 10:15:34.000000000 +0200
-@@ -172,9 +172,11 @@
- fi
-
- dnl Solaris 2.8 claims to be 2004 API, but doesn't have
- dnl ldap_parse_reference() nor ldap_start_tls_s()
-- AC_CHECK_FUNCS([ldap_parse_result ldap_parse_reference ldap_start_tls_s])
-+ AC_CHECK_FUNCS([ldap_parse_result ldap_parse_extended_result ldap_parse_whoami ldap_parse_passwd ldap_parse_reference])
-+ AC_CHECK_FUNCS([ldap_extended_operation_s ldap_start_tls_s ldap_whoami_s ldap_passwd_s])
-+ AC_CHECK_FUNCS([ldap_search_ext_s ldap_add_ext_s ldap_modify_ext_s ldap_delete_ext_s ldap_compare_ext_s])
-
- dnl
- dnl SASL check
- dnl
---- ext/ldap/ldap.c.orig 2012-10-25 10:15:34.000000000 +0200
-+++ ext/ldap/ldap.c 2012-10-25 18:05:38.000000000 +0200
+--- ext/ldap/ldap.c.orig 2015-03-18 10:45:50.000000000 +0100
++++ ext/ldap/ldap.c 2015-04-10 14:54:51.000000000 +0200
@@ -66,8 +66,13 @@
#elif defined(HAVE_LDAP_SASL_SASL_H)
#include <sasl/sasl.h>
@@ -104,7 +89,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
{
ldap_resultentry *entry = (ldap_resultentry *)rsrc->ptr;
-@@ -194,8 +214,21 @@
+@@ -203,8 +223,21 @@
REGISTER_LONG_CONSTANT("GSLC_SSL_ONEWAY_AUTH", GSLC_SSL_ONEWAY_AUTH, CONST_PERSISTENT | CONST_CS);
REGISTER_LONG_CONSTANT("GSLC_SSL_TWOWAY_AUTH", GSLC_SSL_TWOWAY_AUTH, CONST_PERSISTENT | CONST_CS);
#endif
@@ -126,7 +111,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
le_result = zend_register_list_destructors_ex(_free_ldap_result, NULL, "ldap result", module_number);
le_result_entry = zend_register_list_destructors_ex(_free_ldap_result_entry, NULL, "ldap result entry", module_number);
-@@ -276,15 +309,176 @@
+@@ -285,15 +318,176 @@
DISPLAY_INI_ENTRIES();
}
/* }}} */
@@ -304,7 +289,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
char *wallet = NULL, *walletpasswd = NULL;
int walletlen = 0, walletpasswdlen = 0;
long authmode = GSLC_SSL_NO_AUTH;
-@@ -318,23 +512,41 @@
+@@ -327,23 +521,41 @@
ld = ecalloc(1, sizeof(ldap_linkdata));
@@ -353,27 +338,28 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
if (ldap == NULL) {
efree(ld);
RETURN_FALSE;
-@@ -391,17 +603,32 @@
+@@ -429,17 +641,33 @@
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Password contains a null byte");
+ RETURN_FALSE;
}
- 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;
++ 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 */
++ 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 {
@@ -387,7 +373,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
typedef struct {
char *mech;
char *realm;
-@@ -524,8 +751,9 @@
+@@ -562,8 +790,9 @@
_php_sasl_freedefs(ctx);
}
/* }}} */
@@ -397,7 +383,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
/* {{{ proto bool ldap_unbind(resource link)
Unbind from LDAP directory */
PHP_FUNCTION(ldap_unbind)
-@@ -1221,9 +1449,14 @@
+@@ -1259,9 +1488,14 @@
for (i = 0; i<count; i++) {
add_index_string(return_value, i, ldap_value[i], 1);
}
@@ -412,7 +398,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
/* }}} */
/* {{{ proto string ldap_dn2ufn(string dn)
-@@ -1254,38 +1487,67 @@
+@@ -1292,38 +1526,67 @@
/* added to fix use of ldap_modify_add for doing an ldap_add, gerrit thomson. */
#define PHP_LD_FULL_ADD 0xff
/* {{{ php_ldap_do_modify
@@ -490,7 +476,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
ldap_mods[i] = emalloc(sizeof(LDAPMod));
ldap_mods[i]->mod_op = oper | LDAP_MOD_BVALUES;
ldap_mods[i]->mod_type = NULL;
-@@ -1343,19 +1605,78 @@
+@@ -1381,19 +1644,78 @@
zend_hash_move_forward(Z_ARRVAL_P(entry));
}
ldap_mods[num_attribs] = NULL;
@@ -517,11 +503,6 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
- 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) {
-- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Modify: %s", ldap_err2string(i));
-- RETVAL_FALSE;
-- } else RETVAL_TRUE;
+#ifdef HAVE_LDAP_ADD_EXT_S
+ if (ext) {
+ rc = ldap_add_ext(ld->link, dn, ldap_mods, lsctrls, lcctrls, &msgid);
@@ -533,7 +514,11 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
+ rc = ldap_add_s(ld->link, dn, ldap_mods);
+#endif /* ! HAVE_LDAP_ADD_EXT_S */
+
-+ } else {
+ } else {
+- if ((i = ldap_modify_ext_s(ld->link, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
+- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Modify: %s", ldap_err2string(i));
+- RETVAL_FALSE;
+- } else RETVAL_TRUE;
+#ifdef HAVE_LDAP_MODIFY_EXT_S
+ if (ext) {
+ rc = ldap_modify_ext(ld->link, dn, ldap_mods, lsctrls, lcctrls, &msgid);
@@ -578,7 +563,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
errexit:
for (i = 0; i < num_attribs; i++) {
-@@ -1368,46 +1689,57 @@
+@@ -1406,46 +1728,57 @@
}
efree(num_berval);
efree(ldap_mods);
@@ -642,7 +627,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
/* {{{ proto bool ldap_delete(resource link, string dn)
Delete an entry from a directory */
PHP_FUNCTION(ldap_delete)
-@@ -1482,38 +1814,109 @@
+@@ -1869,38 +2202,109 @@
RETURN_STRING(ldap_err2string(ld_errno), 1);
}
/* }}} */
@@ -741,7 +726,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
+#else /* ! HAVE_LDAP_COMPARE_EXT_S */
+ char *ldap_value;
+
-+ ldap_value = Z_STRVAL_PP(value);
++ ldap_value = Z_STRVAL_PP(&value);
+ rc = ldap_compare_s(ld->link, ldap_dn, ldap_attr, ldap_value);
+#endif /* ! HAVE_LDAP_COMPARE_EXT_S */
+
@@ -771,19 +756,19 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
/* }}} */
/* {{{ proto bool ldap_sort(resource link, resource result, string sortfilter)
-@@ -1545,59 +1948,230 @@
+@@ -1932,58 +2336,232 @@
RETURN_TRUE;
}
/* }}} */
--#if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
+-#if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP
-/* {{{ proto bool ldap_get_option(resource link, int option, mixed retval)
- Get the current value of various session-wide parameters */
-PHP_FUNCTION(ldap_get_option)
+/* {{{ Extended API that returns result instead of just bool
+ * to allow further manipulation by the ldap_parse_*() funcs,
+ * Pierangelo Masarati */
-+
++
+/* {{{ proto result ldap_bind_ext(resource link [, string dn, string password])
+ Bind to LDAP directory */
+PHP_FUNCTION(ldap_bind_ext)
@@ -798,9 +783,10 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &link, &option, &retval) != SUCCESS) {
- return;
+ int rc, msgid, lerr;
-+ LDAPMessage *ldap_res;
-+
++ LDAPMessage *ldap_res;
++
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ss", &link, &ldap_bind_dn, &ldap_bind_dnlen, &ldap_bind_pw, &ldap_bind_pwlen) == FAILURE) {
++
+ RETURN_FALSE;
}
@@ -817,15 +803,15 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
-#ifdef LDAP_OPT_RESTART
- case LDAP_OPT_RESTART:
+#ifdef LDAP_API_FEATURE_X_OPENLDAP
-+ {
-+ struct berval cred;
-+
++ {
++ struct berval cred;
++
+ /* ldap_bind() is deprecated; use ldap_sasl_bind() instead */
+ cred.bv_val = ldap_bind_pw;
+ cred.bv_len = ldap_bind_pw ? ldap_bind_pwlen : 0;
-+
++
+ rc = ldap_sasl_bind(ld->link, ldap_bind_dn, LDAP_SASL_SIMPLE, &cred,
-+ NULL, NULL, /* no controls right now */
++ NULL, NULL, /* no controls right now */
+ &msgid);
+ if (rc != LDAP_SUCCESS) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind: %s", ldap_err2string(rc));
@@ -841,12 +827,6 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
#endif
- {
- int val;
-+
-+ rc = ldap_result(ld->link, msgid, LDAP_MSG_ALL, NULL, &ldap_res);
-+ if (rc != LDAP_RES_BIND) {
-+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to get bind result: %s", ldap_err2string(rc));
-+ RETURN_FALSE;
-+ }
- if (ldap_get_option(ld->link, option, &val)) {
- RETURN_FALSE;
@@ -858,10 +838,10 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
- case LDAP_OPT_NETWORK_TIMEOUT:
- {
- struct timeval *timeout = NULL;
-+ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
-+ rc = ldap_parse_result(ld->link, ldap_res, &lerr, NULL, NULL, NULL, NULL, 0);
-+ if (rc == LDAP_SUCCESS) {
-+ rc = lerr;
++ rc = ldap_result(ld->link, msgid, LDAP_MSG_ALL, NULL, &ldap_res);
++ if (rc != LDAP_RES_BIND) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to get bind result: %s", ldap_err2string(rc));
++ RETURN_FALSE;
+ }
- if (ldap_get_option(ld->link, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
@@ -874,7 +854,13 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
- RETURN_FALSE;
- }
- zval_dtor(retval);
-- ZVAL_LONG(retval, timeout->tv_sec);
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++ rc = ldap_parse_result(ld->link, ldap_res, &lerr, NULL, NULL, NULL, NULL, 0);
++ if (rc == LDAP_SUCCESS) {
++ rc = lerr;
++ }
++
++
+ if (rc != LDAP_SUCCESS) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc));
+ }
@@ -897,12 +883,13 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
+}
+/* }}} */
+
++
+/* {{{ proto result ldap_mod_add_ext(resource link, string dn, array entry)
+ Add attribute values to current */
+PHP_FUNCTION(ldap_mod_add_ext)
+{
+ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_ADD, 1);
-+}
++}
+/* }}} */
+
+/* {{{ proto result ldap_mod_del_ext(resource link, string dn, array entry)
@@ -910,7 +897,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
+PHP_FUNCTION(ldap_mod_del_ext)
+{
+ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_DELETE, 1);
-+}
++}
+/* }}} */
+
+/* {{{ proto result ldap_delete_ext(resource link, string dn)
@@ -1039,12 +1026,11 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
+ RETURN_FALSE;
+ }
+ zval_dtor(retval);
-+ ZVAL_LONG(retval, timeout->tv_sec);
+ ZVAL_LONG(retval, timeout->tv_sec);
ldap_memfree(timeout);
} break;
#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
- case LDAP_X_OPT_CONNECT_TIMEOUT:
-@@ -1820,21 +2394,23 @@
+@@ -2207,21 +2785,23 @@
}
/* }}} */
@@ -1067,13 +1053,13 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz|zzz", &link, &result, &errcode, &matcheddn, &errmsg, &referrals) != SUCCESS) {
- return;
-+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz|zzzz", &link, &result, &errcode, &matcheddn, &errmsg, &referrals, &serverctrls) != SUCCESS) {
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz|zzzz", &link, &result, &errcode, &matcheddn, &errmsg, &referrals, &serverctrls) != SUCCESS) {
+ WRONG_PARAM_COUNT;
}
ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
-@@ -1842,9 +2418,9 @@
+@@ -2229,9 +2809,9 @@
rc = ldap_parse_result(ld->link, ldap_result, &lerrcode,
myargcount > 3 ? &lmatcheddn : NULL,
myargcount > 4 ? &lerrmsg : NULL,
@@ -1084,7 +1070,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
if (rc != LDAP_SUCCESS) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse result: %s", ldap_err2string(rc));
RETURN_FALSE;
-@@ -1854,19 +2430,15 @@
+@@ -2241,19 +2821,15 @@
ZVAL_LONG(errcode, lerrcode);
/* Reverse -> fall through */
@@ -1110,7 +1096,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
zval_dtor(errmsg);
if (lerrmsg == NULL) {
ZVAL_EMPTY_STRING(errmsg);
-@@ -1887,8 +2459,142 @@
+@@ -2274,8 +2850,142 @@
}
/* }}} */
#endif
@@ -1253,7 +1239,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
Return first reference */
PHP_FUNCTION(ldap_first_reference)
{
-@@ -2184,60 +2890,742 @@
+@@ -2758,54 +3468,736 @@
}
/* }}} */
#endif
@@ -1373,12 +1359,6 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
-ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_list, 0, 0, 3)
- ZEND_ARG_INFO(0, link_identifier)
-- ZEND_ARG_INFO(0, base_dn)
-- ZEND_ARG_INFO(0, filter)
-- ZEND_ARG_INFO(0, attributes)
-- ZEND_ARG_INFO(0, attrsonly)
-- ZEND_ARG_INFO(0, sizelimit)
-- ZEND_ARG_INFO(0, timelimit)
+ RETURN_TRUE;
+ }
+
@@ -2033,17 +2013,11 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_list, 0, 0, 3)
+ ZEND_ARG_INFO(0, link_identifier)
-+ ZEND_ARG_INFO(0, base_dn)
-+ ZEND_ARG_INFO(0, filter)
-+ ZEND_ARG_INFO(0, attributes)
-+ ZEND_ARG_INFO(0, attrsonly)
-+ ZEND_ARG_INFO(0, sizelimit)
-+ ZEND_ARG_INFO(0, timelimit)
- ZEND_ARG_INFO(0, deref)
- ZEND_END_ARG_INFO()
-
- ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_search, 0, 0, 3)
-@@ -2411,8 +3799,9 @@
+ ZEND_ARG_INFO(0, base_dn)
+ ZEND_ARG_INFO(0, filter)
+ ZEND_ARG_INFO(0, attributes)
+ ZEND_ARG_INFO(0, attrsonly)
+@@ -3007,8 +4399,9 @@
ZEND_ARG_INFO(1, errcode)
ZEND_ARG_INFO(1, matcheddn)
ZEND_ARG_INFO(1, errmsg)
@@ -2053,7 +2027,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
#endif
#endif
-@@ -2431,8 +3820,40 @@
+@@ -3027,8 +4420,40 @@
ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_8859_to_t61, 0, 0, 1)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()
@@ -2094,7 +2068,7 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
/*
This is just a small subset of the functionality provided by the LDAP library. All the
-@@ -2494,10 +3915,23 @@
+@@ -3091,9 +4516,22 @@
#endif
#ifdef HAVE_LDAP_START_TLS_S
PHP_FE(ldap_start_tls, arginfo_ldap_resource)
@@ -2110,49 +2084,48 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
+#ifdef HAVE_LDAP_REFRESH
+ PHP_FE(ldap_refresh,
+ arginfo_ldap_refresh)
-+#endif
#endif
-
++#endif
+
+
#if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
PHP_FE(ldap_set_rebind_proc, arginfo_ldap_set_rebind_proc)
#endif
-
-@@ -2505,8 +3939,33 @@
+@@ -3102,8 +4540,33 @@
PHP_FE(ldap_t61_to_8859, arginfo_ldap_t61_to_8859)
PHP_FE(ldap_8859_to_t61, arginfo_ldap_8859_to_t61)
#endif
+/* routines to handle standard track controls, Pierangelo Masarati */
+#ifdef LDAP_CONTROL_MANAGEDSAIT
-+ PHP_FE(ldap_ctrl_manageDSAit, NULL)
++ PHP_FE(ldap_ctrl_manageDSAit, NULL)
+#endif
+#ifdef LDAP_CONTROL_PAGEDRESULTS
-+ PHP_FE(ldap_ctrl_paged_results, NULL) /* fourth_arg_force_ref */
-+ PHP_FE(ldap_ctrl_paged_results_resp, NULL) /* arg3to4of4_force_ref */
++ PHP_FE(ldap_ctrl_paged_results, NULL) /* fourth_arg_force_ref */
++ PHP_FE(ldap_ctrl_paged_results_resp, NULL) /* arg3to4of4_force_ref */
+#endif
+#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
-+ PHP_FE(ldap_ctrl_ppolicy, NULL)
-+ PHP_FE(ldap_ctrl_ppolicy_resp, NULL) /* arg3to6of6_force_ref */
++ PHP_FE(ldap_ctrl_ppolicy, NULL)
++ PHP_FE(ldap_ctrl_ppolicy_resp, NULL) /* arg3to6of6_force_ref */
+#endif
+#ifdef LDAP_CONTROL_NOOP
-+ PHP_FE(ldap_ctrl_noop, NULL)
++ PHP_FE(ldap_ctrl_noop, NULL)
+#endif
+#ifdef LDAP_CONTROL_MANAGEDIT
-+ PHP_FE(ldap_ctrl_manageDIT, NULL)
++ PHP_FE(ldap_ctrl_manageDIT, NULL)
+#endif
+#ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY
-+ PHP_FE(ldap_ctrl_permissive_modify, NULL)
++ PHP_FE(ldap_ctrl_permissive_modify, NULL)
+#endif
+/* end of ando mod */
+
+
+
- PHP_FE_END
- };
- /* }}} */
-
-@@ -2527,8 +3986,10 @@
+ #ifdef LDAP_CONTROL_PAGEDRESULTS
+ PHP_FE(ldap_control_paged_result, arginfo_ldap_control_paged_result)
+ PHP_FE(ldap_control_paged_result_response, arginfo_ldap_control_paged_result_response)
+ #endif
+@@ -3128,8 +4591,10 @@
STANDARD_MODULE_PROPERTIES_EX
};
/* }}} */
@@ -2163,9 +2136,36 @@ $NetBSD: ldap-ctrl-exop.patch,v 1.3 2012/10/29 08:50:29 manu Exp $
* Local variables:
* tab-width: 4
* c-basic-offset: 4
---- ext/ldap/php_ldap.h.orig 2012-10-25 10:15:34.000000000 +0200
-+++ ext/ldap/php_ldap.h 2012-10-25 10:15:34.000000000 +0200
-@@ -36,8 +36,121 @@
+--- ext/ldap/php_ldap.h.orig 2015-03-18 10:45:50.000000000 +0100
++++ ext/ldap/php_ldap.h 2015-04-12 11:22:11.000000000 +0200
+@@ -28,16 +28,148 @@
+ #endif
+
+ #include <ldap.h>
+
++#define HAVE_3ARG_SETREBINDPROC
++#define HAVE_LDAP_ADD_EXT_S
++#define HAVE_LDAP_MODIFY_EXT_S
++#define HAVE_LDAP_COMPARE_EXT_S
++#define HAVE_LDAP_DELETE_EXT_S
++#define HAVE_LDAP_PARSE_EXTENDED_RESULT
++#define HAVE_LDAP_PARSE_PASSWD
++#define HAVE_LDAP_PARSE_WHOAMI
++#define HAVE_LDAP_EXTENDED_OPERATION_S
++#define HAVE_LDAP_PASSWD_S
++#define HAVE_LDAP_WHOAMI_S
++#define HAVE_LDAP_REFRESH
++#define HAVE_LDAP_SASL
++#define HAVE_LDAP_EXTENDED_OPERATION_S
++#define HAVE_LDAP_REFRESH
++#define HAVE_LDAP_EXTENDED_OPERATION_S
++#define HAVE_LDAP_REFRESH
++#define HAVE_LDAP_EXTENDED_OPERATION
++
+ extern zend_module_entry ldap_module_entry;
+ #define ldap_module_ptr &ldap_module_entry
+
+ /* LDAP functions */
PHP_MINIT_FUNCTION(ldap);
PHP_MSHUTDOWN_FUNCTION(ldap);
PHP_MINFO_FUNCTION(ldap);
diff --git a/databases/php-ldap/files/ldap-ctrl-exop56.patch b/databases/php-ldap/files/ldap-ctrl-exop56.patch
new file mode 100644
index 00000000000..0bf6b06da82
--- /dev/null
+++ b/databases/php-ldap/files/ldap-ctrl-exop56.patch
@@ -0,0 +1,2263 @@
+--- ext/ldap/ldap.c.orig 2015-03-19 01:19:30.000000000 +0100
++++ ext/ldap/ldap.c 2015-04-13 05:51:05.000000000 +0200
+@@ -66,8 +66,13 @@
+ #elif defined(HAVE_LDAP_SASL_SASL_H)
+ #include <sasl/sasl.h>
+ #endif
+
++/* XXX Not detected by configure... */
++#ifdef LDAP_EXOP_REFRESH
++#define HAVE_LDAP_REFRESH 1
++#endif
++
+ #define PHP_LDAP_ESCAPE_FILTER 0x01
+ #define PHP_LDAP_ESCAPE_DN 0x02
+
+ typedef struct {
+@@ -91,31 +96,46 @@
+ #ifdef COMPILE_DL_LDAP
+ ZEND_GET_MODULE(ldap)
+ #endif
+
++
++/* {{{ proto void _close_ldap_link()
++ close a connection and free LDAP resources */
+ static void _close_ldap_link(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
+ {
+ ldap_linkdata *ld = (ldap_linkdata *)rsrc->ptr;
+
+- ldap_unbind_s(ld->link);
+-#if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
++ /* ldap_unbind_s() is deprecated;
++ * the distinction between ldap_unbind() and ldap_unbind_s() is moot */
++#ifdef LDAP_API_FEATURE_X_OPENLDAP
++ ldap_unbind_ext(ld->link, NULL, NULL);
++#ifdef HAVE_3ARG_SETREBINDPROC
++
+ if (ld->rebindproc != NULL) {
+ zval_dtor(ld->rebindproc);
+ FREE_ZVAL(ld->rebindproc);
+ }
+ #endif
++#else /* ! LDAP_API_FEATURE_X_OPENLDAP */
++ ldap_unbind_s(ld->link);
++#endif /* ! LDAP_API_FEATURE_X_OPENLDAP */
++
+ efree(ld);
+ LDAPG(num_links)--;
+ }
+ /* }}} */
+
++/* {{{ proto void _free_ldap_result()
++ free the result of an LDAP operation */
+ static void _free_ldap_result(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
+ {
+ LDAPMessage *result = (LDAPMessage *)rsrc->ptr;
+ ldap_msgfree(result);
+ }
+ /* }}} */
+
++/* {{{ proto void _free_ldap_result_entry()
++ free an entry resulting from an LDAP search operation */
+ static void _free_ldap_result_entry(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
+ {
+ ldap_resultentry *entry = (ldap_resultentry *)rsrc->ptr;
+
+@@ -206,8 +226,21 @@
+ REGISTER_LONG_CONSTANT("GSLC_SSL_ONEWAY_AUTH", GSLC_SSL_ONEWAY_AUTH, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GSLC_SSL_TWOWAY_AUTH", GSLC_SSL_TWOWAY_AUTH, CONST_PERSISTENT | CONST_CS);
+ #endif
+
++#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
++ REGISTER_LONG_CONSTANT("PP_passwordExpired", PP_passwordExpired, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_accountLocked", PP_accountLocked, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_changeAfterReset", PP_changeAfterReset, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_passwordModNotAllowed", PP_passwordModNotAllowed, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_mustSupplyOldPassword", PP_mustSupplyOldPassword, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_insufficientPasswordQuality", PP_insufficientPasswordQuality, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_passwordTooShort", PP_passwordTooShort, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_passwordTooYoung", PP_passwordTooYoung, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_passwordInHistory", PP_passwordInHistory, CONST_PERSISTENT | CONST_CS);
++ REGISTER_LONG_CONSTANT("PP_noError", PP_noError, CONST_PERSISTENT | CONST_CS);
++#endif /* LDAP_CONTROL_PASSWORDPOLICYREQUEST */
++
+ REGISTER_LONG_CONSTANT("LDAP_ESCAPE_FILTER", PHP_LDAP_ESCAPE_FILTER, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("LDAP_ESCAPE_DN", PHP_LDAP_ESCAPE_DN, CONST_PERSISTENT | CONST_CS);
+
+ le_link = zend_register_list_destructors_ex(_close_ldap_link, NULL, "ldap link", module_number);
+@@ -291,15 +324,176 @@
+ DISPLAY_INI_ENTRIES();
+ }
+ /* }}} */
+
++
++/* {{{ proto int _php_parse_referrals_resp()
++ parse an array of LDAP referrals into a zval array */
++static int _php_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;
++ }
++
++ return num_referrals;
++}
++/* }}} */
++
++/* {{{ proto int _php_parse_controls()
++ parse an array of zvals into an array of LDAP controls */
++static int _php_parse_controls(zval **ctrls, LDAPControl ***lctrlsp)
++{
++ LDAPControl *lctrl, **lctrls, **lctrlp;
++ zval **ctrlval, **val;
++ int ncontrols;
++ char error = 0;
++
++
++ if ((Z_TYPE_PP(ctrls) != IS_ARRAY) || !(ncontrols = zend_hash_num_elements(Z_ARRVAL_PP(ctrls)))) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected non-empty array value");
++ return 0;
++ }
++
++ lctrls = safe_emalloc((1 + ncontrols), sizeof(*lctrls), 0);
++ *lctrls = NULL;
++ lctrlp = lctrls;
++ zend_hash_internal_pointer_reset(Z_ARRVAL_PP(ctrls));
++ while (zend_hash_get_current_data(Z_ARRVAL_PP(ctrls), (void**)&ctrlval) == SUCCESS) {
++ if (Z_TYPE_PP(ctrlval) != IS_ARRAY) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The array value must contain only arrays, where each array is a control");
++ error = 1;
++ break;
++ }
++ if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "oid", sizeof("oid"), (void **) &val) == FAILURE) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Control must have an oid key");
++ error = 1;
++ break;
++ }
++ lctrl = *lctrlp = emalloc(sizeof(**lctrlp));
++ convert_to_string_ex(val);
++ lctrl->ldctl_oid = Z_STRVAL_PP(val);
++ if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "value", sizeof("value"), (void **) &val) == SUCCESS) {
++ convert_to_string_ex(val);
++ lctrl->ldctl_value.bv_val = Z_STRVAL_PP(val);
++ lctrl->ldctl_value.bv_len = Z_STRLEN_PP(val);
++ } else {
++ lctrl->ldctl_value.bv_val = NULL;
++ lctrl->ldctl_value.bv_len = 0;
++ }
++ if (zend_hash_find(Z_ARRVAL_PP(ctrlval), "iscritical", sizeof("iscritical"), (void **) &val) == SUCCESS) {
++ convert_to_boolean_ex(val);
++ lctrl->ldctl_iscritical = Z_BVAL_PP(val);
++ } else {
++ lctrl->ldctl_iscritical = 0;
++ }
++
++ ++lctrlp;
++ *lctrlp = NULL;
++ zend_hash_move_forward(Z_ARRVAL_PP(ctrls));
++ }
++ if (!error) {
++ *lctrlsp = lctrls;
++ }
++ return ncontrols;
++}
++/* }}} */
++
++/* {{{ proto void _php_free_controls()
++ frees an array of LDAP controls as parsed (and malloc'ed) by _php_parse_controls */
++static void _php_free_controls(LDAPControl ***lctrlsp)
++{
++ LDAPControl **lctrlp;
++
++ for (lctrlp = *lctrlsp; *lctrlp; lctrlp++) {
++ efree(*lctrlp);
++ }
++ efree(*lctrlsp);
++ *lctrlsp = NULL;
++}
++/* }}} */
++
++/* {{{ proto void _php_parse_controls_resp()
++ parse an array of LDAP controls into a zval array */
++static int _php_parse_controls_resp(LDAPControl ***lctrlsp, zval **ctrls)
++{
++ int num_ctrls = 0;
++
++ if (*lctrlsp != NULL) {
++ int error = 0;
++ LDAPControl **ctrlp = *lctrlsp;
++
++ 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);
++ }
++
++ /* As per <draft-ietf-ldapbis-protocol>:
++ *
++ * 4.1.11
++
++ The criticality field only has meaning in controls attached to
++ request messages (except UnbindRequest). For controls attached to
++ response messages and the UnbindRequest, the criticality field SHOULD
++ be FALSE, and MUST be ignored by the receiving protocol peer.
++
++ */
++
++ add_next_index_zval(*ctrls, ctrlval);
++
++ num_ctrls++;
++ ctrlp++;
++ }
++ ldap_controls_free(*lctrlsp);
++ *lctrlsp = NULL;
++
++ if (error) {
++ /* ... */
++ return -1;
++ }
++ }
++
++ return num_ctrls;
++}
++/* }}} */
++
+ /* {{{ proto resource ldap_connect([string host [, int port [, string wallet [, string wallet_passwd [, int authmode]]]]])
+ Connect to an LDAP server */
+ PHP_FUNCTION(ldap_connect)
+ {
+ char *host = NULL;
+ int hostlen;
+- long port = 389; /* Default port */
++ int port =
++#ifdef LDAP_API_FEATURE_X_OPENLDAP
++ LDAP_PORT
++#else /* ! LDAP_API_FEATURE_X_OPENLDAP */
++ 389 /* Default port */
++#endif /* ! LDAP_API_FEATURE_X_OPENLDAP */
++ ;
+ #ifdef HAVE_ORALDAP
+ char *wallet = NULL, *walletpasswd = NULL;
+ int walletlen = 0, walletpasswdlen = 0;
+ long authmode = GSLC_SSL_NO_AUTH;
+@@ -333,23 +527,41 @@
+
+ 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;
++ * ldap_init()/ldap_open() is deprecated, use ldap_initialize() instead.
++ */
++ {
++ 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:%d", host ? host : "", 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
++#else /* ! LDAP_API_FEATURE_X_OPENLDAP */
+ ldap = ldap_open(host, port);
+-#endif
++#endif /* ! LDAP_API_FEATURE_X_OPENLDAP */
+
+ if (ldap == NULL) {
+ efree(ld);
+ RETURN_FALSE;
+@@ -435,17 +647,33 @@
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Password contains a null byte");
+ RETURN_FALSE;
+ }
+
+- 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 {
+ RETURN_TRUE;
+ }
+ }
+ /* }}} */
+
++/* {{{ SASL bind stuff */
+ #ifdef HAVE_LDAP_SASL
+ typedef struct {
+ char *mech;
+ char *realm;
+@@ -568,8 +796,9 @@
+ _php_sasl_freedefs(ctx);
+ }
+ /* }}} */
+ #endif /* HAVE_LDAP_SASL */
++/* }}} */
+
+ /* {{{ proto bool ldap_unbind(resource link)
+ Unbind from LDAP directory */
+ PHP_FUNCTION(ldap_unbind)
+@@ -1265,9 +1494,14 @@
+ for (i = 0; i<count; i++) {
+ add_index_string(return_value, i, ldap_value[i], 1);
+ }
+
++#ifdef LDAP_API_FEATURE_X_OPENLDAP
++ /* ldap_value_free() is deprecated */
++ ber_memvfree((void **)ldap_value);
++#else /* ! LDAP_API_FEATURE_X_OPENLDAP */
+ ldap_value_free(ldap_value);
++#endif /* ! LDAP_API_FEATURE_X_OPENLDAP */
+ }
+ /* }}} */
+
+ /* {{{ proto string ldap_dn2ufn(string dn)
+@@ -1298,38 +1532,67 @@
+ /* added to fix use of ldap_modify_add for doing an ldap_add, gerrit thomson. */
+ #define PHP_LD_FULL_ADD 0xff
+ /* {{{ php_ldap_do_modify
+ */
+-static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper)
++static void php_ldap_do_modify(INTERNAL_FUNCTION_PARAMETERS, int oper, int ext)
+ {
+- zval *link, *entry, **value, **ivalue;
++ zval *link, *entry, **value, **ivalue, **sctrls, **cctrls;
+ ldap_linkdata *ld;
+ char *dn;
+ LDAPMod **ldap_mods;
+ int i, j, num_attribs, num_values, dn_len;
+ int *num_berval;
+ char *attribute;
+ ulong index;
+ int is_full_add=0; /* flag for full add operation so ldap_mod_add can be put back into oper, gerrit THomson */
++ int rc, msgid, myargcount = ZEND_NUM_ARGS();
++ LDAPMessage *ldap_res;
++ LDAPControl **lsctrls = NULL, **lcctrls = NULL;
++ if (ext) {
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsaZZ", &link, &dn, &dn_len, &entry, &sctrls, &cctrls) != SUCCESS)
++ WRONG_PARAM_COUNT;
++ } else {
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa", &link, &dn, &dn_len, &entry) != SUCCESS)
++ WRONG_PARAM_COUNT;
++ }
+
+- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsa", &link, &dn, &dn_len, &entry) != SUCCESS) {
+- return;
+- }
++ if (Z_TYPE_PP(&entry) != IS_ARRAY) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected Array as the last element");
++ RETURN_FALSE;
++ }
+
+- ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
+
+- num_attribs = zend_hash_num_elements(Z_ARRVAL_P(entry));
+- ldap_mods = safe_emalloc((num_attribs+1), sizeof(LDAPMod *), 0);
+- num_berval = safe_emalloc(num_attribs, sizeof(int), 0);
+- zend_hash_internal_pointer_reset(Z_ARRVAL_P(entry));
+
+ /* added by gerrit thomson to fix ldap_add using ldap_mod_add */
+ if (oper == PHP_LD_FULL_ADD) {
+ oper = LDAP_MOD_ADD;
+ is_full_add = 1;
+ }
+ /* end additional , gerrit thomson */
+
++ if (myargcount > 3) {
++ if (is_full_add) {
++#ifndef HAVE_LDAP_ADD_EXT_S
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "ldap_add_ext not available");
++ RETURN_FALSE;
++#endif /* ! HAVE_LDAP_ADD_EXT_S */
++
++ } else {
++#ifndef HAVE_LDAP_MODIFY_EXT_S
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "ldap_modify_ext not available");
++ RETURN_FALSE;
++#endif /* ! HAVE_LDAP_MODIFY_EXT_S */
++ }
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
++
++ num_attribs = zend_hash_num_elements(Z_ARRVAL_P(entry));
++ ldap_mods = safe_emalloc((num_attribs+1), sizeof(LDAPMod *), 0);
++ num_berval = safe_emalloc(num_attribs, sizeof(int), 0);
++ zend_hash_internal_pointer_reset(Z_ARRVAL_P(entry));
++
++
+ for (i = 0; i < num_attribs; i++) {
+ ldap_mods[i] = emalloc(sizeof(LDAPMod));
+ ldap_mods[i]->mod_op = oper | LDAP_MOD_BVALUES;
+ ldap_mods[i]->mod_type = NULL;
+@@ -1387,19 +1650,78 @@
+ zend_hash_move_forward(Z_ARRVAL_P(entry));
+ }
+ ldap_mods[num_attribs] = NULL;
+
++ if (ext) {
++ switch (myargcount) {
++ case 5:
++ if (_php_parse_controls(cctrls, &lcctrls) == 0) {
++ RETVAL_FALSE;
++ goto errexit;
++ }
++
++ case 4:
++ if (_php_parse_controls(sctrls, &lsctrls) == 0) {
++ RETVAL_FALSE;
++ goto errexit;
++ }
++ }
++ }
++
+ /* check flag to see if do_mod was called to perform full add , gerrit thomson */
+ if (is_full_add == 1) {
+- if ((i = ldap_add_s(ld->link, dn, ldap_mods)) != LDAP_SUCCESS) {
+- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Add: %s", ldap_err2string(i));
+- RETVAL_FALSE;
+- } else RETVAL_TRUE;
++#ifdef HAVE_LDAP_ADD_EXT_S
++ if (ext) {
++ rc = ldap_add_ext(ld->link, dn, ldap_mods, lsctrls, lcctrls, &msgid);
++
++ } else {
++ rc = ldap_add_ext_s(ld->link, dn, ldap_mods, NULL, NULL);
++ }
++#else /* ! HAVE_LDAP_ADD_EXT_S */
++ rc = ldap_add_s(ld->link, dn, ldap_mods);
++#endif /* ! HAVE_LDAP_ADD_EXT_S */
++
+ } else {
+- if ((i = ldap_modify_ext_s(ld->link, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
+- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Modify: %s", ldap_err2string(i));
+- RETVAL_FALSE;
+- } else RETVAL_TRUE;
++#ifdef HAVE_LDAP_MODIFY_EXT_S
++ if (ext) {
++ rc = ldap_modify_ext(ld->link, dn, ldap_mods, lsctrls, lcctrls, &msgid);
++
++ } else {
++ rc = ldap_modify_ext_s(ld->link, dn, ldap_mods, NULL, NULL);
++ }
++#else /* ! HAVE_LDAP_MODIFY_EXT_S */
++ rc = ldap_modify_s(ld->link, dn, ldap_mods);
++#endif /* ! HAVE_LDAP_MODIFY_EXT_S */
++ }
++
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: %s", is_full_add ? "Add" : "Modify", ldap_err2string(i));
++ RETVAL_FALSE;
++
++ } else {
++ if (ext) {
++ rc = ldap_result(ld->link, msgid, LDAP_MSG_ALL, NULL, &ldap_res);
++ if ((is_full_add && rc != LDAP_RES_ADD) || (!is_full_add && rc != LDAP_RES_MODIFY)) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: unable to collect result", is_full_add ? "Add" : "Modify");
++ RETVAL_FALSE;
++
++ } else {
++ int lerr;
++
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++ rc = ldap_parse_result(ld->link, ldap_res, &lerr, NULL, NULL, NULL, NULL, 0);
++ if (rc == LDAP_SUCCESS) {
++ rc = lerr;
++ }
++
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s failed: %s", is_full_add ? "Add" : "Modify", ldap_err2string(rc));
++ }
++ }
++
++ } else {
++ RETVAL_TRUE;
++ }
+ }
+
+ errexit:
+ for (i = 0; i < num_attribs; i++) {
+@@ -1412,46 +1734,57 @@
+ }
+ efree(num_berval);
+ efree(ldap_mods);
+
++ if (ext) {
++ if (lsctrls) {
++ _php_free_controls(&lsctrls);
++ }
++ if (lcctrls) {
++ _php_free_controls(&lcctrls);
++ }
++ }
++
+ return;
+ }
+ /* }}} */
+
+ /* {{{ proto bool ldap_add(resource link, string dn, array entry)
+ Add entries to LDAP directory */
+ PHP_FUNCTION(ldap_add)
+ {
+- /* use a newly define parameter into the do_modify so ldap_mod_add can be used the way it is supposed to be used , Gerrit THomson */
+- php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_LD_FULL_ADD);
++ /* use a newly define parameter into the do_modify so ldap_mod_add can be used the way it is supposed to be used , Gerrit Thomson */
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_LD_FULL_ADD, 0);
+ }
+ /* }}} */
+
+-/* three functions for attribute base modifications, gerrit Thomson */
++/* {{{ Three functions for attribute base modifications, gerrit Thomson */
+
+ /* {{{ proto bool ldap_mod_replace(resource link, string dn, array entry)
+ Replace attribute values with new ones */
+ PHP_FUNCTION(ldap_mod_replace)
+ {
+- php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_REPLACE);
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_REPLACE, 0);
+ }
+ /* }}} */
+
+ /* {{{ proto bool ldap_mod_add(resource link, string dn, array entry)
+ Add attribute values to current */
+ PHP_FUNCTION(ldap_mod_add)
+ {
+- php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_ADD);
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_ADD, 0);
+ }
+ /* }}} */
+
+ /* {{{ proto bool ldap_mod_del(resource link, string dn, array entry)
++
+ Delete attribute values */
+ PHP_FUNCTION(ldap_mod_del)
+ {
+- php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_DELETE);
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_DELETE, 0);
+ }
+ /* }}} */
++/* }}} */
+
+ /* {{{ proto bool ldap_delete(resource link, string dn)
+ Delete an entry from a directory */
+ PHP_FUNCTION(ldap_delete)
+@@ -1875,38 +2208,109 @@
+ RETURN_STRING(ldap_err2string(ld_errno), 1);
+ }
+ /* }}} */
+
+-/* {{{ proto bool ldap_compare(resource link, string dn, string attr, string value)
+- Determine if an entry has a specific value for one of its attributes */
+-PHP_FUNCTION(ldap_compare)
++/* {{{ proto void php_ldap_do_compare */
++void php_ldap_do_compare(INTERNAL_FUNCTION_PARAMETERS, int ext)
+ {
+- zval *link;
+- char *dn, *attr, *value;
++ zval *link, *dn, *attr, *value, **sctrls, **cctrls;
++ char *ldap_dn, *ldap_attr;
+ int dn_len, attr_len, value_len;
+ ldap_linkdata *ld;
+- int errno;
++ int rc, msgid, lerr, myargcount = ZEND_NUM_ARGS();
++ LDAPMessage *ldap_res;
++ LDAPControl **lsctrls = NULL, **lcctrls = NULL;
+
+- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsss", &link, &dn, &dn_len, &attr, &attr_len, &value, &value_len) != SUCCESS) {
+- return;
++ if (ext) {
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsss|ZZ", &link, &dn, &dn_len, &attr, &attr_len, &value, &value_len, &sctrls, &cctrls) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++ } else {
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsss", &link, &dn, &dn_len, &attr, &attr_len, &value, &value_len) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
+ }
+
+ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
+
+- errno = ldap_compare_s(ld->link, dn, attr, value);
+-
+- switch (errno) {
+- case LDAP_COMPARE_TRUE:
+- RETURN_TRUE;
+- break;
++ if (ext) {
++ struct berval ldap_bvalue;
++ switch (myargcount) {
++ case 6:
++ _php_parse_controls(cctrls, &lcctrls);
++ case 5:
++ _php_parse_controls(sctrls, &lsctrls);
++ }
+
+- case LDAP_COMPARE_FALSE:
++ ldap_bvalue.bv_val = Z_STRVAL_PP(&value);
++ ldap_bvalue.bv_len = Z_STRLEN_PP(&value);
++ rc = ldap_compare_ext(ld->link, ldap_dn, ldap_attr, &ldap_bvalue, lsctrls, lcctrls, &msgid);
++ if (lsctrls) {
++ _php_free_controls(&lsctrls);
++ }
++ if (lcctrls) {
++ _php_free_controls(&lcctrls);
++ }
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Compare: %s", ldap_err2string(rc));
+ RETURN_FALSE;
+- break;
++ }
++
++ rc = ldap_result(ld->link, msgid, LDAP_MSG_ALL, NULL, &ldap_res);
++ if (rc != LDAP_RES_COMPARE) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Compare: unable to get result");
++ RETURN_FALSE;
++ }
++
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++ rc = ldap_parse_result(ld->link, ldap_res, &lerr, NULL, NULL, NULL, NULL, 0);
++ if (rc == LDAP_SUCCESS) {
++ rc = lerr;
++ }
++
++ switch (rc) {
++ case LDAP_COMPARE_TRUE:
++ case LDAP_COMPARE_FALSE:
++ break;
++
++ default:
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Compare failed: %s", ldap_err2string(rc));
++ break;
++ }
++
++ } else {
++#ifdef HAVE_LDAP_COMPARE_EXT_S
++ struct berval ldap_bvalue;
++
++ ldap_bvalue.bv_val = Z_STRVAL_PP(&value);
++ ldap_bvalue.bv_len = Z_STRLEN_PP(&value);
++ rc = ldap_compare_ext_s(ld->link, ldap_dn, ldap_attr, &ldap_bvalue, NULL, NULL);
++#else /* ! HAVE_LDAP_COMPARE_EXT_S */
++ char *ldap_value;
++
++ ldap_value = Z_STRVAL_PP(&value);
++ rc = ldap_compare_s(ld->link, ldap_dn, ldap_attr, ldap_value);
++#endif /* ! HAVE_LDAP_COMPARE_EXT_S */
++
++ switch (rc) {
++ case LDAP_COMPARE_TRUE:
++ RETURN_TRUE;
++ break;
++
++ case LDAP_COMPARE_FALSE:
++ RETURN_FALSE;
++ break;
++ }
++
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Compare: %s", ldap_err2string(rc));
++ RETURN_LONG(-1);
+ }
+-
+- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Compare: %s", ldap_err2string(errno));
+- RETURN_LONG(-1);
++}
++/* {{{ proto bool ldap_compare(resource link, string dn, string attr, string valu)
++ Determine if an entry has a specific value for one of its attributes */
++PHP_FUNCTION(ldap_compare)
++{
++ php_ldap_do_compare(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+ }
+ /* }}} */
+
+ /* {{{ proto bool ldap_sort(resource link, resource result, string sortfilter)
+@@ -1938,59 +2342,233 @@
+ RETURN_TRUE;
+ }
+ /* }}} */
+
+-#if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP
+-/* {{{ proto bool ldap_get_option(resource link, int option, mixed retval)
+- Get the current value of various session-wide parameters */
+-PHP_FUNCTION(ldap_get_option)
++/* {{{ Extended API that returns result instead of just bool
++ * to allow further manipulation by the ldap_parse_*() funcs,
++ * Pierangelo Masarati */
++
++/* {{{ proto result ldap_bind_ext(resource link [, string dn, string password])
++ Bind to LDAP directory */
++PHP_FUNCTION(ldap_bind_ext)
+ {
+- zval *link, *retval;
++ zval *link;
++ char *ldap_bind_dn = NULL, *ldap_bind_pw = NULL;
++ int ldap_bind_dnlen, ldap_bind_pwlen;
+ ldap_linkdata *ld;
+- long option;
+-
+- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &link, &option, &retval) != SUCCESS) {
+- return;
++ int rc, msgid, lerr;
++ LDAPMessage *ldap_res;
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|ss", &link, &ldap_bind_dn, &ldap_bind_dnlen, &ldap_bind_pw, &ldap_bind_pwlen) == FAILURE) {
++
++ RETURN_FALSE;
+ }
+
+ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
+
+- switch (option) {
+- /* options with int value */
+- case LDAP_OPT_DEREF:
+- case LDAP_OPT_SIZELIMIT:
+- case LDAP_OPT_TIMELIMIT:
+- case LDAP_OPT_PROTOCOL_VERSION:
+- case LDAP_OPT_ERROR_NUMBER:
+- case LDAP_OPT_REFERRALS:
+-#ifdef LDAP_OPT_RESTART
+- case LDAP_OPT_RESTART:
++#ifdef LDAP_API_FEATURE_X_OPENLDAP
++ {
++ struct berval cred;
++
++ /* ldap_bind() is deprecated; use ldap_sasl_bind() instead */
++ cred.bv_val = ldap_bind_pw;
++ cred.bv_len = ldap_bind_pw ? ldap_bind_pwlen : 0;
++
++ rc = ldap_sasl_bind(ld->link, ldap_bind_dn, LDAP_SASL_SIMPLE, &cred,
++ NULL, NULL, /* no controls right now */
++ &msgid);
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind: %s", ldap_err2string(rc));
++ RETURN_FALSE;
++ }
++ }
++#else
++ msgid = ldap_bind(ld->link, ldap_bind_dn, ldap_bind_pw, LDAP_AUTH_SIMPLE);
++ if (msgid == -1) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind");
++ RETURN_FALSE;
++ }
+ #endif
+- {
+- int val;
+
+- if (ldap_get_option(ld->link, option, &val)) {
+- RETURN_FALSE;
+- }
+- zval_dtor(retval);
+- ZVAL_LONG(retval, val);
+- } break;
+-#ifdef LDAP_OPT_NETWORK_TIMEOUT
+- case LDAP_OPT_NETWORK_TIMEOUT:
+- {
+- struct timeval *timeout = NULL;
++ rc = ldap_result(ld->link, msgid, LDAP_MSG_ALL, NULL, &ldap_res);
++ if (rc != LDAP_RES_BIND) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to get bind result: %s", ldap_err2string(rc));
++ RETURN_FALSE;
++ }
+
+- if (ldap_get_option(ld->link, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
+- if (timeout) {
+- ldap_memfree(timeout);
+- }
+- RETURN_FALSE;
+- }
+- if (!timeout) {
+- RETURN_FALSE;
+- }
+- zval_dtor(retval);
+- ZVAL_LONG(retval, timeout->tv_sec);
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++ rc = ldap_parse_result(ld->link, ldap_res, &lerr, NULL, NULL, NULL, NULL, 0);
++ if (rc == LDAP_SUCCESS) {
++ rc = lerr;
++ }
++
++
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc));
++ }
++}
++/* }}} */
++
++/* {{{ proto result ldap_add_ext(resource link, string dn, array entry)
++ Add entries to LDAP directory; returns result */
++PHP_FUNCTION(ldap_add_ext)
++{
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_LD_FULL_ADD, 1);
++}
++/* }}} */
++
++/* {{{ proto result ldap_mod_replace_ext(resource link, string dn, array entry)
++ Replace attribute values with new ones */
++PHP_FUNCTION(ldap_mod_replace_ext)
++{
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_REPLACE, 1);
++}
++/* }}} */
++
++
++/* {{{ proto result ldap_mod_add_ext(resource link, string dn, array entry)
++ Add attribute values to current */
++PHP_FUNCTION(ldap_mod_add_ext)
++{
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_ADD, 1);
++}
++/* }}} */
++
++/* {{{ proto result ldap_mod_del_ext(resource link, string dn, array entry)
++ Delete attribute values */
++PHP_FUNCTION(ldap_mod_del_ext)
++{
++ php_ldap_do_modify(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_MOD_DELETE, 1);
++}
++/* }}} */
++
++/* {{{ proto result ldap_delete_ext(resource link, string dn)
++ Delete an entry from a directory */
++PHP_FUNCTION(ldap_delete_ext)
++{
++ zval **link, **dn, **sctrls, **cctrls;
++ ldap_linkdata *ld;
++ char *ldap_dn;
++ int rc, dn_len, msgid, lerr, myargcount = ZEND_NUM_ARGS();
++ LDAPMessage *ldap_res;
++ LDAPControl **lsctrls = NULL, **lcctrls = NULL;
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|ZZ", &link, &dn, &dn_len, &sctrls, &cctrls) == FAILURE) {
++ WRONG_PARAM_COUNT;
++ }
++
++ switch (myargcount) {
++ case 4:
++ _php_parse_controls(cctrls, &lcctrls);
++
++ case 3:
++ _php_parse_controls(sctrls, &lsctrls);
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++
++ convert_to_string_ex(dn);
++ ldap_dn = Z_STRVAL_PP(dn);
++
++#ifdef HAVE_LDAP_DELETE_EXT_S
++ rc = ldap_delete_ext_s(ld->link, ldap_dn, NULL, NULL);
++#else /* ! HAVE_LDAP_DELETE_EXT_S */
++ rc = ldap_delete_s(ld->link, ldap_dn);
++#endif /* ! HAVE_LDAP_DELETE_EXT_S */
++ if (lsctrls) {
++ _php_free_controls(&lsctrls);
++ }
++ if (lcctrls) {
++ _php_free_controls(&lcctrls);
++ }
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Delete: %s", ldap_err2string(rc));
++ RETURN_FALSE;
++ }
++
++ rc = ldap_result(ld->link, msgid, LDAP_MSG_ALL, NULL, &ldap_res);
++ if (rc != LDAP_RES_DELETE) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Delete: unable to get result");
++ RETURN_FALSE;
++ }
++
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++ rc = ldap_parse_result(ld->link, ldap_res, &lerr, NULL, NULL, NULL, NULL, 0);
++ if (rc == LDAP_SUCCESS) {
++ rc = lerr;
++ }
++
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Delete failed: %s", ldap_err2string(rc));
++ }
++}
++/* }}} */
++
++/* }}} End of extended API, Pierangelo Masarati */
++
++
++/* {{{ proto result ldap_compare_ext(resource link, string dn, string attr, string value)
++ Determine if an entry has a specific value for one of its attributes */
++PHP_FUNCTION(ldap_compare_ext)
++{
++ php_ldap_do_compare(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
++}
++/* }}} */
++
++/* }}} End of extended API, Pierangelo Masarati */
++
++
++#if (LDAP_API_VERSION > 2000) || HAVE_NSLDAP || HAVE_ORALDAP_10
++/* {{{ proto bool ldap_get_option(resource link, int option, mixed retval)
++ Get the current value of various session-wide parameters */
++PHP_FUNCTION(ldap_get_option)
++{
++ zval *link, *retval;
++ ldap_linkdata *ld;
++ long option;
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &link, &option, &retval) != SUCCESS) {
++ return;
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
++
++ switch (option) {
++ /* options with int value */
++ case LDAP_OPT_DEREF:
++ case LDAP_OPT_SIZELIMIT:
++ case LDAP_OPT_TIMELIMIT:
++ case LDAP_OPT_PROTOCOL_VERSION:
++ case LDAP_OPT_ERROR_NUMBER:
++ case LDAP_OPT_REFERRALS:
++#ifdef LDAP_OPT_RESTART
++ case LDAP_OPT_RESTART:
++#endif
++ {
++ int val;
++
++ if (ldap_get_option(ld->link, option, &val)) {
++ RETURN_FALSE;
++ }
++ zval_dtor(retval);
++ ZVAL_LONG(retval, val);
++ } break;
++#ifdef LDAP_OPT_NETWORK_TIMEOUT
++ case LDAP_OPT_NETWORK_TIMEOUT:
++ {
++ struct timeval *timeout = NULL;
++
++ if (ldap_get_option(ld->link, LDAP_OPT_NETWORK_TIMEOUT, (void *) &timeout)) {
++ if (timeout) {
++ ldap_memfree(timeout);
++ }
++ RETURN_FALSE;
++ }
++ if (!timeout) {
++ RETURN_FALSE;
++ }
++ zval_dtor(retval);
++ ZVAL_LONG(retval, timeout->tv_sec);
+ ldap_memfree(timeout);
+ } break;
+ #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
+ case LDAP_X_OPT_CONNECT_TIMEOUT:
+@@ -2213,21 +2791,23 @@
+ }
+ /* }}} */
+
+ #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;
+ ldap_linkdata *ld;
+ LDAPMessage *ldap_result;
+- char **lreferrals, **refp;
++ LDAPControl **lserverctrls;
++ char **lreferrals;
+ char *lmatcheddn, *lerrmsg;
+ int rc, lerrcode, myargcount = ZEND_NUM_ARGS();
++ /* int matcheddn_len, errmsg_len; */
+
+- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz|zzz", &link, &result, &errcode, &matcheddn, &errmsg, &referrals) != SUCCESS) {
+- return;
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rrz|zzzz", &link, &result, &errcode, &matcheddn, &errmsg, &referrals, &serverctrls) != SUCCESS) {
++ WRONG_PARAM_COUNT;
+ }
+
+ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
+ ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
+@@ -2235,9 +2815,9 @@
+ rc = ldap_parse_result(ld->link, ldap_result, &lerrcode,
+ 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));
+ RETURN_FALSE;
+@@ -2247,19 +2827,15 @@
+ ZVAL_LONG(errcode, lerrcode);
+
+ /* 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);
++ _php_parse_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);
+- }
++ _php_parse_referrals_resp(&lreferrals, &referrals);
+ case 5:
+ zval_dtor(errmsg);
+ if (lerrmsg == NULL) {
+ ZVAL_EMPTY_STRING(errmsg);
+@@ -2280,8 +2856,142 @@
+ }
+ /* }}} */
+ #endif
+
++/* {{{ Extended operation response parsing, Pierangelo Masarati */
++#ifdef HAVE_LDAP_PARSE_EXTENDED_RESULT
++/* {{{ proto bool ldap_parse_exop(resource link, resource result [, string retoid [, string retdata]])
++ Extract information from extended operation result */
++PHP_FUNCTION(ldap_parse_exop)
++{
++ zval *link, *result, *retoid, *retdata;
++ ldap_linkdata *ld;
++ LDAPMessage *ldap_result;
++ char *lretoid;
++ struct berval *lretdata;
++ int rc, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|zz", &link, &result, &retoid, &retdata) == SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link);
++ ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, &result, -1, "ldap result", le_result);
++
++ rc = ldap_parse_extended_result(ld->link, ldap_result,
++ myargcount > 2 ? &lretoid: NULL,
++ myargcount > 3 ? &lretdata: NULL,
++ 0);
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse extended operation result: %s", ldap_err2string(rc));
++ RETURN_FALSE;
++ }
++
++ /* Reverse -> fall through */
++ switch (myargcount) {
++ case 4:
++ /* use arg #4 as the data returned by the server */
++ zval_dtor(retdata);
++ if (lretdata == NULL) {
++ ZVAL_EMPTY_STRING(retdata);
++ } else {
++ ZVAL_STRINGL(retdata, lretdata->bv_val, lretdata->bv_len, 1);
++ ldap_memfree(lretdata->bv_val);
++ ldap_memfree(lretdata);
++ }
++ case 3:
++ zval_dtor(retoid);
++ if (lretoid == NULL) {
++ ZVAL_EMPTY_STRING(retoid);
++ } else {
++ ZVAL_STRING(retoid, lretoid, 1);
++ ldap_memfree(lretoid);
++ }
++ }
++ RETURN_TRUE;
++}
++/* }}} */
++
++#ifdef HAVE_LDAP_PARSE_PASSWD
++/* {{{ proto bool ldap_parse_exop_passwd(resource link, resource result, string newpasswd)
++ Extract information from RFC 3062 password modify extended operation result */
++PHP_FUNCTION(ldap_parse_exop_passwd)
++{
++ zval **link, **result, **newpasswd;
++ ldap_linkdata *ld;
++ LDAPMessage *ldap_result;
++ struct berval lnewpasswd;
++ int rc, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ", &link, &result, &newpasswd) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, result, -1, "ldap result", le_result);
++
++ rc = ldap_parse_passwd(ld->link, ldap_result, &lnewpasswd);
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse passwd modify extended operation result: %s", ldap_err2string(rc));
++ RETURN_FALSE;
++ }
++
++ zval_dtor(*newpasswd);
++ if (lnewpasswd.bv_len == 0) {
++ ZVAL_EMPTY_STRING(*newpasswd);
++ } else {
++ ZVAL_STRINGL(*newpasswd, lnewpasswd.bv_val, lnewpasswd.bv_len, 1);
++ ldap_memfree(lnewpasswd.bv_val);
++ }
++
++ RETURN_TRUE;
++}
++#else
++/* TODO: implement based on ldap_parse_exop() */
++/* }}} */
++#endif
++
++#ifdef HAVE_LDAP_PARSE_WHOAMI
++/* {{{ proto bool ldap_parse_exop_whoami(resource link, resource result, string authzid)
++ Extract information from <draft-zeilenga-ldap-authzid> whoami extended operation result (a Work in Progress) */
++PHP_FUNCTION(ldap_parse_exop_whoami)
++{
++ zval **link, **result, **authzid;
++ ldap_linkdata *ld;
++ LDAPMessage *ldap_result;
++ struct berval *lauthzid;
++ int rc, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ", &link, &result, &authzid) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, result, -1, "ldap result", le_result);
++
++ rc = ldap_parse_whoami(ld->link, ldap_result, &lauthzid );
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse whoami extended operation result: %s", ldap_err2string(rc));
++ RETURN_FALSE;
++ }
++
++ zval_dtor(*authzid);
++ if (lauthzid == NULL) {
++ ZVAL_EMPTY_STRING(*authzid);
++ } else {
++ ZVAL_STRINGL(*authzid, lauthzid->bv_val, lauthzid->bv_len, 1);
++ ldap_memfree(lauthzid->bv_val);
++ ldap_memfree(lauthzid);
++ }
++ RETURN_TRUE;
++}
++#else
++/* TODO: implement based on ldap_parse_extended_result() */
++/* }}} */
++#endif
++/* }}} */
++#endif
++
+ /* {{{ proto resource ldap_first_reference(resource link, resource result)
+ Return first reference */
+ PHP_FUNCTION(ldap_first_reference)
+ {
+@@ -2841,53 +3551,735 @@
+ }
+ /* }}} */
+ #endif
+
+-/* {{{ arginfo */
+-ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_connect, 0, 0, 0)
+- ZEND_ARG_INFO(0, hostname)
+- ZEND_ARG_INFO(0, port)
+-#ifdef HAVE_ORALDAP
+- ZEND_ARG_INFO(0, wallet)
+- ZEND_ARG_INFO(0, wallet_passwd)
+- ZEND_ARG_INFO(0, authmode)
+-#endif
+-ZEND_END_ARG_INFO()
++/* {{{ Extended operations, Pierangelo Masarati */
++#ifdef HAVE_LDAP_EXTENDED_OPERATION_S
++/* {{{ proto ? ldap_exop(resource link, string reqoid [, string reqdata [, string retoid [, string retdata]]])
++ Extended operation */
++PHP_FUNCTION(ldap_exop)
++{
++ zval **link, **reqoid, **reqdata, **retoid, **retdata;
++ char *lreqoid, *lretoid = NULL;
++ struct berval lreqdata, *lretdata = NULL;
++ ldap_linkdata *ld;
++ LDAP *ldap;
++ LDAPMessage *ldap_res;
++ int rc, msgid, myargcount = ZEND_NUM_ARGS();
++ /* int reqoid_len, reqdata_len, retdata_len, retoid_len, retdat_len; */
+
+-ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_resource, 0, 0, 1)
+- ZEND_ARG_INFO(0, link_identifier)
+-ZEND_END_ARG_INFO()
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|ZZZ", &link, &reqoid, &reqdata, &retoid, &retdata) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
+
+-ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_bind, 0, 0, 1)
+- ZEND_ARG_INFO(0, link_identifier)
+- ZEND_ARG_INFO(0, bind_rdn)
+- ZEND_ARG_INFO(0, bind_password)
+-ZEND_END_ARG_INFO()
++ if (Z_TYPE_PP(link) == IS_NULL) {
++ ldap = NULL;
++ } else {
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ldap = ld->link;
++ }
+
+-#ifdef HAVE_LDAP_SASL
+-ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_sasl_bind, 0, 0, 1)
+- ZEND_ARG_INFO(0, link)
+- ZEND_ARG_INFO(0, binddn)
+- ZEND_ARG_INFO(0, password)
+- ZEND_ARG_INFO(0, sasl_mech)
+- ZEND_ARG_INFO(0, sasl_realm)
+- ZEND_ARG_INFO(0, sasl_authz_id)
+- ZEND_ARG_INFO(0, props)
+-ZEND_END_ARG_INFO()
+-#endif
++ switch (myargcount) {
++ case 5:
++ case 4:
++ case 3:
++ convert_to_string_ex(reqdata);
++ lreqdata.bv_val = Z_STRVAL_PP(reqdata);
++ lreqdata.bv_len = Z_STRLEN_PP(reqdata);
++ /* fallthru */
++ case 2:
++ convert_to_string_ex(reqoid);
++ lreqoid = Z_STRVAL_PP(reqoid);
++ }
++
++ if (myargcount > 3) {
++ /* synchronous call */
++ rc = ldap_extended_operation_s(ld->link, lreqoid,
++ lreqdata.bv_len > 0 ? &lreqdata: NULL,
++ NULL,
++ NULL,
++ &lretoid,
++ myargcount > 4 ? &lretdata : NULL );
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Extended operation %s failed: %s (%d)", lreqoid, ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
+
+-ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_read, 0, 0, 3)
+- ZEND_ARG_INFO(0, link_identifier)
+- ZEND_ARG_INFO(0, base_dn)
+- ZEND_ARG_INFO(0, filter)
+- ZEND_ARG_INFO(0, attributes)
+- ZEND_ARG_INFO(0, attrsonly)
+- ZEND_ARG_INFO(0, sizelimit)
+- ZEND_ARG_INFO(0, timelimit)
+- ZEND_ARG_INFO(0, deref)
+-ZEND_END_ARG_INFO()
++ /* Reverse -> fall through */
++ switch (myargcount) {
++ case 5:
++ /* use arg #4 as the data returned by the server */
++ zval_dtor(*retdata);
++ if (lretdata == NULL) {
++ ZVAL_EMPTY_STRING(*retdata);
++ } else {
++ ZVAL_STRINGL(*retdata, lretdata->bv_val, lretdata->bv_len, 1);
++ ldap_memfree(lretdata->bv_val);
++ ldap_memfree(lretdata);
++ }
++ case 4:
++ zval_dtor(*retoid);
++ if (lretoid == NULL) {
++ ZVAL_EMPTY_STRING(*retoid);
++ } else {
++ ZVAL_STRING(*retoid, lretoid, 1);
++ ldap_memfree(lretoid);
++ }
++ }
+
+-ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_list, 0, 0, 3)
++ RETURN_TRUE;
++ }
++
++ /* asynchronous call */
++ rc = ldap_extended_operation(ld->link, lreqoid,
++ lreqdata.bv_len > 0 ? &lreqdata: NULL,
++ NULL, NULL, &msgid);
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Extended operation %s failed: %s (%d)", lreqoid, ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ rc = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
++ if (rc == -1) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Extended operation %s failed", lreqoid);
++ RETURN_FALSE;
++ }
++
++ /* return a PHP control object */
++ array_init(return_value);
++
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++}
++/* }}} */
++
++#ifdef HAVE_LDAP_PASSWD_S
++/* {{{ proto ? ldap_exop_passwd(resource link [, string user [, string oldpw [, string newpw [, string newpasswd ]]]])
++ Passwd modify extended operation */
++PHP_FUNCTION(ldap_exop_passwd)
++{
++ zval **link, **user, **newpw, **oldpw, **newpasswd;
++ struct berval luser, loldpw, lnewpw, lnewpasswd;
++ ldap_linkdata *ld;
++ LDAP *ldap;
++ LDAPMessage *ldap_res;
++ int rc, msgid, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|ZZZZ", &link, &user, &oldpw, &newpw, &newpasswd) == FAILURE) {
++ WRONG_PARAM_COUNT;
++ }
++
++ if (Z_TYPE_PP(link) == IS_NULL) {
++ ldap = NULL;
++ } else {
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ldap = ld->link;
++ }
++
++ luser.bv_len = 0;
++ loldpw.bv_len = 0;
++ lnewpw.bv_len = 0;
++
++ switch (myargcount) {
++ case 5:
++ case 4:
++ convert_to_string_ex(newpw);
++ lnewpw.bv_val = Z_STRVAL_PP(newpw);
++ lnewpw.bv_len = Z_STRLEN_PP(newpw);
++
++ case 3:
++ convert_to_string_ex(oldpw);
++ loldpw.bv_val = Z_STRVAL_PP(oldpw);
++ loldpw.bv_len = Z_STRLEN_PP(oldpw);
++
++ case 2:
++ convert_to_string_ex(user);
++ luser.bv_val = Z_STRVAL_PP(user);
++ luser.bv_len = Z_STRLEN_PP(user);
++ }
++
++ if (myargcount > 4 || lnewpw.bv_len > 0) {
++ /* synchronous call */
++ rc = ldap_passwd_s(ld->link, &luser,
++ loldpw.bv_len > 0 ? &loldpw : NULL,
++ /* loldpw.bv_len > 0 ? &loldpw : NULL, */
++ lnewpw.bv_len > 0 ? &lnewpw : NULL,
++ &lnewpasswd, NULL, NULL);
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passwd modify extended operation failed: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ if (myargcount > 4) {
++ zval_dtor(*newpasswd);
++ if (lnewpasswd.bv_len == 0) {
++ ZVAL_EMPTY_STRING(*newpasswd);
++ } else {
++ ZVAL_STRINGL(*newpasswd, lnewpasswd.bv_val, lnewpasswd.bv_len, 1);
++ }
++ }
++
++ ldap_memfree(lnewpasswd.bv_val);
++
++ RETURN_TRUE;
++ }
++
++ /* asynchronous call */
++ rc = ldap_passwd(ld->link, &luser,
++ loldpw.bv_len > 0 ? &loldpw : NULL,
++ lnewpw.bv_len > 0 ? &lnewpw : NULL,
++ NULL, NULL, &msgid);
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passwd modify extended operation failed: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ rc = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
++ if (rc == -1) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passwd modify extended operation failed");
++ RETURN_FALSE;
++ }
++
++ /* return a PHP control object */
++ array_init(return_value);
++
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++}
++#else
++/* TODO: implement based on ldap_extended_operation_s() */
++/* }}} */
++#endif
++
++#ifdef HAVE_LDAP_WHOAMI_S
++/* {{{ proto bool ldap_exop_whoami(resource link [, string authzid])
++ Whoami extended operation */
++PHP_FUNCTION(ldap_exop_whoami)
++{
++ zval **link, **authzid;
++ struct berval *lauthzid;
++ ldap_linkdata *ld;
++ LDAP *ldap;
++ LDAPMessage *ldap_res;
++ int rc, msgid, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|Z", &link, &authzid) == FAILURE) {
++ WRONG_PARAM_COUNT;
++ }
++
++ if (Z_TYPE_PP(link) == IS_NULL) {
++ ldap = NULL;
++ } else {
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ldap = ld->link;
++ }
++
++ if (myargcount == 2) {
++ /* synchronous call */
++ rc = ldap_whoami_s(ld->link, &lauthzid, NULL, NULL);
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Whoami extended operation failed: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ zval_dtor(*authzid);
++ if (lauthzid == NULL) {
++ ZVAL_EMPTY_STRING(*authzid);
++ } else {
++ ZVAL_STRINGL(*authzid, lauthzid->bv_val, lauthzid->bv_len, 1);
++ ldap_memfree(lauthzid->bv_val);
++ ldap_memfree(lauthzid);
++ }
++
++ RETURN_TRUE;
++ }
++
++ /* asynchronous call */
++ rc = ldap_whoami(ld->link, NULL, NULL, &msgid);
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Whoami extended operation failed: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ rc = ldap_result(ld->link, msgid, 1 /* LDAP_MSG_ALL */, NULL, &ldap_res);
++ if (rc == -1) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Whoami extended operation failed");
++ RETURN_FALSE;
++ }
++
++ /* return a PHP control object */
++ array_init(return_value);
++
++ ZEND_REGISTER_RESOURCE(return_value, ldap_res, le_result);
++}
++#else
++/* TODO: implement based on ldap_extended_operation_s() */
++#endif
++/* }}} */
++#endif
++/* }}} */
++
++/* {{{ LDAP controls encoding/decoding, Pierangelo Masarati */
++/* {{{ php_set_no_value_server_ctrl
++ */
++void php_set_no_value_server_ctrl(INTERNAL_FUNCTION_PARAMETERS, const char *oid, const char *msg)
++{
++ zval **link, **iscritical;
++ ldap_linkdata *ld;
++ LDAP *ldap;
++ LDAPControl ctrl = { 0 }, *ctrlsp[2];
++ int rc, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|Z", &link, &iscritical) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ if (Z_TYPE_PP(link) == IS_NULL) {
++ ldap = NULL;
++
++ } else {
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ldap = ld->link;
++ }
++
++ if (myargcount == 2) {
++ convert_to_boolean_ex(iscritical);
++ ctrl.ldctl_iscritical = Z_BVAL_PP(iscritical);
++ }
++
++ ctrl.ldctl_oid = (char *)oid;
++
++ if (ldap) {
++ /* directly set the option */
++ ctrlsp[0] = &ctrl;
++ ctrlsp[1] = NULL;
++
++ rc = ldap_set_option(ldap, LDAP_OPT_SERVER_CONTROLS, ctrlsp);
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set %s control: %s (%d)", msg, ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ } else {
++ /* return a PHP control object */
++ array_init(return_value);
++
++ add_assoc_string(return_value, "oid", ctrl.ldctl_oid, 1);
++ if (ctrl.ldctl_iscritical) {
++ add_assoc_bool(return_value, "iscritical", ctrl.ldctl_iscritical);
++ }
++ }
++
++ RETURN_TRUE;
++}
++/* }}} */
++
++#ifdef LDAP_CONTROL_MANAGEDSAIT
++/* {{{ proto bool ldap_ctrl_manageDSAit(resource link [, bool iscritical])
++ Inject manageDSAit control */
++PHP_FUNCTION(ldap_ctrl_manageDSAit)
++{
++ php_set_no_value_server_ctrl(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_CONTROL_MANAGEDSAIT, "manageDSAit");
++}
++/* }}} */
++#endif
++
++#ifdef LDAP_CONTROL_PAGEDRESULTS
++/* {{{ proto bool ldap_ctrl_paged_results(resource link, int pagesize [, bool iscritical [, string cookie]])
++ Inject paged results control*/
++PHP_FUNCTION(ldap_ctrl_paged_results)
++{
++ zval **link, **pagesize, **iscritical, **cookie;
++ int lpagesize = 0;
++ struct berval lcookie = { 0, NULL };
++ ldap_linkdata *ld;
++ LDAP *ldap;
++ BerElement *ber = NULL;
++ LDAPControl ctrl, *ctrlsp[2];
++ int rc, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|ZZ", &link, &pagesize, &iscritical, &cookie) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ if (Z_TYPE_PP(link) == IS_NULL) {
++ ldap = NULL;
++ } else {
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ldap = ld->link;
++ }
++
++ ber = ber_alloc_t(LBER_USE_DER);
++ if (ber == NULL) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to alloc BER encoding resources for paged results control");
++ RETURN_FALSE;
++ }
++
++ ctrl.ldctl_iscritical = 0;
++
++ switch (myargcount) {
++ case 4:
++ convert_to_string_ex(cookie);
++ lcookie.bv_val = Z_STRVAL_PP(cookie);
++ lcookie.bv_len = Z_STRLEN_PP(cookie);
++ /* fallthru */
++ case 3:
++ convert_to_boolean_ex(iscritical);
++ ctrl.ldctl_iscritical = Z_BVAL_PP(iscritical);
++ /* fallthru */
++ }
++ convert_to_long_ex(pagesize);
++ lpagesize = Z_LVAL_PP(pagesize);
++
++ ber_printf(ber, "{iO}", lpagesize, &lcookie );
++ rc = ber_flatten2( ber, &ctrl.ldctl_value, 0 );
++ if ( rc == -1 ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to BER encode paged results control");
++ RETURN_FALSE;
++ }
++
++ ctrl.ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
++
++ if (ldap) {
++ /* directly set the option */
++ ctrlsp[0] = &ctrl;
++ ctrlsp[1] = NULL;
++
++ rc = ldap_set_option(ldap, LDAP_OPT_SERVER_CONTROLS, ctrlsp);
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set paged results control: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ } else {
++ /* return a PHP control object */
++ array_init(return_value);
++
++ add_assoc_string(return_value, "oid", ctrl.ldctl_oid, 1);
++ if ( ctrl.ldctl_value.bv_len ) {
++ add_assoc_stringl(return_value, "value", ctrl.ldctl_value.bv_val, ctrl.ldctl_value.bv_len, 1);
++ }
++ if (ctrl.ldctl_iscritical) {
++ add_assoc_bool(return_value, "iscritical", ctrl.ldctl_iscritical);
++ }
++ }
++
++ if (ber != NULL) {
++ ber_free(ber, 1);
++ }
++}
++/* }}} */
++
++/* {{{ proto bool ldap_ctrl_paged_results_resp(resource link, resource result [, string cookie [, int estimated]])
++ Extract paged results control response */
++PHP_FUNCTION(ldap_ctrl_paged_results_resp)
++{
++ zval **link, **result, **cookie, **estimated;
++ struct berval lcookie;
++ int lestimated;
++ ldap_linkdata *ld;
++ LDAPMessage *ldap_result;
++ LDAPControl **lserverctrls, *lctrl;
++ BerElement *ber;
++ ber_tag_t tag;
++ int rc, lerrcode, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|ZZ", &link, &result, &cookie, &estimated) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, result, -1, "ldap result", le_result);
++
++ rc = ldap_parse_result(ld->link,
++ ldap_result,
++ &lerrcode,
++ NULL, /* matcheddn */
++ NULL, /* errmsg */
++ NULL, /* referrals */
++ &lserverctrls,
++ 0);
++
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse result: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ if (lerrcode != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result is: %s (%d)", ldap_err2string(lerrcode), lerrcode);
++ RETURN_FALSE;
++ }
++
++ if (lserverctrls == NULL) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No server controls in result");
++ RETURN_FALSE;
++ }
++
++ lctrl = ldap_find_control(LDAP_CONTROL_PAGEDRESULTS, lserverctrls);
++ if (lctrl == NULL) {
++ ldap_controls_free(lserverctrls);
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No paged results control response in result");
++ RETURN_FALSE;
++ }
++
++ ber = ber_init(&lctrl->ldctl_value);
++ if (ber == NULL) {
++ ldap_controls_free(lserverctrls);
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to alloc BER decoding resources for paged results control response");
++ RETURN_FALSE;
++ }
++
++ tag = ber_scanf(ber, "{io}", &lestimated, &lcookie );
++ (void)ber_free(ber, 1);
++
++ if (tag == LBER_ERROR) {
++ ldap_controls_free(lserverctrls);
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to decode paged results control response");
++ RETURN_FALSE;
++ }
++
++ if (lestimated < 0) {
++ ldap_controls_free(lserverctrls);
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid paged results control response value");
++ RETURN_FALSE;
++ }
++
++ ldap_controls_free(lserverctrls);
++
++ if (myargcount == 4) {
++ zval_dtor(*estimated);
++ ZVAL_LONG(*estimated, lestimated);
++ }
++
++ zval_dtor(*cookie);
++ if (lcookie.bv_len == 0) {
++ ZVAL_EMPTY_STRING(*cookie);
++ } else {
++ ZVAL_STRINGL(*cookie, lcookie.bv_val, lcookie.bv_len, 1);
++ }
++ ldap_memfree(lcookie.bv_val);
++
++ RETURN_TRUE;
++}
++/* }}} */
++#endif
++
++#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
++/* {{{ proto bool ldap_ctrl_ppolicy(resource link [, bool iscritical])
++ Inject password policy control */
++PHP_FUNCTION(ldap_ctrl_ppolicy)
++{
++ php_set_no_value_server_ctrl(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_CONTROL_PASSWORDPOLICYREQUEST, "passwordPolicy");
++}
++/* }}} */
++
++/* {{{ proto bool ldap_ctrl_ppolicy_resp(resource link, resource result [, expire [, grace [, error[, errmsg]]]])
++ Extract password policy control response */
++PHP_FUNCTION(ldap_ctrl_ppolicy_resp)
++{
++ zval **link, **result, **ppexpire, **ppgrace, **pperror, **pperrmsg;
++ int lexpire, lgrace;
++ LDAPPasswordPolicyError lerror;
++ ldap_linkdata *ld;
++ LDAPMessage *ldap_result;
++ LDAPControl **lserverctrls, *lctrl;
++ int rc, pperrmsg_len, lerrcode, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|ZZZZ", &link, &result, &ppexpire, &ppgrace, &pperror, &pperrmsg) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, link, -1, "ldap link", le_link);
++ ZEND_FETCH_RESOURCE(ldap_result, LDAPMessage *, result, -1, "ldap result", le_result);
++
++ rc = ldap_parse_result(ld->link,
++ ldap_result,
++ &lerrcode,
++ NULL, /* matcheddn */
++ NULL, /* errmsg */
++ NULL, /* referrals */
++ &lserverctrls,
++ 0);
++
++ if (rc != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse result: %s (%d)", ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ if (lerrcode != LDAP_SUCCESS && lerrcode != LDAP_INVALID_CREDENTIALS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result is: %s (%d)", ldap_err2string(lerrcode), lerrcode);
++ RETURN_FALSE;
++ }
++
++ if (lserverctrls == NULL) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No server controls in result");
++ RETURN_FALSE;
++ }
++
++ lctrl = ldap_find_control(LDAP_CONTROL_PASSWORDPOLICYRESPONSE, lserverctrls);
++ if (lctrl == NULL) {
++ ldap_controls_free(lserverctrls);
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No password policy control response in result");
++ RETURN_FALSE;
++ }
++
++ lerrcode = ldap_parse_passwordpolicy_control(ld->link, lctrl, &lexpire, &lgrace, &lerror);
++ ldap_controls_free(lserverctrls);
++ if (lerrcode != LDAP_SUCCESS) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to parse password policy control response: %s (%d)", ldap_err2string(lerrcode), lerrcode);
++ RETURN_FALSE;
++ }
++
++ switch (myargcount) {
++ case 6:
++ zval_dtor(*pperrmsg);
++ ZVAL_STRING(*pperrmsg, (char *)ldap_passwordpolicy_err2txt(lerror), 1);
++
++ case 5:
++ zval_dtor(*pperror);
++ ZVAL_LONG(*pperror, (long)lerror);
++
++ case 4:
++ zval_dtor(*ppgrace);
++ ZVAL_LONG(*ppgrace, (long)lgrace);
++ }
++
++ zval_dtor(*ppexpire);
++ ZVAL_LONG(*ppexpire, (long)lexpire);
++
++ RETURN_TRUE;
++}
++/* }}} */
++#endif
++
++#ifdef LDAP_CONTROL_NOOP
++/* {{{ proto bool ldap_ctrl_noop(resource link, bool iscritical)
++ Inject control*/
++PHP_FUNCTION(ldap_ctrl_noop)
++{
++ php_set_no_value_server_ctrl(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_CONTROL_NOOP, "no-op");
++}
++/* }}} */
++#endif
++
++#ifdef LDAP_CONTROL_MANAGEDIT
++/* {{{ proto bool ldap_ctrl_manageDIT(resource link [, bool iscritical])
++ Inject control*/
++PHP_FUNCTION(ldap_ctrl_manageDIT)
++{
++ php_set_no_value_server_ctrl(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_CONTROL_MANAGEDIT, "manageDIT");
++}
++/* }}} */
++#endif
++
++#ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY
++/* {{{ proto bool ldap_ctrl_permissive_modify(resource link [, bool iscritical])
++ Inject control*/
++PHP_FUNCTION(ldap_ctrl_permissive_modify)
++{
++ php_set_no_value_server_ctrl(INTERNAL_FUNCTION_PARAM_PASSTHRU, LDAP_CONTROL_X_PERMISSIVE_MODIFY, "permissive modify");
++}
++/* }}} */
++#endif
++/* }}} */
++
++#ifdef HAVE_LDAP_REFRESH
++/* {{{ proto ? ldap_refresh(resource link , string dn , int ttl, [int *newttl])
++ DDS refresh extended operation */
++PHP_FUNCTION(ldap_refresh)
++{
++ zval **link, **dn, **ttl, **newttl;
++ struct berval ldn;
++ ber_int_t lttl;
++ ber_int_t lnewttl;
++ ldap_linkdata *ld;
++ LDAP *ldap;
++ LDAPMessage *ldap_res;
++ int rc, msgid, myargcount = ZEND_NUM_ARGS();
++
++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|Z", &link, &dn, &ttl, &newttl) != SUCCESS) {
++ WRONG_PARAM_COUNT;
++ }
++
++ if (Z_TYPE_PP(link) == IS_NULL) {
++ ldap = NULL;
++ } else {
++ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *,
++ link, -1, "ldap link", le_link);
++ ldap = ld->link;
++ }
++
++ ldn.bv_len = 0;
++ convert_to_string_ex(dn);
++ ldn.bv_val = Z_STRVAL_PP(dn);
++ ldn.bv_len = Z_STRLEN_PP(dn);
++
++ convert_to_long_ex(ttl);
++ lttl = (ber_int_t)Z_LVAL_PP(ttl);
++
++ /* asynchronous call */
++ rc = ldap_refresh_s(ld->link, &ldn, lttl, &lnewttl, NULL, NULL);
++ if (rc != LDAP_SUCCESS ) {
++ php_error_docref(NULL TSRMLS_CC, E_WARNING,
++ "Refresh extended operation failed: %s (%d)",
++ ldap_err2string(rc), rc);
++ RETURN_FALSE;
++ }
++
++ if (myargcount == 4) {
++ zval_dtor(*newttl);
++ ZVAL_LONG(*newttl, (long)lnewttl);
++ }
++ RETURN_TRUE;
++}
++#else
++/* TODO: implement based on ldap_extended_operation_s() */
++/* }}} */
++#endif
++
++/* {{{ arginfo */
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_connect, 0, 0, 0)
++ ZEND_ARG_INFO(0, hostname)
++ ZEND_ARG_INFO(0, port)
++#ifdef HAVE_ORALDAP
++ ZEND_ARG_INFO(0, wallet)
++ ZEND_ARG_INFO(0, wallet_passwd)
++ ZEND_ARG_INFO(0, authmode)
++#endif
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_resource, 0, 0, 1)
++ ZEND_ARG_INFO(0, link_identifier)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_bind, 0, 0, 1)
++ ZEND_ARG_INFO(0, link_identifier)
++ ZEND_ARG_INFO(0, bind_rdn)
++ ZEND_ARG_INFO(0, bind_password)
++ZEND_END_ARG_INFO()
++
++#ifdef HAVE_LDAP_SASL
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_sasl_bind, 0, 0, 1)
++ ZEND_ARG_INFO(0, link)
++ ZEND_ARG_INFO(0, binddn)
++ ZEND_ARG_INFO(0, password)
++ ZEND_ARG_INFO(0, sasl_mech)
++ ZEND_ARG_INFO(0, sasl_realm)
++ ZEND_ARG_INFO(0, sasl_authz_id)
++ ZEND_ARG_INFO(0, props)
++ZEND_END_ARG_INFO()
++#endif
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_read, 0, 0, 3)
++ ZEND_ARG_INFO(0, link_identifier)
++ ZEND_ARG_INFO(0, base_dn)
++ ZEND_ARG_INFO(0, filter)
++ ZEND_ARG_INFO(0, attributes)
++ ZEND_ARG_INFO(0, attrsonly)
++ ZEND_ARG_INFO(0, sizelimit)
++ ZEND_ARG_INFO(0, timelimit)
++ ZEND_ARG_INFO(0, deref)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_list, 0, 0, 3)
+ ZEND_ARG_INFO(0, link_identifier)
+ ZEND_ARG_INFO(0, base_dn)
+ ZEND_ARG_INFO(0, filter)
+ ZEND_ARG_INFO(0, attributes)
+@@ -3090,8 +4482,9 @@
+ ZEND_ARG_INFO(1, errcode)
+ 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
+
+@@ -3116,8 +4509,40 @@
+ ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_8859_to_t61, 0, 0, 1)
+ ZEND_ARG_INFO(0, value)
+ ZEND_END_ARG_INFO()
+ #endif
++
++#ifdef HAVE_LDAP_EXTENDED_OPERATION_S
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_exop, 0, 0, 5)
++ ZEND_ARG_INFO(0, link)
++ ZEND_ARG_INFO(0, reqoid)
++ ZEND_ARG_INFO(1, reqdata)
++ ZEND_ARG_INFO(1, repoid)
++ ZEND_ARG_INFO(1, repdata)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_exop_passwd, 0, 0, 5)
++ ZEND_ARG_INFO(0, link)
++ ZEND_ARG_INFO(1, user)
++ ZEND_ARG_INFO(1, oldpw)
++ ZEND_ARG_INFO(1, newpw)
++ ZEND_ARG_INFO(1, newpasswd)
++ZEND_END_ARG_INFO()
++
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_exop_whoami, 0, 0, 2)
++ ZEND_ARG_INFO(0, link)
++ ZEND_ARG_INFO(1, authzid)
++ZEND_END_ARG_INFO()
++#endif
++
++#ifdef HAVE_LDAP_REFRESH
++ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_refresh, 0, 0, 4)
++ ZEND_ARG_INFO(0, link)
++ ZEND_ARG_INFO(0, dn)
++ ZEND_ARG_INFO(1, ttl)
++ ZEND_ARG_INFO(0, newttl)
++ZEND_END_ARG_INFO()
++#endif
+ /* }}} */
+
+ /*
+ This is just a small subset of the functionality provided by the LDAP library. All the
+@@ -3180,9 +4605,22 @@
+ #endif
+ #ifdef HAVE_LDAP_START_TLS_S
+ PHP_FE(ldap_start_tls, arginfo_ldap_resource)
+ #endif
++#ifdef HAVE_LDAP_EXTENDED_OPERATION_S
++ PHP_FE(ldap_exop,
++ arginfo_ldap_exop)
++ PHP_FE(ldap_exop_passwd,
++ arginfo_ldap_exop_passwd)
++ PHP_FE(ldap_exop_whoami,
++ arginfo_ldap_exop_whoami)
++#endif
++#ifdef HAVE_LDAP_REFRESH
++ PHP_FE(ldap_refresh,
++ arginfo_ldap_refresh)
+ #endif
++#endif
++
+
+ #if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
+ PHP_FE(ldap_set_rebind_proc, arginfo_ldap_set_rebind_proc)
+ #endif
+@@ -3193,8 +4631,33 @@
+ PHP_FE(ldap_t61_to_8859, arginfo_ldap_t61_to_8859)
+ PHP_FE(ldap_8859_to_t61, arginfo_ldap_8859_to_t61)
+ #endif
+
++/* routines to handle standard track controls, Pierangelo Masarati */
++#ifdef LDAP_CONTROL_MANAGEDSAIT
++ PHP_FE(ldap_ctrl_manageDSAit, NULL)
++#endif
++#ifdef LDAP_CONTROL_PAGEDRESULTS
++ PHP_FE(ldap_ctrl_paged_results, NULL) /* fourth_arg_force_ref */
++ PHP_FE(ldap_ctrl_paged_results_resp, NULL) /* arg3to4of4_force_ref */
++#endif
++#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
++ PHP_FE(ldap_ctrl_ppolicy, NULL)
++ PHP_FE(ldap_ctrl_ppolicy_resp, NULL) /* arg3to6of6_force_ref */
++#endif
++#ifdef LDAP_CONTROL_NOOP
++ PHP_FE(ldap_ctrl_noop, NULL)
++#endif
++#ifdef LDAP_CONTROL_MANAGEDIT
++ PHP_FE(ldap_ctrl_manageDIT, NULL)
++#endif
++#ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY
++ PHP_FE(ldap_ctrl_permissive_modify, NULL)
++#endif
++/* end of ando mod */
++
++
++
+ #ifdef LDAP_CONTROL_PAGEDRESULTS
+ PHP_FE(ldap_control_paged_result, arginfo_ldap_control_paged_result)
+ PHP_FE(ldap_control_paged_result_response, arginfo_ldap_control_paged_result_response)
+ #endif
+@@ -3219,8 +4682,10 @@
+ STANDARD_MODULE_PROPERTIES_EX
+ };
+ /* }}} */
+
++
++
+ /*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+--- ext/ldap/php_ldap.h.orig 2015-03-19 01:19:30.000000000 +0100
++++ ext/ldap/php_ldap.h 2015-04-13 05:48:10.000000000 +0200
+@@ -28,16 +28,148 @@
+ #endif
+
+ #include <ldap.h>
+
++#define HAVE_3ARG_SETREBINDPROC
++#define HAVE_LDAP_ADD_EXT_S
++#define HAVE_LDAP_MODIFY_EXT_S
++#define HAVE_LDAP_COMPARE_EXT_S
++#define HAVE_LDAP_DELETE_EXT_S
++#define HAVE_LDAP_PARSE_EXTENDED_RESULT
++#define HAVE_LDAP_PARSE_PASSWD
++#define HAVE_LDAP_PARSE_WHOAMI
++#define HAVE_LDAP_EXTENDED_OPERATION_S
++#define HAVE_LDAP_PASSWD_S
++#define HAVE_LDAP_WHOAMI_S
++#define HAVE_LDAP_REFRESH
++#define HAVE_LDAP_SASL
++#define HAVE_LDAP_EXTENDED_OPERATION_S
++#define HAVE_LDAP_REFRESH
++#define HAVE_LDAP_EXTENDED_OPERATION_S
++#define HAVE_LDAP_REFRESH
++#define HAVE_LDAP_EXTENDED_OPERATION
++
+ extern zend_module_entry ldap_module_entry;
+ #define ldap_module_ptr &ldap_module_entry
+
+ /* LDAP functions */
+ PHP_MINIT_FUNCTION(ldap);
+ PHP_MSHUTDOWN_FUNCTION(ldap);
+ PHP_MINFO_FUNCTION(ldap);
+
++#ifdef HAVE_LDAP_EXTENDED_OPERATION
++
++#endif
++
++#ifdef LDAP_CONTROL_MANAGEDSAIT
++/* RFC 3296 */
++PHP_FUNCTION(ldap_ctrl_manageDSAit);
++#endif
++#ifdef LDAP_CONTROL_PROXY_AUTHZ
++/* <draft-weltman-ldapv3-proxy> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_proxy_authz);
++#endif
++#ifdef LDAP_CONTROL_SUBENTRIES
++/* RFC 3672 */
++PHP_FUNCTION(ldap_ctrl_subentries);
++#endif
++#ifdef LDAP_CONTROL_VALUESRETURNFILTER
++/* RFC 3876 */
++PHP_FUNCTION(ldap_ctrl_vlv);
++#endif
++#ifdef LDAP_CONTROL_ASSERT
++/* <draft-zeilenga-ldap-assert> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_assert);
++#endif
++#ifdef LDAP_CONTROL_PRE_READ
++/* <draft-zeilenga-ldap-readentry> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_preread);
++PHP_FUNCTION(ldap_ctrl_postread);
++#endif
++#ifdef LDAP_CONTROL_SORTREQUEST
++/* RFC 2891 */
++PHP_FUNCTION(ldap_ctrl_sort);
++PHP_FUNCTION(ldap_ctrl_sort_resp);
++#endif
++#ifdef LDAP_CONTROL_PAGEDRESULTS
++/* RFC 2696 */
++PHP_FUNCTION(ldap_ctrl_paged_results);
++PHP_FUNCTION(ldap_ctrl_paged_results_resp);
++#endif
++#ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
++/* <draft-behera-ldap-password-policy> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_ppolicy);
++PHP_FUNCTION(ldap_ctrl_ppolicy_resp);
++#endif
++#ifdef LDAP_CONTROL_NOOP
++/* <draft-zeilenga-ldap-noop> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_noop);
++#endif
++#ifdef LDAP_CONTROL_NO_SUBORDINATES
++/* don't know anything about it */
++#endif
++#ifdef LDAP_CONTROL_MANAGEDIT
++/* no spec; partially implemented in OpenLDAP 2.3 */
++PHP_FUNCTION(ldap_ctrl_manageDIT);
++#endif
++#ifdef LDAP_CONTROL_SLURP
++/* don't know anything about it */
++#endif
++#ifdef LDAP_CONTROL_VALSORT
++/* <> */
++PHP_FUNCTION(ldap_ctrl_valsort);
++#endif
++#ifdef LDAP_CONTROL_SYNC
++/* <draft-zeilenga-ldup-sync> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_sync);
++PHP_FUNCTION(ldap_ctrl_sync_state);
++PHP_FUNCTION(ldap_ctrl_sync_done);
++/* TODO: need to handle the SYNC intermediate response message (LDAPIRM) */
++#endif
++#ifdef LDAP_CONTROL_X_CHAINING_BEHAVIOR
++/* <draft-sermersheim-ldap-chaining> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_chaining);
++#endif
++#ifdef LDAP_CONTROL_X_INCREMENTAL_VALUES
++/* MS Active Directory */
++PHP_FUNCTION(ldap_ctrl_incremental_values);
++#endif
++#ifdef LDAP_CONTROL_X_DOMAIN_SCOPE
++/* MS Active Directory */
++PHP_FUNCTION(ldap_ctrl_domain_scope);
++#endif
++#ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY
++/* MS Active Directory */
++PHP_FUNCTION(ldap_ctrl_permissive_modify);
++#endif
++#ifdef LDAP_CONTROL_X_SEARCH_OPTIONS
++/* MS Active Directory */
++PHP_FUNCTION(ldap_ctrl_search_options);
++#endif
++#ifdef LDAP_CONTROL_X_TREE_DELETE
++/* MS Active Directory */
++PHP_FUNCTION(ldap_ctrl_tree_delete);
++#endif
++#ifdef LDAP_CONTROL_X_EXTENDED_DN
++/* MS Active Directory */
++PHP_FUNCTION(ldap_ctrl_extended_dn);
++#endif
++#ifdef LDAP_CONTROL_DUPENT
++/* <draft-ietf-ldapext-ldapv3-dupent> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_dupent);
++PHP_FUNCTION(ldap_ctrl_dupent_resp);
++PHP_FUNCTION(ldap_ctrl_dupent_done_resp);
++#endif
++#ifdef LDAP_CONTROL_PERSIST_REQUEST
++/* ? */
++#endif
++#ifdef LDAP_CONTROL_VLVREQUEST
++/* <draft-ietf-ldapext-ldapv3-vlv> (a Work in Progress) */
++PHP_FUNCTION(ldap_ctrl_vlv);
++PHP_FUNCTION(ldap_ctrl_vlv_resp);
++#endif
++
++
+ ZEND_BEGIN_MODULE_GLOBALS(ldap)
+ long num_links;
+ long max_links;
+ ZEND_END_MODULE_GLOBALS(ldap)
diff --git a/databases/php-ldap/options.mk b/databases/php-ldap/options.mk
index 15bd8d3710d..90cb61b06f5 100644
--- a/databases/php-ldap/options.mk
+++ b/databases/php-ldap/options.mk
@@ -1,4 +1,4 @@
-# $NetBSD: options.mk,v 1.3 2011/04/13 13:23:05 adam Exp $
+# $NetBSD: options.mk,v 1.4 2015/04/13 08:04:17 manu Exp $
PKG_OPTIONS_VAR= PKG_OPTIONS.php-ldap
PKG_SUPPORTED_OPTIONS= sasl exop
@@ -15,7 +15,7 @@ CONFIGURE_ARGS+= --with-ldap-sasl=${PREFIX}
.if !empty(PKG_OPTIONS:Mexop)
USE_TOOLS+= patch
-EXOP_PATCH= ${FILESDIR}/ldap-ctrl-exop.patch
+EXOP_PATCH= ${FILESDIR}/ldap-ctrl-exop${PKG_PHP_VERSION}.patch
post-patch:
${PATCH} -d ${WRKSRC} -p2 --forward --quiet < ${EXOP_PATCH}
.endif