Beispiel #1
0
 /**
  * Establish a connection to the LDAP server
  */
 private function _connect()
 {
     $rcube = rcube::get_instance();
     if ($this->ready) {
         return true;
     }
     if (!is_array($this->prop['hosts'])) {
         $this->prop['hosts'] = array($this->prop['hosts']);
     }
     // 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) {
         // skip host if connection failed
         if (!$this->ldap->connect($host)) {
             continue;
         }
         // 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'];
         $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();
             }
             // 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
             $replaces = array('%dn' => '', '%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u);
             // Search for the dn to use to authenticate
             if ($this->prop['search_base_dn'] && $this->prop['search_filter'] && (strstr($bind_dn, '%dn') || strstr($this->base_dn, '%dn') || strstr($this->groups_base_dn, '%dn'))) {
                 $search_attribs = array('uid');
                 if ($search_bind_attrib = (array) $this->prop['search_bind_attrib']) {
                     foreach ($search_bind_attrib as $r => $attr) {
                         $search_attribs[] = $attr;
                         $replaces[$r] = '';
                     }
                 }
                 $search_bind_dn = strtr($this->prop['search_bind_dn'], $replaces);
                 $search_base_dn = strtr($this->prop['search_base_dn'], $replaces);
                 $search_filter = strtr($this->prop['search_filter'], $replaces);
                 $cache_key = 'DN.' . md5("{$host}:{$search_bind_dn}:{$search_base_dn}:{$search_filter}:" . $this->prop['search_bind_pw']);
                 if ($this->cache && ($dn = $this->cache->get($cache_key))) {
                     $replaces['%dn'] = $dn;
                 } else {
                     $ldap = $this->ldap;
                     if (!empty($search_bind_dn) && !empty($this->prop['search_bind_pw'])) {
                         // To protect from "Critical extension is unavailable" error
                         // we need to use a separate LDAP connection
                         if (!empty($this->prop['vlv'])) {
                             $ldap = new rcube_ldap_generic($this->prop);
                             $ldap->config_set(array('cache' => $this->cache, 'debug' => $this->debug));
                             if (!$ldap->connect($host)) {
                                 continue;
                             }
                         }
                         if (!$ldap->bind($search_bind_dn, $this->prop['search_bind_pw'])) {
                             continue;
                             // bind failed, try next host
                         }
                     }
                     $res = $ldap->search($search_base_dn, $search_filter, 'sub', $search_attribs);
                     if ($res) {
                         $res->rewind();
                         $replaces['%dn'] = key($res->entries(TRUE));
                         // add more replacements from 'search_bind_attrib' config
                         if ($search_bind_attrib) {
                             $res = $res->current();
                             foreach ($search_bind_attrib as $r => $attr) {
                                 $replaces[$r] = $res[$attr][0];
                             }
                         }
                     }
                     if ($ldap != $this->ldap) {
                         $ldap->close();
                     }
                 }
                 // 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);
                         continue;
                     }
                 }
                 if ($this->cache && !empty($replaces['%dn'])) {
                     $this->cache->set($cache_key, $replaces['%dn']);
                 }
             }
             // 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 placeholders in filter settings
             if (!empty($this->prop['filter'])) {
                 $this->prop['filter'] = strtr($this->prop['filter'], $replaces);
             }
             foreach (array('base_dn', 'filter', 'member_filter') as $k) {
                 if (!empty($this->prop['groups'][$k])) {
                     $this->prop['groups'][$k] = strtr($this->prop['groups'][$k], $replaces);
                 }
             }
             if (is_array($this->prop['group_filters'])) {
                 foreach ($this->prop['group_filters'] as $i => $gf) {
                     if (!empty($gf['base_dn'])) {
                         $this->prop['group_filters'][$i]['base_dn'] = strtr($gf['base_dn'], $replaces);
                     }
                     if (!empty($gf['filter'])) {
                         $this->prop['group_filters'][$i]['filter'] = strtr($gf['filter'], $replaces);
                     }
                 }
             }
             if (empty($bind_user)) {
                 $bind_user = $u;
             }
         }
         if (empty($bind_pass)) {
             $this->ready = true;
         } else {
             if (!empty($bind_dn)) {
                 $this->ready = $this->ldap->bind($bind_dn, $bind_pass);
             } else {
                 if (!empty($this->prop['auth_cid'])) {
                     $this->ready = $this->ldap->sasl_bind($this->prop['auth_cid'], $bind_pass, $bind_user);
                 } else {
                     $this->ready = $this->ldap->sasl_bind($bind_user, $bind_pass);
                 }
             }
         }
         // connection established, we're done here
         if ($this->ready) {
             break;
         }
     }
     // end foreach hosts
     if (!is_resource($this->ldap->conn)) {
         rcube::raise_error(array('code' => 100, 'type' => 'ldap', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Could not connect to any LDAP server, last tried {$host}"), true);
         return false;
     }
     return $this->ready;
 }