This patch provides misc cleanup of the LDAP extension of PHP according to the current status and evolution trends of the OpenLDAP API as of 2.3 and above. It is intended for PHP HEAD code as of December 2005, but it is known to apply without relevant issues to PHP 5 and 4. It __should__ be backward compatible at least with OpenLDAP 2.2. All requested features are detected at compile time, so it __should__ not cause problem with any other LDAP API; simply, the extensions will not be available. Author: Pierangelo Masarati , This software is released under the terms of the PHP license for inclusion in PHP software. Index: ext/ldap/ldap.c =================================================================== RCS file: /repository/php-src/ext/ldap/ldap.c,v retrieving revision 1.163 diff -u -r1.163 ldap.c --- ext/ldap/ldap.c 6 Dec 2005 02:24:38 -0000 1.163 +++ ext/ldap/ldap.c 10 Dec 2005 14:45:08 -0000 @@ -191,13 +253,19 @@ { 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)--; } @@ -370,7 +513,13 @@ { 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, *walletpasswd; int walletlen, walletpasswdlen; @@ -406,21 +555,39 @@ 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() ius 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:%ld", host ? host : "", port ? port : LDAP_PORT ); + } - rc = ldap_initialize(&ldap, host); + rc = ldap_initialize(&ldap, url); if (rc != LDAP_SUCCESS) { efree(ld); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not create session handle: %s", ldap_err2string(rc)); RETURN_FALSE; } - } else { - ldap = ldap_init(host, port); + + if (url != host) { + efree(url); + } } -#else +#else /* ! LDAP_API_FEATURE_X_OPENLDAP */ ldap = ldap_open(host, port); -#endif +#endif /* ! LDAP_API_FEATURE_X_OPENLDAP */ if (ldap == NULL) { efree(ld); @@ -479,7 +646,21 @@ ZEND_FETCH_RESOURCE(ld, ldap_linkdata *, &link, -1, "ldap link", le_link); - if ((rc = ldap_bind_s(ld->link, ldap_bind_dn, ldap_bind_pw, LDAP_AUTH_SIMPLE)) != LDAP_SUCCESS) { +#ifdef LDAP_API_FEATURE_X_OPENLDAP + { + struct berval cred; + + /* ldap_bind_s() is deprecated; use ldap_sasl_bind_s() instead */ + cred.bv_val = ldap_bind_pw; + cred.bv_len = ldap_bind_pw ? ldap_bind_pwlen : 0; + rc = ldap_sasl_bind_s(ld->link, ldap_bind_dn, LDAP_SASL_SIMPLE, &cred, + NULL, NULL, /* no controls right now */ + NULL); /* we don't care about the server's credentials */ + } +#else + rc = ldap_bind_s(ld->link, ldap_bind_dn, ldap_bind_pw, LDAP_AUTH_SIMPLE); +#endif + if ( rc != LDAP_SUCCESS) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to bind to server: %s", ldap_err2string(rc)); RETURN_FALSE; } else { @@ -1030,7 +1211,6 @@ BerElement *ber; char *attribute; size_t attr_len; - char **ldap_value; char *dn; if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &link, &result) == FAILURE) { @@ -1061,16 +1241,22 @@ attribute = ldap_first_attribute(ldap, ldap_result_entry, &ber); while (attribute != NULL) { - ldap_value = ldap_get_values(ldap, ldap_result_entry, attribute); - num_values = ldap_count_values(ldap_value); + struct berval **ldap_value; + + /* ldap_get_values() is deprecated, because it cannot deal + * with non-null terminated string values; always use + * the *_len() variant instead, which __should__ be portable + * and is safe regardless of the actual data being returned. */ + ldap_value = ldap_get_values_len(ldap, ldap_result_entry, attribute); + num_values = ldap_count_values_len(ldap_value); MAKE_STD_ZVAL(tmp2); array_init(tmp2); add_assoc_long(tmp2, "count", num_values); for (i = 0; i < num_values; i++) { - add_index_string(tmp2, i, ldap_value[i], 1); + add_index_stringl(tmp2, i, ldap_value[i]->bv_val, ldap_value[i]->bv_len, 1); } - ldap_value_free(ldap_value); + ldap_value_free_len(ldap_value); attr_len = strlen(attribute); zend_hash_update(Z_ARRVAL_P(tmp1), php_strtolower(attribute, attr_len), attr_len+1, (void *) &tmp2, sizeof(zval *), NULL); @@ -1177,7 +1363,6 @@ ldap_linkdata *ld; ldap_resultentry *resultentry; char *attribute; - char **ldap_value; int i, num_values, num_attrib; BerElement *ber; @@ -1193,16 +1378,18 @@ attribute = ldap_first_attribute(ld->link, resultentry->data, &ber); while (attribute != NULL) { - ldap_value = ldap_get_values(ld->link, resultentry->data, attribute); - num_values = ldap_count_values(ldap_value); + struct berval **ldap_value; + + ldap_value = ldap_get_values_len(ld->link, resultentry->data, attribute); + num_values = ldap_count_values_len(ldap_value); MAKE_STD_ZVAL(tmp); array_init(tmp); add_assoc_long(tmp, "count", num_values); for (i = 0; i < num_values; i++) { - add_index_string(tmp, i, ldap_value[i], 1); + add_index_stringl(tmp, i, ldap_value[i]->bv_val, ldap_value[i]->bv_len, 1); } - ldap_value_free(ldap_value); + ldap_value_free_len(ldap_value); zend_hash_update(Z_ARRVAL_P(return_value), attribute, strlen(attribute)+1, (void *) &tmp, sizeof(zval *), NULL); add_index_string(return_value, num_attrib, attribute, 1); @@ -1231,7 +1418,7 @@ ldap_linkdata *ld; ldap_resultentry *resultentry; char *attribute; - char **ldap_value; + struct berval **ldap_value; int i, num_values; if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &link, &result_entry, &attr) == FAILURE) { @@ -1244,21 +1431,21 @@ convert_to_string_ex(attr); attribute = Z_STRVAL_PP(attr); - if ((ldap_value = ldap_get_values(ld->link, resultentry->data, attribute)) == NULL) { + if ((ldap_value = ldap_get_values_len(ld->link, resultentry->data, attribute)) == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot get the value(s) of attribute %s", ldap_err2string(_get_lderrno(ld->link))); RETURN_FALSE; } - num_values = ldap_count_values(ldap_value); + num_values = ldap_count_values_len(ldap_value); array_init(return_value); for (i = 0; ibv_val, ldap_value[i]->bv_len, 1); } add_assoc_long(return_value, "count", num_values); - ldap_value_free(ldap_value); + ldap_value_free_len(ldap_value); } /* }}} */ @@ -1363,7 +1550,12 @@ 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 */ } /* }}} */