summaryrefslogtreecommitdiff
path: root/program/lib/Roundcube/rcube_ldap.php
diff options
context:
space:
mode:
Diffstat (limited to 'program/lib/Roundcube/rcube_ldap.php')
-rw-r--r--program/lib/Roundcube/rcube_ldap.php206
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);