From c041d57036d4a30730408c8fbba2d4e12778d2d5 Mon Sep 17 00:00:00 2001 From: alecpl Date: Wed, 19 Oct 2011 09:56:06 +0000 Subject: - Added 'search_dn_default' variable in ldap config - Better handling of situation when search for bind DN doesn't return data --- config/main.inc.php.dist | 2 + program/include/rcube_ldap.php | 146 ++++++++++++++++++++++++----------------- 2 files changed, 86 insertions(+), 62 deletions(-) diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist index 9ce4440c6..3782374f3 100644 --- a/config/main.inc.php.dist +++ b/config/main.inc.php.dist @@ -535,6 +535,8 @@ $rcmail_config['ldap_public']['Verisign'] = array( // The login name is used to search for the DN to bind with 'search_base_dn' => '', 'search_filter' => '', // e.g. '(&(objectClass=posixAccount)(uid=%u))' + // Default for %dn variable if search doesn't return DN value + 'search_dn_default' => '', // Optional authentication identifier to be used as SASL authorization proxy // bind_dn need to be empty 'auth_cid' => '', diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index f33db0cf4..1f03e1500 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -165,12 +165,14 @@ class rcube_ldap extends rcube_addressbook foreach ($this->prop['hosts'] as $host) { - $host = idn_to_ascii(rcube_parse_host($host)); - $this->_debug("C: Connect [$host".($this->prop['port'] ? ':'.$this->prop['port'] : '')."]"); + $host = idn_to_ascii(rcube_parse_host($host)); + $hostname = $host.($this->prop['port'] ? ':'.$this->prop['port'] : ''); + + $this->_debug("C: Connect [$hostname]"); if ($lc = @ldap_connect($host, $this->prop['port'])) { - if ($this->prop['use_tls']===true) + if ($this->prop['use_tls'] === true) if (!ldap_start_tls($lc)) continue; @@ -184,85 +186,105 @@ class rcube_ldap extends rcube_addressbook $this->_debug("S: NOT OK"); } - if (is_resource($this->conn)) - { - $this->ready = true; + // See if the directory is writeable. + if ($this->prop['writable']) { + $this->readonly = false; + } + + if (!is_resource($this->conn)) { + raise_error(array('code' => 100, 'type' => 'ldap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Could not connect to any LDAP server, last tried $hostname"), true); - $bind_pass = $this->prop['bind_pass']; - $bind_user = $this->prop['bind_user']; - $bind_dn = $this->prop['bind_dn']; + return false; + } - $this->base_dn = $this->prop['base_dn']; - $this->groups_base_dn = ($this->prop['groups']['base_dn']) ? - $this->prop['groups']['base_dn'] : $this->base_dn; + $bind_pass = $this->prop['bind_pass']; + $bind_user = $this->prop['bind_user']; + $bind_dn = $this->prop['bind_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 = $RCMAIL->decrypt($_SESSION['password']); - } + $this->base_dn = $this->prop['base_dn']; + $this->groups_base_dn = ($this->prop['groups']['base_dn']) ? + $this->prop['groups']['base_dn'] : $this->base_dn; - // Get the pieces needed for variable replacement. - if ($fu = $RCMAIL->user->get_username()) - list($u, $d) = explode('@', $fu); - else - $d = $this->mail_domain; + // 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 = $RCMAIL->decrypt($_SESSION['password']); + } - $dc = 'dc='.strtr($d, array('.' => ',dc=')); // hierarchal domain string + // Get the pieces needed for variable replacement. + if ($fu = $RCMAIL->user->get_username()) + list($u, $d) = explode('@', $fu); + else + $d = $this->mail_domain; - $replaces = array('%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u); + $dc = 'dc='.strtr($d, array('.' => ',dc=')); // hierarchal domain string - if ($this->prop['search_base_dn'] && $this->prop['search_filter']) { - // 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); + $replaces = array('%dn' => '', '%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u); - $this->_debug("S: searching with base {$this->prop['search_base_dn']} for {$this->prop['search_filter']}"); + if ($this->prop['search_base_dn'] && $this->prop['search_filter']) { + // 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); - $res = @ldap_search($this->conn, $this->prop['search_base_dn'], $this->prop['search_filter'], array('uid')); - if ($res && ($entry = ldap_first_entry($this->conn, $res))) { - $bind_dn = ldap_get_dn($this->conn, $entry); + $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"); - - if ($bind_dn) { - $dn = ldap_explode_dn($bind_dn, 1); - $replaces = array('%dn' => $dn[0]) + $replaces; - } + $dn = ldap_explode_dn($bind_dn, 1); + $replaces['%dn'] = $dn[0]; } } - // 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); + else { + $this->_debug("S: ".ldap_error($this->conn)); + } - if (empty($bind_user)) { - $bind_user = $u; + // DN not found + if (empty($replaces['%dn'])) { + if (!empty($this->prop['search_dn_default'])) + $replaces['%dn'] = $this->prop['search_dn_default']; + else { + raise_error(array( + 'code' => 100, 'type' => 'ldap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "DN not found using LDAP search."), true); + return false; + } } } - if (!empty($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); - } + // 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; } } - else - raise_error(array('code' => 100, 'type' => 'ldap', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Could not connect to any LDAP server, last tried $host:{$this->prop[port]}"), true); - // See if the directory is writeable. - if ($this->prop['writable']) { - $this->readonly = false; - } // end if + 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); + } + else { + $this->ready = $this->sasl_bind($bind_user, $bind_pass); + } + } + + return $this->ready; } -- cgit v1.2.3