From e3ef52cdb2ca53f62839275fb578c5a972d93d71 Mon Sep 17 00:00:00 2001
From: Mikhail Krasilnikov <mihalych@vsepofigu.ru>
Date: Fri, 8 Jun 2012 11:41:51 +0400
Subject: [PATCH] Allow multiple LDAP servers.

---
 inc/auth/ldap.class.php | 99 +++++++++++++++++++++++++++--------------
 1 file changed, 66 insertions(+), 33 deletions(-)

diff --git a/inc/auth/ldap.class.php b/inc/auth/ldap.class.php
index a6a15ee3d..9b6ff5023 100644
--- a/inc/auth/ldap.class.php
+++ b/inc/auth/ldap.class.php
@@ -387,49 +387,82 @@ class auth_ldap extends auth_basic {
         $this->bound = 0;
 
         $port = ($this->cnf['port']) ? $this->cnf['port'] : 389;
-        $this->con = @ldap_connect($this->cnf['server'],$port);
-        if(!$this->con){
-            msg("LDAP: couldn't connect to LDAP server",-1);
-            return false;
+        if (!is_array($this->cnf['server']))
+        {
+            $this->cnf['server'] = array($this->cnf['server']);
         }
+        $bound = false;
+        foreach ($this->cnf['server'] as $server)
+        {
+            $this->con = @ldap_connect($server, $port);
+            if (!$this->con)
+            {
+                continue;
+            }
 
-        //set protocol version and dependend options
-        if($this->cnf['version']){
-            if(!@ldap_set_option($this->con, LDAP_OPT_PROTOCOL_VERSION,
-                                 $this->cnf['version'])){
-                msg('Setting LDAP Protocol version '.$this->cnf['version'].' failed',-1);
-                if($this->cnf['debug'])
-                    msg('LDAP version set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
-            }else{
-                //use TLS (needs version 3)
-                if($this->cnf['starttls']) {
-                    if (!@ldap_start_tls($this->con)){
-                        msg('Starting TLS failed',-1);
-                        if($this->cnf['debug'])
-                            msg('LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+            /*
+             * When OpenLDAP 2.x.x is used, ldap_connect() will always return a resource as it does
+             * not actually connect but just initializes the connecting parameters. The actual
+             * connect happens with the next calls to ldap_* funcs, usually with ldap_bind().
+             *
+             * So we should try to bind to server in order to check its availability.
+             */
+
+            //set protocol version and dependend options
+            if($this->cnf['version']){
+                if(!@ldap_set_option($this->con, LDAP_OPT_PROTOCOL_VERSION,
+                                     $this->cnf['version'])){
+                    msg('Setting LDAP Protocol version '.$this->cnf['version'].' failed',-1);
+                    if($this->cnf['debug'])
+                        msg('LDAP version set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+                }else{
+                    //use TLS (needs version 3)
+                    if($this->cnf['starttls']) {
+                        if (!@ldap_start_tls($this->con)){
+                            msg('Starting TLS failed',-1);
+                            if($this->cnf['debug'])
+                                msg('LDAP TLS set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+                        }
                     }
-                }
-                // needs version 3
-                if(isset($this->cnf['referrals'])) {
-                    if(!@ldap_set_option($this->con, LDAP_OPT_REFERRALS,
-                       $this->cnf['referrals'])){
-                        msg('Setting LDAP referrals to off failed',-1);
-                        if($this->cnf['debug'])
-                            msg('LDAP referal set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+                    // needs version 3
+                    if(isset($this->cnf['referrals'])) {
+                        if(!@ldap_set_option($this->con, LDAP_OPT_REFERRALS,
+                           $this->cnf['referrals'])){
+                            msg('Setting LDAP referrals to off failed',-1);
+                            if($this->cnf['debug'])
+                                msg('LDAP referal set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+                        }
                     }
                 }
             }
-        }
 
-        //set deref mode
-        if($this->cnf['deref']){
-            if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->cnf['deref'])){
-                msg('Setting LDAP Deref mode '.$this->cnf['deref'].' failed',-1);
-                if($this->cnf['debug'])
-                    msg('LDAP deref set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+            //set deref mode
+            if($this->cnf['deref']){
+                if(!@ldap_set_option($this->con, LDAP_OPT_DEREF, $this->cnf['deref'])){
+                    msg('Setting LDAP Deref mode '.$this->cnf['deref'].' failed',-1);
+                    if($this->cnf['debug'])
+                        msg('LDAP deref set: '.htmlspecialchars(ldap_error($this->con)),0,__LINE__,__FILE__);
+                }
+            }
+            /* As of PHP 5.3.0 we can set timeout to speedup skipping of invalid servers */
+            if (defined('LDAP_OPT_NETWORK_TIMEOUT'))
+            {
+                ldap_set_option($this->con, LDAP_OPT_NETWORK_TIMEOUT, 1);
+            }
+            $bound = ldap_bind($this->con);
+            if ($bound)
+            {
+                break;
             }
         }
 
+        if(!$bound)
+        {
+            msg("LDAP: couldn't connect to LDAP server",-1);
+            return false;
+        }
+
+
         $this->canDo['getUsers'] = true;
         return true;
     }
-- 
GitLab