diff options
Diffstat (limited to 'program/lib/Roundcube/rcube_ldap.php')
-rw-r--r-- | program/lib/Roundcube/rcube_ldap.php | 206 |
1 files changed, 101 insertions, 105 deletions
diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index c9a14d863..a2dd163e9 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -2,8 +2,6 @@ /* +-----------------------------------------------------------------------+ - | program/include/rcube_ldap.php | - | | | This file is part of the Roundcube Webmail client | | Copyright (C) 2006-2012, The Roundcube Dev Team | | Copyright (C) 2011-2012, Kolab Systems AG | @@ -14,7 +12,6 @@ | | | PURPOSE: | | Interface to an LDAP address directory | - | | +-----------------------------------------------------------------------+ | Author: Thomas Bruederli <roundcube@gmail.com> | | Andreas Dick <andudi (at) gmx (dot) ch> | @@ -22,7 +19,6 @@ +-----------------------------------------------------------------------+ */ - /** * Model class to access an LDAP address directory * @@ -218,15 +214,16 @@ class rcube_ldap extends rcube_addressbook if (empty($this->prop['ldap_version'])) $this->prop['ldap_version'] = 3; - foreach ($this->prop['hosts'] as $host) - { + // 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 + foreach ($this->prop['hosts'] as $host) { $host = rcube_utils::idn_to_ascii(rcube_utils::parse_host($host)); $hostname = $host.($this->prop['port'] ? ':'.$this->prop['port'] : ''); $this->_debug("C: Connect [$hostname] [{$this->prop['name']}]"); - if ($lc = @ldap_connect($host, $this->prop['port'])) - { + if ($lc = @ldap_connect($host, $this->prop['port'])) { if ($this->prop['use_tls'] === true) if (!ldap_start_tls($lc)) continue; @@ -237,113 +234,124 @@ class rcube_ldap extends rcube_addressbook $this->prop['host'] = $host; $this->conn = $lc; + if (!empty($this->prop['network_timeout'])) + ldap_set_option($lc, LDAP_OPT_NETWORK_TIMEOUT, $this->prop['network_timeout']); + if (isset($this->prop['referrals'])) ldap_set_option($lc, LDAP_OPT_REFERRALS, $this->prop['referrals']); - break; } - $this->_debug("S: NOT OK"); - } - - // See if the directory is writeable. - if ($this->prop['writable']) { - $this->readonly = false; - } - - if (!is_resource($this->conn)) { - rcube::raise_error(array('code' => 100, 'type' => 'ldap', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Could not connect to any LDAP server, last tried $hostname"), true); + else { + $this->_debug("S: NOT OK"); + continue; + } - return false; - } + // See if the directory is writeable. + if ($this->prop['writable']) { + $this->readonly = false; + } - $bind_pass = $this->prop['bind_pass']; - $bind_user = $this->prop['bind_user']; - $bind_dn = $this->prop['bind_dn']; + $bind_pass = $this->prop['bind_pass']; + $bind_user = $this->prop['bind_user']; + $bind_dn = $this->prop['bind_dn']; - $this->base_dn = $this->prop['base_dn']; - $this->groups_base_dn = ($this->prop['groups']['base_dn']) ? - $this->prop['groups']['base_dn'] : $this->base_dn; + $this->base_dn = $this->prop['base_dn']; + $this->groups_base_dn = ($this->prop['groups']['base_dn']) ? + $this->prop['groups']['base_dn'] : $this->base_dn; - // User specific access, generate the proper values to use. - if ($this->prop['user_specific']) { - // No password set, use the session password - if (empty($bind_pass)) { - $bind_pass = $rcube->get_user_password(); - } + // User specific access, generate the proper values to use. + if ($this->prop['user_specific']) { + // No password set, use the session password + if (empty($bind_pass)) { + $bind_pass = $rcube->get_user_password(); + } - // Get the pieces needed for variable replacement. - if ($fu = $rcube->get_user_email()) - list($u, $d) = explode('@', $fu); - else - $d = $this->mail_domain; + // Get the pieces needed for variable replacement. + if ($fu = $rcube->get_user_email()) + list($u, $d) = explode('@', $fu); + else + $d = $this->mail_domain; - $dc = 'dc='.strtr($d, array('.' => ',dc=')); // hierarchal domain string + $dc = 'dc='.strtr($d, array('.' => ',dc=')); // hierarchal domain string - $replaces = array('%dn' => '', '%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u); + $replaces = array('%dn' => '', '%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u); - if ($this->prop['search_base_dn'] && $this->prop['search_filter']) { - if (!empty($this->prop['search_bind_dn']) && !empty($this->prop['search_bind_pw'])) { - $this->bind($this->prop['search_bind_dn'], $this->prop['search_bind_pw']); - } + if ($this->prop['search_base_dn'] && $this->prop['search_filter']) { + if (!empty($this->prop['search_bind_dn']) && !empty($this->prop['search_bind_pw'])) { + $this->bind($this->prop['search_bind_dn'], $this->prop['search_bind_pw']); + } - // Search for the dn to use to authenticate - $this->prop['search_base_dn'] = strtr($this->prop['search_base_dn'], $replaces); - $this->prop['search_filter'] = strtr($this->prop['search_filter'], $replaces); + // Search for the dn to use to authenticate + $this->prop['search_base_dn'] = strtr($this->prop['search_base_dn'], $replaces); + $this->prop['search_filter'] = strtr($this->prop['search_filter'], $replaces); - $this->_debug("S: searching with base {$this->prop['search_base_dn']} for {$this->prop['search_filter']}"); + $this->_debug("S: searching with base {$this->prop['search_base_dn']} for {$this->prop['search_filter']}"); - $res = @ldap_search($this->conn, $this->prop['search_base_dn'], $this->prop['search_filter'], array('uid')); - if ($res) { - if (($entry = ldap_first_entry($this->conn, $res)) - && ($bind_dn = ldap_get_dn($this->conn, $entry)) - ) { - $this->_debug("S: search returned dn: $bind_dn"); - $dn = ldap_explode_dn($bind_dn, 1); - $replaces['%dn'] = $dn[0]; + $res = @ldap_search($this->conn, $this->prop['search_base_dn'], $this->prop['search_filter'], array('uid')); + if ($res) { + if (($entry = ldap_first_entry($this->conn, $res)) + && ($bind_dn = ldap_get_dn($this->conn, $entry)) + ) { + $this->_debug("S: search returned dn: $bind_dn"); + $dn = ldap_explode_dn($bind_dn, 1); + $replaces['%dn'] = $dn[0]; + } } - } - else { - $this->_debug("S: ".ldap_error($this->conn)); - } - - // DN not found - if (empty($replaces['%dn'])) { - if (!empty($this->prop['search_dn_default'])) - $replaces['%dn'] = $this->prop['search_dn_default']; else { - rcube::raise_error(array( - 'code' => 100, 'type' => 'ldap', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "DN not found using LDAP search."), true); - return false; + $this->_debug("S: ".ldap_error($this->conn)); + } + + // DN not found + if (empty($replaces['%dn'])) { + if (!empty($this->prop['search_dn_default'])) + $replaces['%dn'] = $this->prop['search_dn_default']; + else { + rcube::raise_error(array( + 'code' => 100, 'type' => 'ldap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "DN not found using LDAP search."), true); + return false; + } } } - } - // Replace the bind_dn and base_dn variables. - $bind_dn = strtr($bind_dn, $replaces); - $this->base_dn = strtr($this->base_dn, $replaces); - $this->groups_base_dn = strtr($this->groups_base_dn, $replaces); + // Replace the bind_dn and base_dn variables. + $bind_dn = strtr($bind_dn, $replaces); + $this->base_dn = strtr($this->base_dn, $replaces); + $this->groups_base_dn = strtr($this->groups_base_dn, $replaces); - if (empty($bind_user)) { - $bind_user = $u; + if (empty($bind_user)) { + $bind_user = $u; + } } - } - if (empty($bind_pass)) { - $this->ready = true; - } - else { - if (!empty($bind_dn)) { - $this->ready = $this->bind($bind_dn, $bind_pass); - } - else if (!empty($this->prop['auth_cid'])) { - $this->ready = $this->sasl_bind($this->prop['auth_cid'], $bind_pass, $bind_user); + if (empty($bind_pass)) { + $this->ready = true; } else { - $this->ready = $this->sasl_bind($bind_user, $bind_pass); + if (!empty($bind_dn)) { + $this->ready = $this->bind($bind_dn, $bind_pass); + } + else if (!empty($this->prop['auth_cid'])) { + $this->ready = $this->sasl_bind($this->prop['auth_cid'], $bind_pass, $bind_user); + } + else { + $this->ready = $this->sasl_bind($bind_user, $bind_pass); + } + } + + // connection established, we're done here + if ($this->ready) { + break; } + + } // end foreach hosts + + if (!is_resource($this->conn)) { + rcube::raise_error(array('code' => 100, 'type' => 'ldap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Could not connect to any LDAP server, last tried $hostname"), true); + + return false; } return $this->ready; @@ -798,27 +806,14 @@ class rcube_ldap extends rcube_addressbook $this->_debug("S: ".ldap_count_entries($this->conn, $this->ldap_result)." record(s)"); // get all entries of this page and post-filter those that really match the query - $search = mb_strtolower($value); + $search = mb_strtolower($value); $entries = ldap_get_entries($this->conn, $this->ldap_result); for ($i = 0; $i < $entries['count']; $i++) { $rec = $this->_ldap2result($entries[$i]); foreach ($fields as $f) { foreach ((array)$rec[$f] as $val) { - $val = mb_strtolower($val); - switch ($mode) { - case 1: - $got = ($val == $search); - break; - case 2: - $got = ($search == substr($val, 0, strlen($search))); - break; - default: - $got = (strpos($val, $search) !== false); - break; - } - - if ($got) { + if ($this->compare_search_value($f, $val, $search, $mode)) { $this->result->add($rec); $this->result->count++; break 2; @@ -1455,6 +1450,7 @@ class rcube_ldap extends rcube_addressbook if ($this->vlv_active && function_exists('ldap_parse_virtuallist_control')) { if (ldap_parse_result($this->conn, $this->ldap_result, $errcode, $matcheddn, $errmsg, $referrals, $serverctrls) + && $serverctrls // can be null e.g. in case of adm. limit error ) { ldap_parse_virtuallist_control($this->conn, $serverctrls, $last_offset, $this->vlv_count, $vresult); |