| | |
| | | */ |
| | | class rcube_ldap extends rcube_addressbook |
| | | { |
| | | /** public properties */ |
| | | public $primary_key = 'ID'; |
| | | public $groups = false; |
| | | public $readonly = true; |
| | | public $ready = false; |
| | | public $group_id = 0; |
| | | public $list_page = 1; |
| | | public $page_size = 10; |
| | | public $coltypes = array(); |
| | | |
| | | /** private properties */ |
| | | protected $conn; |
| | | protected $prop = array(); |
| | | protected $fieldmap = array(); |
| | |
| | | protected $sort_col = ''; |
| | | protected $mail_domain = ''; |
| | | protected $debug = false; |
| | | |
| | | /** public properties */ |
| | | public $primary_key = 'ID'; |
| | | public $readonly = true; |
| | | public $groups = false; |
| | | public $list_page = 1; |
| | | public $page_size = 10; |
| | | public $group_id = 0; |
| | | public $ready = false; |
| | | public $coltypes = array(); |
| | | |
| | | private $group_cache = array(); |
| | | private $group_members = array(); |
| | |
| | | $this->debug = $debug; |
| | | $this->mail_domain = $mail_domain; |
| | | |
| | | $this->connect(); |
| | | $this->_connect(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Establish a connection to the LDAP server |
| | | */ |
| | | function connect() |
| | | private function _connect() |
| | | { |
| | | global $RCMAIL; |
| | | |
| | |
| | | |
| | | foreach ($this->prop['hosts'] as $host) |
| | | { |
| | | $host = rcube_idn_to_ascii(rcube_parse_host($host)); |
| | | $host = idn_to_ascii(rcube_parse_host($host)); |
| | | $this->_debug("C: Connect [$host".($this->prop['port'] ? ':'.$this->prop['port'] : '')."]"); |
| | | |
| | | if ($lc = @ldap_connect($host, $this->prop['port'])) |
| | |
| | | } |
| | | |
| | | if (!empty($this->prop['bind_dn']) && !empty($this->prop['bind_pass'])) |
| | | $this->ready = $this->bind($this->prop['bind_dn'], $this->prop['bind_pass']); |
| | | $this->ready = $this->_bind($this->prop['bind_dn'], $this->prop['bind_pass']); |
| | | } |
| | | else |
| | | raise_error(array('code' => 100, 'type' => 'ldap', |
| | |
| | | if ($this->prop['writable']) { |
| | | $this->readonly = false; |
| | | } // end if |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | * @param string Bind password |
| | | * @return boolean True on success, False on error |
| | | */ |
| | | function bind($dn, $pass) |
| | | private function _bind($dn, $pass) |
| | | { |
| | | if (!$this->conn) { |
| | | return false; |
| | |
| | | |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | |
| | | raise_error(array( |
| | | $error = array( |
| | | 'code' => ldap_errno($this->conn), 'type' => 'ldap', |
| | | 'file' => __FILE__, 'line' => __LINE__, |
| | | 'message' => "Bind failed for dn=$dn: ".ldap_error($this->conn)), |
| | | true); |
| | | 'message' => "Bind failed for dn=$dn: ".ldap_error($this->conn)); |
| | | raise_error($error,true); |
| | | |
| | | return false; |
| | | } |
| | |
| | | } |
| | | |
| | | // temp hack for filtering group members |
| | | if ($this->group_id) |
| | | if ($this->groups and $this->group_id) |
| | | { |
| | | $result = new rcube_result_set(); |
| | | while ($record = $this->result->iterate()) |
| | |
| | | $ids = explode(',', $value); |
| | | $result = new rcube_result_set(); |
| | | foreach ($ids as $id) |
| | | { |
| | | if ($rec = $this->get_record($id, true)) |
| | | { |
| | | $result->add($rec); |
| | | $result->count++; |
| | | } |
| | | |
| | | } |
| | | return $result; |
| | | } |
| | | |
| | |
| | | if (is_array($this->prop['search_fields'])) |
| | | { |
| | | foreach ($this->prop['search_fields'] as $k => $field) |
| | | $filter .= "($field=$wc" . rcube_ldap::quote_string($value) . "$wc)"; |
| | | $filter .= "($field=$wc" . $this->_quote_string($value) . "$wc)"; |
| | | } |
| | | else |
| | | { |
| | | foreach ((array)$fields as $field) |
| | | if ($f = $this->_map_field($field)) |
| | | $filter .= "($f=$wc" . rcube_ldap::quote_string($value) . "$wc)"; |
| | | $filter .= "($f=$wc" . $this->_quote_string($value) . "$wc)"; |
| | | } |
| | | $filter .= ')'; |
| | | |
| | |
| | | } |
| | | |
| | | // Build the new entries DN. |
| | | $dn = $this->prop['LDAP_rdn'].'='.rcube_ldap::quote_string($newentry[$this->prop['LDAP_rdn']], true).','.$this->prop['base_dn']; |
| | | $dn = $this->prop['LDAP_rdn'].'='.$this->_quote_string($newentry[$this->prop['LDAP_rdn']], true).','.$this->prop['base_dn']; |
| | | |
| | | $this->_debug("C: Add [dn: $dn]: ".print_r($newentry, true)); |
| | | |
| | |
| | | } // end if |
| | | |
| | | $this->_debug("S: OK"); |
| | | |
| | | // add new contact to the selected group |
| | | if ($this->groups) |
| | | $this->add_to_group($this->group_id, base64_encode($dn)); |
| | | |
| | | return base64_encode($dn); |
| | | } |
| | |
| | | foreach ($this->fieldmap as $col => $fld) { |
| | | $val = $save_cols[$col]; |
| | | if ($fld) { |
| | | // remove empty array values |
| | | if (is_array($val)) |
| | | $val = array_filter($val); |
| | | // The field does exist compare it to the ldap record. |
| | | if ($record[$col] != $val) { |
| | | // Changed, but find out how. |
| | |
| | | // Handle RDN change |
| | | if ($replacedata[$this->prop['LDAP_rdn']]) { |
| | | $newdn = $this->prop['LDAP_rdn'].'=' |
| | | .rcube_ldap::quote_string($replacedata[$this->prop['LDAP_rdn']], true) |
| | | .$this->_quote_string($replacedata[$this->prop['LDAP_rdn']], true) |
| | | .','.$this->prop['base_dn']; |
| | | if ($dn != $newdn) { |
| | | $newrdn = $this->prop['LDAP_rdn'].'=' |
| | | .rcube_ldap::quote_string($replacedata[$this->prop['LDAP_rdn']], true); |
| | | .$this->_quote_string($replacedata[$this->prop['LDAP_rdn']], true); |
| | | unset($replacedata[$this->prop['LDAP_rdn']]); |
| | | } |
| | | } |
| | |
| | | // Handle RDN change |
| | | if (!empty($newrdn)) { |
| | | $this->_debug("C: Rename [dn: $dn] [dn: $newrdn]"); |
| | | if (@ldap_rename($this->conn, $dn, $newrdn, NULL, TRUE)) { |
| | | if (!ldap_rename($this->conn, $dn, $newrdn, NULL, TRUE)) { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | return base64_encode($newdn); |
| | | return false; |
| | | } |
| | | $this->_debug("S: OK"); |
| | | |
| | | // change the group membership of the contact |
| | | if ($this->groups) |
| | | { |
| | | $group_ids = $this->get_record_groups(base64_encode($dn)); |
| | | foreach ($group_ids as $group_id) |
| | | { |
| | | $this->remove_from_group($group_id, base64_encode($dn)); |
| | | $this->add_to_group($group_id, base64_encode($newdn)); |
| | | } |
| | | } |
| | | return base64_encode($newdn); |
| | | } |
| | | |
| | | return true; |
| | |
| | | return false; |
| | | } // end if |
| | | $this->_debug("S: OK"); |
| | | |
| | | // remove contact from all groups where he was member |
| | | if ($this->groups) |
| | | { |
| | | $group_ids = $this->get_record_groups(base64_encode($dn)); |
| | | foreach ($group_ids as $group_id) |
| | | { |
| | | $this->remove_from_group($group_id, base64_encode($dn)); |
| | | } |
| | | } |
| | | } // end foreach |
| | | |
| | | return count($dns); |
| | |
| | | $this->_debug("C: Search [".$filter."]"); |
| | | |
| | | if ($this->ldap_result = @$function($this->conn, $this->prop['base_dn'], $filter, |
| | | array_values($this->fieldmap), 0, (int) $this->prop['sizelimit'], (int) $this->prop['timelimit']) |
| | | ) { |
| | | array_values($this->fieldmap), 0, (int) $this->prop['sizelimit'], (int) $this->prop['timelimit'])) |
| | | { |
| | | $this->_debug("S: ".ldap_count_entries($this->conn, $this->ldap_result)." record(s)"); |
| | | return true; |
| | | } else |
| | | } |
| | | else |
| | | { |
| | | $this->_debug("S: ".ldap_error($this->conn)); |
| | | } |
| | | } |
| | | |
| | | return false; |
| | |
| | | /** |
| | | * @static |
| | | */ |
| | | function quote_string($str, $dn=false) |
| | | private function _quote_string($str, $dn=false) |
| | | { |
| | | // take firt entry if array given |
| | | if (is_array($str)) |
| | |
| | | { |
| | | if ($group_id) |
| | | { |
| | | if (! $this->group_cache) $this->list_groups(); |
| | | $cache = $this->group_cache[$group_id]['members']; |
| | | if (!$this->group_cache) |
| | | $this->list_groups(); |
| | | |
| | | $cache_members = $this->group_cache[$group_id]['members']; |
| | | |
| | | $members = array(); |
| | | for ($i=1; $i<$cache["count"]; $i++) |
| | | for ($i=1; $i<$cache_members["count"]; $i++) |
| | | { |
| | | $member_dn = base64_encode($cache[$i]); |
| | | $members[$member_dn] = 1; |
| | | $members[base64_encode($cache_members[$i])] = 1; |
| | | } |
| | | $this->group_members = $members; |
| | | $this->group_id = $group_id; |
| | | } |
| | | else $this->group_id = 0; |
| | | else |
| | | $this->group_id = 0; |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | function list_groups($search = null) |
| | | { |
| | | if (!$this->prop['groups']) |
| | | if (!$this->groups) |
| | | return array(); |
| | | |
| | | $base_dn = $this->prop['groups']['base_dn']; |
| | | $filter = $this->prop['groups']['filter']; |
| | | $filter = '(objectClass=groupOfNames)'; |
| | | |
| | | $res = ldap_search($this->conn, $base_dn, $filter, array('cn','member')); |
| | | if ($res === false) |
| | |
| | | $group_sortnames[] = strtolower($group_name); |
| | | } |
| | | array_multisort($group_sortnames, SORT_ASC, SORT_STRING, $groups); |
| | | |
| | | $this->group_cache = $groups; |
| | | |
| | | return $groups; |
| | | } |
| | | |
| | |
| | | */ |
| | | function get_record_groups($contact_id) |
| | | { |
| | | if (!$this->prop['groups']) |
| | | if (!$this->groups) |
| | | return array(); |
| | | |
| | | $base_dn = $this->prop['groups']['base_dn']; |
| | |
| | | return $groups; |
| | | } |
| | | } |
| | | |