diff -urN ../roundcubemail-1.6.2.orig/program/lib/Roundcube/rcube_ldap.php ./program/lib/Roundcube/rcube_ldap.php --- ../roundcubemail-1.6.2.orig/program/lib/Roundcube/rcube_ldap.php 2023-07-01 14:29:36.000000000 +0300 +++ ./program/lib/Roundcube/rcube_ldap.php 2023-07-03 22:15:06.391155000 +0300 @@ -307,6 +307,19 @@ $this->prop['hosts'] = []; } + $this->ldap->_debug("Check LDAP hosts list against broken hosts list."); + if (!isset($_SESSION['roundcube_ldap_hosts_probably_broken']) or !is_array($_SESSION['roundcube_ldap_hosts_probably_broken']) or (count($_SESSION['roundcube_ldap_hosts_probably_broken']) == 0)) { + $this->ldap->_debug("Broken LDAP hosts list is empty."); + } else { + $hosts_checked = array_diff($this->prop['hosts'], $_SESSION['roundcube_ldap_hosts_probably_broken']); + if (count($hosts_checked) == 0) { + $this->ldap->_debug("All hosts are broken. Reset broken hosts list."); + $_SESSION['roundcube_ldap_hosts_probably_broken'] = []; + } else { + $this->prop['hosts'] = $hosts_checked; + } + } + // try to connect + bind for every host configured // with OpenLDAP 2.x ldap_connect() always succeeds but ldap_bind will fail if host isn't reachable // see http://www.php.net/manual/en/function.ldap-connect.php diff -urN ../roundcubemail-1.6.2.orig/vendor/kolab/net_ldap3/lib/Net/LDAP3.php ./vendor/kolab/net_ldap3/lib/Net/LDAP3.php --- ../roundcubemail-1.6.2.orig/vendor/kolab/net_ldap3/lib/Net/LDAP3.php 2023-07-01 14:29:39.000000000 +0300 +++ ./vendor/kolab/net_ldap3/lib/Net/LDAP3.php 2023-07-03 22:16:40.024998000 +0300 @@ -66,6 +66,8 @@ 'v' => 'read' ]; + private $hosts_used = []; + /* * Manipulate configuration through the config_set and config_get methods. * Available options: @@ -518,6 +520,18 @@ $this->_debug("S: ".ldap_error($this->conn)); $this->_error("LDAP: Bind failed for dn=$bind_dn. ".ldap_error($this->conn)); + if ((ldap_errno($this->conn) == -1) or (ldap_error($this->conn) == "Can't contact LDAP server")) { + if (isset($_SESSION['roundcube_ldap_hosts_probably_broken']) and is_array($_SESSION['roundcube_ldap_hosts_probably_broken'])) { + if (!in_array($this->_current_host, $_SESSION['roundcube_ldap_hosts_probably_broken'])) { + $this->_debug(sprintf("Save host %s as broken", $this->_current_host)); + $_SESSION['roundcube_ldap_hosts_probably_broken'][] = $this->_current_host; + } + } else { + $this->_debug(sprintf("Save host %s as broken", $this->_current_host)); + $_SESSION['roundcube_ldap_hosts_probably_broken'] = [$this->_current_host]; + } + } + return false; } @@ -605,11 +619,23 @@ } if (isset($this->conn) && $this->conn !== false) { - $this->_debug("Connection already exists"); - return true; + if ($this->_current_bind_dn) { + $this->_debug("Connection already exists"); + return true; + } else { + $hosts = (!empty($host) ? (is_array($host) ? $host : [$host]) : $this->config_get('hosts', [])); + $hosts = array_diff($hosts, $this->hosts_used); + if (count($hosts) == 0) { + $this->_debug("All LDAP hosts are broken"); + return true; + } else { + $this->_debug(sprintf("C: Try next LDAP host %s", $hosts[0])); + } + } + } else { + $hosts = (!empty($host) ? $host : $this->config_get('hosts', [])); } - $hosts = !empty($host) ? $host : $this->config_get('hosts', []); $port = $this->config_get('port', 389); foreach ((array) $hosts as $host) { @@ -617,6 +643,7 @@ $this->_debug("C: Connect [{$ldap_uri}]"); if ($lc = @ldap_connect($ldap_uri)) { + $this->hosts_used[] = $host; if ($this->config_get('use_tls', false) === true) { if (!ldap_start_tls($lc)) { $this->_debug("S: Could not start TLS. " . ldap_error($lc)); @@ -2616,7 +2643,7 @@ $this->__log(LOG_CRIT, func_get_args()); } - protected function _debug() + public function _debug() { $this->__log(LOG_DEBUG, func_get_args()); }