diff -urN ../z-push-2.6.2+0.orig/src/backend/searchldap/config.php ./src/backend/searchldap/config.php --- ../z-push-2.6.2+0.orig/src/backend/searchldap/config.php 2021-02-04 03:38:38.000000000 +0200 +++ ./src/backend/searchldap/config.php 2022-01-30 13:35:50.442340000 +0200 @@ -26,6 +26,18 @@ // LDAP server uri define("LDAP_SERVER_URI", "ldap://127.0.0.1:389/"); +//define("LDAP_START_TLS", false); + +//define("LDAP_SERVER_URI", "ldaps://127.0.0.1:636/"); +//define("LDAP_DISABLE_REFERRALS", true); + +// Multi servers settings +//define("LDAP_SERVER_CONF", array( +// "ldap://127.0.0.1:389/", +// array("LDAP_SERVER_URI" => "ldap://192.168.1.1:3268/", "LDAP_START_TLS" => true), +// array("LDAP_SERVER_URI" => "ldaps://127.0.0.1:636/", "LDAP_START_TLS" => false, "LDAP_DISABLE_REFERRALS" => true) +//)); +//define("LDAP_BIND_TIMEOUT", 10); // Set USER and PASSWORD if not using anonymous bind define("ANONYMOUS_BIND", true); diff -urN ../z-push-2.6.2+0.orig/src/backend/searchldap/searchldap.php ./src/backend/searchldap/searchldap.php --- ../z-push-2.6.2+0.orig/src/backend/searchldap/searchldap.php 2021-02-04 03:38:38.000000000 +0200 +++ ./src/backend/searchldap/searchldap.php 2023-09-26 20:11:27.701668000 +0300 @@ -44,34 +44,145 @@ throw new StatusException("BackendSearchLDAP(): php-ldap is not installed. Search aborted.", SYNC_SEARCHSTATUS_STORE_SERVERERROR, null, LOGLEVEL_FATAL); } - // Connect - if (defined('LDAP_SERVER_URI')) { - $this->connection = @ldap_connect(LDAP_SERVER_URI); - @ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, 3); + if (defined('LDAP_SERVER_CONF') and (is_array(LDAP_SERVER_CONF))) { + $ldap_server_conf = LDAP_SERVER_CONF; } else { - $this->connection = false; - throw new StatusException("BackendSearchLDAP(): No LDAP server URI defined! Search aborted.", SYNC_SEARCHSTATUS_STORE_CONNECTIONFAILED, null, LOGLEVEL_ERROR); + $ldap_server_conf_item = array(); + if (defined('LDAP_SERVER_URI')) { + $ldap_server_conf_item['LDAP_SERVER_URI'] = LDAP_SERVER_URI; + } else { + $this->connection = false; + throw new StatusException("BackendSearchLDAP(): No LDAP server URI defined. Search aborted.", SYNC_SEARCHSTATUS_STORE_CONNECTIONFAILED, null, LOGLEVEL_ERROR); + } + if (defined('LDAP_DISABLE_REFERRALS') and (constant('LDAP_DISABLE_REFERRALS') === true)) { + $ldap_server_conf_item['LDAP_DISABLE_REFERRALS'] = true; + } + if (defined('LDAP_START_TLS') and (constant('LDAP_START_TLS') === true)) { + $ldap_server_conf_item['LDAP_START_TLS'] = true; + } + $ldap_server_conf = array($ldap_server_conf_item); } - // Authenticate - if (constant('ANONYMOUS_BIND') === true) { - if(! @ldap_bind($this->connection)) { + ZLog::Write(LOGLEVEL_DEBUG, "\$ldap_server_conf: " . print_r($ldap_server_conf, true)); + + while ($ldap_server_conf_item = array_shift($ldap_server_conf)) { + if (!is_array($ldap_server_conf_item)) { + $ldap_server_conf_item = array('LDAP_SERVER_URI' => $ldap_server_conf_item); + } + if (!isset($ldap_server_conf_item['ANONYMOUS_BIND'])) { + $ldap_server_conf_item['ANONYMOUS_BIND'] = (defined('ANONYMOUS_BIND') and (constant('ANONYMOUS_BIND') === true) ? true : false); + } + if (!isset($ldap_server_conf_item['LDAP_BIND_USER']) and defined('LDAP_BIND_USER')) { + $ldap_server_conf_item['LDAP_BIND_USER'] = LDAP_BIND_USER; + } + if (!isset($ldap_server_conf_item['LDAP_BIND_PASSWORD']) and defined('LDAP_BIND_PASSWORD')) { + $ldap_server_conf_item['LDAP_BIND_PASSWORD'] = LDAP_BIND_PASSWORD; + } + if (!isset($ldap_server_conf_item['LDAP_BIND_TIMEOUT']) and defined('LDAP_BIND_TIMEOUT')) { + $ldap_server_conf_item['LDAP_BIND_TIMEOUT'] = LDAP_BIND_TIMEOUT; + } + + ZLog::Write(LOGLEVEL_DEBUG, "\$ldap_server_conf_item: " . print_r($ldap_server_conf_item, true)); + + // Connect + if (empty($ldap_server_conf_item['LDAP_SERVER_URI'])) { $this->connection = false; - throw new StatusException("BackendSearchLDAP(): Could not bind anonymously to server! Search aborted.", SYNC_SEARCHSTATUS_STORE_CONNECTIONFAILED, null, LOGLEVEL_ERROR); + if (count($ldap_server_conf) > 0) { + ZLog::Write(LOGLEVEL_ERROR, sprintf("BackendSearchLDAP(): No LDAP server URI defined. Try next server.")); + continue; + } + else { + throw new StatusException("BackendSearchLDAP(): No LDAP server URI defined. Search aborted.", SYNC_SEARCHSTATUS_STORE_CONNECTIONFAILED, null, LOGLEVEL_ERROR); + } } - } - else if (constant('LDAP_BIND_USER') != "") { - if(! @ldap_bind($this->connection, LDAP_BIND_USER, LDAP_BIND_PASSWORD)) { + else { + ZLog::Write(LOGLEVEL_INFO, sprintf("BackendSearchLDAP(): Try to connect to %s", $ldap_server_conf_item['LDAP_SERVER_URI'])); + $this->connection = @ldap_connect($ldap_server_conf_item['LDAP_SERVER_URI']); + if (!is_resource($this->connection)) { + if (count($ldap_server_conf) > 0) { + ZLog::Write(LOGLEVEL_ERROR, sprintf("BackendSearchLDAP(): Incorrect LDAP_SERVER_URI '%s'. Try next server.", $ldap_server_conf_item['LDAP_SERVER_URI'])); + continue; + } + else { + throw new StatusException(sprintf("BackendSearchLDAP(): Incorrect LDAP_SERVER_URI '%s'. Search aborted.", $ldap_server_conf_item['LDAP_SERVER_URI']), SYNC_SEARCHSTATUS_STORE_CONNECTIONFAILED, null, LOGLEVEL_ERROR); + } + } + ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendSearchLDAP(): Set LDAP_OPT_PROTOCOL_VERSION to 3")); + @ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, 3); + } + + if (!empty($ldap_server_conf_item['LDAP_DISABLE_REFERRALS']) and ($ldap_server_conf_item['LDAP_DISABLE_REFERRALS'] === true)) { + ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendSearchLDAP(): Set LDAP_OPT_REFERRALS to 0")); + @ldap_set_option($this->connection, LDAP_OPT_REFERRALS, 0); + } + + if (!empty($ldap_server_conf_item['LDAP_BIND_TIMEOUT'])) { + ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendSearchLDAP(): Set LDAP_OPT_NETWORK_TIMEOUT to %d", $ldap_server_conf_item['LDAP_BIND_TIMEOUT'])); + @ldap_set_option($this->connection, LDAP_OPT_NETWORK_TIMEOUT, $ldap_server_conf_item['LDAP_BIND_TIMEOUT']); + } + + if (!empty($ldap_server_conf_item['LDAP_START_TLS']) and ($ldap_server_conf_item['LDAP_START_TLS'] === true)) { + ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendSearchLDAP(): Try to start TLS")); + if (! @ldap_start_tls($this->connection)) { + $ldap_errno = ldap_errno($this->connection); + $ldap_error = ldap_error($this->connection); + $this->connection = false; + if (count($ldap_server_conf) > 0) { + ZLog::Write(LOGLEVEL_ERROR, sprintf("BackendSearchLDAP(): Could not start TLS session with server (error %d: %s). Try next server.", $ldap_errno, $ldap_error)); + continue; + } + else { + throw new StatusException(sprintf("BackendSearchLDAP(): Could not start TLS session with server (error %d: %s). Search aborted.", $ldap_errno, $ldap_error), SYNC_SEARCHSTATUS_STORE_CONNECTIONFAILED, null, LOGLEVEL_ERROR); + } + } + } + + // Authenticate + if (isset($ldap_server_conf_item['ANONYMOUS_BIND']) and ($ldap_server_conf_item['ANONYMOUS_BIND'] === true)) { + ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendSearchLDAP(): Try to bind anonymously")); + if(! @ldap_bind($this->connection)) { + $ldap_errno = ldap_errno($this->connection); + $ldap_error = ldap_error($this->connection); + $this->connection = false; + if (count($ldap_server_conf) > 0) { + ZLog::Write(LOGLEVEL_ERROR, sprintf("BackendSearchLDAP(): Could not bind anonymously to server (error %d: %s). Try next server.", $ldap_errno, $ldap_error)); + continue; + } + else { + throw new StatusException(sprintf("BackendSearchLDAP(): Could not bind anonymously to server (error %d: %s). Search aborted.", $ldap_errno, $ldap_error), SYNC_SEARCHSTATUS_STORE_CONNECTIONFAILED, null, LOGLEVEL_ERROR); + } + } + return; + } + else if (!empty($ldap_server_conf_item['LDAP_BIND_USER']) and !empty($ldap_server_conf_item['LDAP_BIND_PASSWORD'])) { + ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendSearchLDAP(): Try to bind as user '%s'", $ldap_server_conf_item['LDAP_BIND_USER'])); + if(! @ldap_bind($this->connection, $ldap_server_conf_item['LDAP_BIND_USER'], $ldap_server_conf_item['LDAP_BIND_PASSWORD'])) { + $ldap_errno = ldap_errno($this->connection); + $ldap_error = ldap_error($this->connection); + $this->connection = false; + if (count($ldap_server_conf) > 0) { + ZLog::Write(LOGLEVEL_ERROR, sprintf("BackendSearchLDAP(): Could not bind to server with user '%s' and specified password (error %d: %s). Try next server.", $ldap_server_conf_item['LDAP_BIND_USER'], $ldap_errno, $ldap_error)); + continue; + } + else { + throw new StatusException(sprintf("BackendSearchLDAP(): Could not bind to server with user '%s' and specified password (error %d: %s). Search aborted.", $ldap_server_conf_item['LDAP_BIND_USER'], $ldap_errno, $ldap_error), SYNC_SEARCHSTATUS_STORE_ACCESSDENIED, null, LOGLEVEL_ERROR); + } + } + return; + } + else { + // it would be possible to use the users login and password to authenticate on the LDAP server + // the main $backend has to keep these values so they could be used here $this->connection = false; - throw new StatusException(sprintf("BackendSearchLDAP(): Could not bind to server with user '%s' and specified password! Search aborted.", LDAP_BIND_USER), SYNC_SEARCHSTATUS_STORE_ACCESSDENIED, null, LOGLEVEL_ERROR); + if (count($ldap_server_conf) > 0) { + ZLog::Write(LOGLEVEL_ERROR, "BackendSearchLDAP(): neither anonymous nor default bind enabled. Other options not implemented. Try next server."); + continue; + } + else { + throw new StatusException("BackendSearchLDAP(): neither anonymous nor default bind enabled. Other options not implemented. Search aborted.", SYNC_SEARCHSTATUS_STORE_CONNECTIONFAILED, null, LOGLEVEL_ERROR); + } } - } - else { - // it would be possible to use the users login and password to authenticate on the LDAP server - // the main $backend has to keep these values so they could be used here - $this->connection = false; - throw new StatusException("BackendSearchLDAP(): neither anonymous nor default bind enabled. Other options not implemented.", SYNC_SEARCHSTATUS_STORE_CONNECTIONFAILED, null, LOGLEVEL_ERROR); } }