1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

ext/ldap: Use FCC for rebind_proc callback (#17369)

This commit is contained in:
Gina Peter Banyard
2025-01-08 20:52:33 +00:00
committed by GitHub
parent 1ec95c33e8
commit 915feea12d
4 changed files with 108 additions and 75 deletions

View File

@@ -73,7 +73,7 @@ void ldap_memvfree(void **v)
typedef struct {
LDAP *link;
#if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
zval rebindproc;
zend_fcall_info_cache rebind_proc_fcc;
#endif
zend_object std;
} ldap_linkdata;
@@ -131,7 +131,9 @@ static void ldap_link_free(ldap_linkdata *ld)
ld->link = NULL;
#if defined(LDAP_API_FEATURE_X_OPENLDAP) && defined(HAVE_3ARG_SETREBINDPROC)
zval_ptr_dtor(&ld->rebindproc);
if (ZEND_FCC_INITIALIZED(ld->rebind_proc_fcc)) {
zend_fcc_dtor(&ld->rebind_proc_fcc);
}
#endif
LDAPG(num_links)--;
@@ -3711,7 +3713,7 @@ int _ldap_rebind_proc(LDAP *ldap, const char *url, ber_tag_t req, ber_int_t msgi
}
/* link exists and callback set? */
if (Z_ISUNDEF(ld->rebindproc)) {
if (!ZEND_FCC_INITIALIZED(ld->rebind_proc_fcc)) {
php_error_docref(NULL, E_WARNING, "No callback set");
return LDAP_OTHER;
}
@@ -3719,11 +3721,12 @@ int _ldap_rebind_proc(LDAP *ldap, const char *url, ber_tag_t req, ber_int_t msgi
/* callback */
ZVAL_COPY_VALUE(&cb_args[0], cb_link);
ZVAL_STRING(&cb_args[1], url);
if (call_user_function(EG(function_table), NULL, &ld->rebindproc, &cb_retval, 2, cb_args) == SUCCESS && !Z_ISUNDEF(cb_retval)) {
zend_call_known_fcc(&ld->rebind_proc_fcc, &cb_retval, 2, cb_args, NULL);
if (EXPECTED(!Z_ISUNDEF(cb_retval))) {
// TODO Use zval_try_get_long()
retval = zval_get_long(&cb_retval);
zval_ptr_dtor(&cb_retval);
} else {
php_error_docref(NULL, E_WARNING, "rebind_proc PHP callback failed");
retval = LDAP_OTHER;
}
zval_ptr_dtor(&cb_args[1]);
@@ -3735,35 +3738,35 @@ int _ldap_rebind_proc(LDAP *ldap, const char *url, ber_tag_t req, ber_int_t msgi
PHP_FUNCTION(ldap_set_rebind_proc)
{
zval *link;
zend_fcall_info fci;
zend_fcall_info_cache fcc;
zend_fcall_info dummy_fci;
zend_fcall_info_cache fcc = empty_fcall_info_cache;
ldap_linkdata *ld;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Of!", &link, ldap_link_ce, &fci, &fcc) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "OF!", &link, ldap_link_ce, &dummy_fci, &fcc) == FAILURE) {
RETURN_THROWS();
}
ld = Z_LDAP_LINK_P(link);
VERIFY_LDAP_LINK_CONNECTED(ld);
if (!ZEND_FCI_INITIALIZED(fci)) {
/* unregister rebind procedure */
if (!Z_ISUNDEF(ld->rebindproc)) {
zval_ptr_dtor(&ld->rebindproc);
ZVAL_UNDEF(&ld->rebindproc);
ldap_set_rebind_proc(ld->link, NULL, NULL);
}
RETURN_TRUE;
/* Inline VERIFY_LDAP_LINK_CONNECTED(ld); as we need to free trampoline */
if (!ld->link) {
zend_release_fcall_info_cache(&fcc);
zend_throw_error(NULL, "LDAP connection has already been closed");
RETURN_THROWS();
}
/* register rebind procedure */
if (Z_ISUNDEF(ld->rebindproc)) {
/* Free old FCC */
if (!ZEND_FCC_INITIALIZED(ld->rebind_proc_fcc)) {
zend_fcc_dtor(&ld->rebind_proc_fcc);
}
if (ZEND_FCC_INITIALIZED(fcc)) {
/* register rebind procedure */
ldap_set_rebind_proc(ld->link, _ldap_rebind_proc, (void *) link);
zend_fcc_dup(&ld->rebind_proc_fcc, &fcc);
} else {
zval_ptr_dtor(&ld->rebindproc);
}
/* unregister rebind procedure */
ldap_set_rebind_proc(ld->link, NULL, NULL);
}
ZVAL_COPY(&ld->rebindproc, &fci.function_name);
RETURN_TRUE;
}
/* }}} */

View File

@@ -12,22 +12,31 @@ require_once('skipifbindfailure.inc');
?>
--FILE--
<?php
/*** NOTE: THE CALLBACK IS NOT CALLED AS WE DON'T TEST THE REBINDING HAPPENS AS WE NEED MULTIPLE LDAP SERVERS ***/
require "connect.inc";
function rebind_proc ($ds, $ldap_url) {
global $user;
global $passwd;
global $protocol_version;
function rebind_proc ($ldap, $referral) {
global $user;
global $passwd;
global $protocol_version;
// required by most modern LDAP servers, use LDAPv3
ldap_set_option($a, LDAP_OPT_PROTOCOL_VERSION, $protocol_version);
// required by most modern LDAP servers, use LDAPv3
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, $protocol_version);
if (!ldap_bind($a, $user, $passwd)) {
if (!ldap_bind($ldap, $user, $passwd)) {
// Failure
print "Cannot bind";
}
return 1;
}
// Success
return 0;
}
$link = ldap_connect_and_bind($uri, $user, $passwd, $protocol_version);
ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($link, LDAP_OPT_REFERRALS, true);
var_dump(ldap_set_rebind_proc($link, "rebind_proc"));
var_dump(ldap_set_rebind_proc($link, null));
?>

View File

@@ -1,44 +0,0 @@
--TEST--
ldap_set_rebind_proc() - Testing ldap_set_rebind_proc() that should fail
--CREDITS--
Patrick Allaert <patrickallaert@php.net>
# Belgian PHP Testfest 2009
--EXTENSIONS--
ldap
--SKIPIF--
<?php
if (!function_exists("ldap_set_rebind_proc")) {
die("skip ldap_set_rebind_proc() does not exist");
}
require "connect.inc";
$link = @fsockopen($uri);
if (!$link) {
die("skip no server listening");
}
?>
--FILE--
<?php
require "connect.inc";
function rebind_proc ($ds, $ldap_url) {
global $user;
global $passwd;
global $protocol_version;
// required by most modern LDAP servers, use LDAPv3
ldap_set_option($a, LDAP_OPT_PROTOCOL_VERSION, $protocol_version);
if (!ldap_bind($a, $user, $passwd)) {
print "Cannot bind";
}
}
$link = ldap_connect($uri);
try {
$result = ldap_set_rebind_proc($link, "rebind_proc_inexistent");
} catch(\TypeError $error) {
echo $error->getMessage(), "\n";
}
?>
--EXPECT--
ldap_set_rebind_proc(): Argument #2 ($callback) must be a valid callback or null, function "rebind_proc_inexistent" not found or invalid function name

View File

@@ -0,0 +1,65 @@
--TEST--
ldap_set_rebind_proc() with a trampoline
--EXTENSIONS--
ldap
--SKIPIF--
<?php
if (!function_exists('ldap_set_rebind_proc')) die("skip ldap_set_rebind_proc() not available");
require_once('skipifbindfailure.inc');
?>
--FILE--
<?php
/*** NOTE: THE TRAMPOLINE IS NOT CALLED AS WE DON'T TEST THE REBINDING HAPPENS AS WE NEED MULTIPLE LDAP SERVERS ***/
require "connect.inc";
class TrampolineTest {
public function __construct(private $user, private $password, private $protocol_version) {}
public function __call(string $name, array $arguments) {
echo 'Trampoline for ', $name, PHP_EOL;
var_dump(count($arguments));
if ($name === 'trampolineThrow') {
throw new Exception('boo');
}
if ($name === 'trampolineWrongType') {
return ['not an int'];
}
// required by most modern LDAP servers, use LDAPv3
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, $this->$protocol_version);
if (!ldap_bind($ldap, $this->$user, $this->$password)) {
// Failure
print "Cannot bind";
return 1;
}
// Success
return 0;
}
}
$o = new TrampolineTest($user, $passwd, $protocol_version);
$callback = [$o, 'trampoline'];
$callbackThrow = [$o, 'trampolineThrow'];
$callbackWrongType = [$o, 'trampolineWrongType'];
$link = ldap_connect_and_bind($uri, $user, $passwd, $protocol_version);
var_dump(ldap_set_rebind_proc($link, $callback));
var_dump(ldap_set_rebind_proc($link, null));
var_dump(ldap_set_rebind_proc($link, $callbackThrow));
var_dump(ldap_set_rebind_proc($link, null));
var_dump(ldap_set_rebind_proc($link, $callbackWrongType));
var_dump(ldap_unbind($link));
try {
var_dump(ldap_set_rebind_proc($link, $callback));
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}
?>
--EXPECT--
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
Error: LDAP connection has already been closed