From bffca14d964091b3256868bc42bcb9417a72629b Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Tue, 19 Jan 2016 03:37:29 -0500 Subject: [PATCH] Exit when imagecreatetruecolor() fails --- program/lib/Roundcube/rcube_ldap.php | 239 ++++++++++++++++++++++++++++++++++------------------------- 1 files changed, 138 insertions(+), 101 deletions(-) diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index 274616a..b08ee7b 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -1,6 +1,6 @@ <?php -/* +/** +-----------------------------------------------------------------------+ | This file is part of the Roundcube Webmail client | | Copyright (C) 2006-2013, The Roundcube Dev Team | @@ -38,6 +38,7 @@ // private properties protected $ldap; + protected $formats = array(); protected $prop = array(); protected $fieldmap = array(); protected $filter = ''; @@ -45,7 +46,7 @@ protected $result; protected $ldap_result; protected $mail_domain = ''; - protected $debug = false; + protected $debug = false; /** * Group objectclass (lowercase) to member attribute mapping @@ -64,7 +65,6 @@ private $base_dn = ''; private $groups_base_dn = ''; - private $group_url; private $group_data; private $group_search_cache; private $cache; @@ -118,23 +118,40 @@ // fieldmap property is given if (is_array($p['fieldmap'])) { + $p['fieldmap'] = array_filter($p['fieldmap']); foreach ($p['fieldmap'] as $rf => $lf) - $this->fieldmap[$rf] = $this->_attr_name(strtolower($lf)); + $this->fieldmap[$rf] = $this->_attr_name($lf); } else if (!empty($p)) { // read deprecated *_field properties to remain backwards compatible foreach ($p as $prop => $value) - if (preg_match('/^(.+)_field$/', $prop, $matches)) - $this->fieldmap[$matches[1]] = $this->_attr_name(strtolower($value)); + if (!empty($value) && preg_match('/^(.+)_field$/', $prop, $matches)) + $this->fieldmap[$matches[1]] = $this->_attr_name($value); } // use fieldmap to advertise supported coltypes to the application foreach ($this->fieldmap as $colv => $lfv) { list($col, $type) = explode(':', $colv); - list($lf, $limit, $delim) = explode(':', $lfv); + $params = explode(':', $lfv); - if ($limit == '*') $limit = null; - else $limit = max(1, intval($limit)); + $lf = array_shift($params); + $limit = 1; + + foreach ($params as $idx => $param) { + // field format specification + if (preg_match('/^(date)\[(.+)\]$/i', $param, $m)) { + $this->formats[$lf] = array('type' => strtolower($m[1]), 'format' => $m[2]); + } + // first argument is a limit + else if ($idx === 0) { + if ($param == '*') $limit = null; + else $limit = max(1, intval($param)); + } + // second is a composite field separator + else if ($idx === 1 && $param) { + $this->coltypes[$col]['serialized'][$type] = $param; + } + } if (!is_array($this->coltypes[$col])) { $subtypes = $type ? array($type) : null; @@ -146,10 +163,7 @@ $this->coltypes[$col]['limit'] += $limit; } - if ($delim) - $this->coltypes[$col]['serialized'][$type] = $delim; - - $this->fieldmap[$colv] = $lf; + $this->fieldmap[$colv] = $lf; } // support for composite address @@ -195,7 +209,7 @@ } foreach ($this->prop['required_fields'] as $key => $val) { - $this->prop['required_fields'][$key] = $this->_attr_name(strtolower($val)); + $this->prop['required_fields'][$key] = $this->_attr_name($val); } // Build sub_fields filter @@ -239,10 +253,9 @@ $this->_connect(); } - /** - * Establish a connection to the LDAP server - */ + * Establish a connection to the LDAP server + */ private function _connect() { $rcube = rcube::get_instance(); @@ -272,8 +285,7 @@ $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->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']) { @@ -283,12 +295,21 @@ } // Get the pieces needed for variable replacement. - if ($fu = $rcube->get_user_email()) + if ($fu = $rcube->get_user_email()) { list($u, $d) = explode('@', $fu); - else + } + else { $d = $this->mail_domain; + } $dc = 'dc='.strtr($d, array('.' => ',dc=')); // hierarchal domain string + + // resolve $dc through LDAP + if (!empty($this->prop['domain_filter']) && !empty($this->prop['search_bind_dn']) && + method_exists($this->ldap, 'domain_root_dn')) { + $this->ldap->bind($this->prop['search_bind_dn'], $this->prop['search_bind_pw']); + $dc = $this->ldap->domain_root_dn($d); + } $replaces = array('%dn' => '', '%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u); @@ -430,7 +451,6 @@ return $this->ready; } - /** * Close connection to LDAP server */ @@ -441,7 +461,6 @@ } } - /** * Returns address book name * @@ -451,7 +470,6 @@ { return $this->prop['name']; } - /** * Set internal list page @@ -475,7 +493,6 @@ $this->ldap->set_vlv_page($this->list_page, $this->page_size); } - /** * Set internal sort settings * @@ -488,7 +505,6 @@ $this->sort_col = $this->coltypes[$sort_col]['attributes'][0]; } - /** * Save a search string for future listings * @@ -498,7 +514,6 @@ { $this->filter = $filter; } - /** * Getter for saved search properties @@ -510,7 +525,6 @@ return $this->filter; } - /** * Reset all saved results and search parameters */ @@ -521,14 +535,13 @@ $this->filter = ''; } - /** * List the current set of contact records * - * @param array List of cols to show - * @param int Only return this number of records + * @param array List of cols to show + * @param int Only return this number of records * - * @return array Indexed list of contact records, each a hash array + * @return array Indexed list of contact records, each a hash array */ function list_records($cols=null, $subset=0) { @@ -663,7 +676,7 @@ $attrib = array_merge($attrib, array_values($this->group_types)); $attrib[] = 'memberURL'; - $filter = $this->prop['groups']['member_filter'] ? $this->prop['groups']['member_filter'] : '(objectclass=*)'; + $filter = $this->prop['groups']['member_filter'] ?: '(objectclass=*)'; for ($i=0; $i < $entry[$attr]['count']; $i++) { if (empty($entry[$attr][$i])) @@ -698,8 +711,9 @@ for ($i=0; $i < $entry['memberurl']['count']; $i++) { // extract components from url - if (!preg_match('!ldap:///([^\?]+)\?\?(\w+)\?(.*)$!', $entry['memberurl'][$i], $m)) + if (!preg_match('!ldap://[^/]*/([^\?]+)\?\?(\w+)\?(.*)$!', $entry['memberurl'][$i], $m)) { continue; + } // add search filter if any $filter = $this->filter ? '(&(' . $m[3] . ')(' . $this->filter . '))' : $m[3]; @@ -725,7 +739,6 @@ { return strcmp($a[$this->sort_col][0], $b[$this->sort_col][0]); } - /** * Search contacts @@ -766,16 +779,16 @@ if ($this->prop['vlv_search'] && $this->ready && join(',', (array)$fields) == join(',', $list_fields)) { $this->result = new rcube_result_set(0); - $search_suffix = $this->prop['fuzzy_search'] && $mode != 1 ? '*' : ''; + $this->ldap->config_set('fuzzy_search', intval($this->prop['fuzzy_search'] && $mode != 1)); $ldap_data = $this->ldap->search($this->base_dn, $this->prop['filter'], $this->prop['scope'], $this->prop['attributes'], - array('search' => $value . $search_suffix /*, 'sort' => $this->prop['sort'] */)); + array('search' => $value /*, 'sort' => $this->prop['sort'] */)); if ($ldap_data === false) { return $this->result; } // get all entries of this page and post-filter those that really match the query $search = mb_strtolower($value); - foreach ($ldap_data as $i => $entry) { + foreach ($ldap_data as $entry) { $rec = $this->_ldap2result($entry); foreach ($fields as $f) { foreach ((array)$rec[$f] as $val) { @@ -791,33 +804,24 @@ return $this->result; } - // use AND operator for advanced searches - $filter = is_array($value) ? '(&' : '(|'; - // set wildcards - $wp = $ws = ''; - if (!empty($this->prop['fuzzy_search']) && $mode != 1) { - $ws = '*'; - if (!$mode) { - $wp = '*'; - } - } + // advanced per-attribute search + if (is_array($value)) { + // use AND operator for advanced searches + $filter = '(&'; - if ($fields == '*') { - // search_fields are required for fulltext search - if (empty($this->prop['search_fields'])) { - $this->set_error(self::ERROR_SEARCH, 'nofulltextsearch'); - $this->result = new rcube_result_set(); - return $this->result; - } - if (is_array($this->prop['search_fields'])) { - foreach ($this->prop['search_fields'] as $field) { - $filter .= "($field=$wp" . rcube_ldap_generic::quote_string($value) . "$ws)"; + // set wildcards + $wp = $ws = ''; + if (!empty($this->prop['fuzzy_search']) && $mode != 1) { + $ws = '*'; + if (!$mode) { + $wp = '*'; } } - } - else { + foreach ((array)$fields as $idx => $field) { - $val = is_array($value) ? $value[$idx] : $value; + $val = $value[$idx]; + if (!strlen($val)) + continue; if ($attrs = $this->_map_field($field)) { if (count($attrs) > 1) $filter .= '(|'; @@ -827,8 +831,32 @@ $filter .= ')'; } } + + $filter .= ')'; } - $filter .= ')'; + else { + if ($fields == '*') { + // search_fields are required for fulltext search + if (empty($this->prop['search_fields'])) { + $this->set_error(self::ERROR_SEARCH, 'nofulltextsearch'); + $this->result = new rcube_result_set(); + return $this->result; + } + $attributes = (array)$this->prop['search_fields']; + } + else { + // map address book fields into ldap attributes + $attributes = array(); + foreach ((array) $fields as $field) { + if ($this->coltypes[$field] && ($attrs = $this->coltypes[$field]['attributes'])) { + $attributes = array_merge($attributes, (array) $attrs); + } + } + } + + // compose a full-text-like search filter + $filter = rcube_ldap_generic::fulltext_search_filter($value, $attributes, $mode); + } // add required (non empty) fields filter $req_filter = ''; @@ -866,7 +894,6 @@ return $this->result; } - /** * Count number of available contacts in database * @@ -895,7 +922,6 @@ return new rcube_result_set($count, ($this->list_page-1) * $this->page_size); } - /** * Return the last result set * @@ -905,7 +931,6 @@ { return $this->result; } - /** * Get a specific contact record @@ -948,6 +973,22 @@ return $assoc ? $res : $this->result; } + /** + * Returns the last error occurred (e.g. when updating/inserting failed) + * + * @return array Hash array with the following fields: type, message + */ + function get_error() + { + $err = $this->error; + + // check ldap connection for errors + if (!$err && $this->ldap->get_error()) { + $err = array(self::ERROR_SEARCH, $this->ldap->get_error()); + } + + return $err; + } /** * Check the given data before saving. @@ -1020,15 +1061,17 @@ return true; } - /** * Create a new contact record * - * @param array Hash array with save data + * @param array Associative array with save data + * Keys: Field name with optional section in the form FIELD:SECTION + * Values: Field value. Can be either a string or an array of strings for multiple values + * @param boolean True to check for duplicates first * - * @return encoded record ID on success, False on error + * @return mixed The created record ID on success, False on error */ - function insert($save_cols) + function insert($save_cols, $check = false) { // Map out the column names to their LDAP ones to build the new entry. $newentry = $this->_map_data($save_cols); @@ -1089,7 +1132,6 @@ return $dn; } - /** * Update a specific contact record @@ -1269,9 +1311,8 @@ } } - return $newdn ? $newdn : true; + return $newdn ?: true; } - /** * Mark one or more contact records as deleted @@ -1322,7 +1363,6 @@ return count($ids); } - /** * Remove all contact records * @@ -1331,7 +1371,7 @@ function delete_all($with_groups = false) { // searching for contact entries - $dn_list = $this->ldap->list_entries($this->base_dn, $this->prop['filter'] ? $this->prop['filter'] : '(objectclass=*)'); + $dn_list = $this->ldap->list_entries($this->base_dn, $this->prop['filter'] ?: '(objectclass=*)'); if (!empty($dn_list)) { foreach ($dn_list as $idx => $entry) { @@ -1391,7 +1431,6 @@ } } - /** * Converts LDAP entry into an array */ @@ -1407,7 +1446,7 @@ if ($this->is_group_entry($rec)) { $out['_type'] = 'group'; $out['readonly'] = true; - $fieldmap['name'] = $this->group_data['name_attr'] ? $this->group_data['name_attr'] : $this->prop['groups']['name_attr']; + $fieldmap['name'] = $this->group_data['name_attr'] ?: $this->prop['groups']['name_attr']; } // assign object type from object class mapping @@ -1432,7 +1471,7 @@ if ($col == 'email' && $this->mail_domain && !strpos($value, '@')) $out[$rf][] = sprintf('%s@%s', $value, $this->mail_domain); else if (in_array($col, array('street','zipcode','locality','country','region'))) - $out['address'.($subtype?':':'').$subtype][$i][$col] = $value; + $out['address' . ($subtype ? ':' : '') . $subtype][$i][$col] = $value; else if ($col == 'address' && strpos($value, '$') !== false) // address data is represented as string separated with $ list($out[$rf][$i]['street'], $out[$rf][$i]['locality'], $out[$rf][$i]['zipcode'], $out[$rf][$i]['country']) = explode('$', $value); else if ($rec[$lf]['count'] > 1) @@ -1450,7 +1489,6 @@ return $out; } - /** * Return LDAP attribute(s) for the given field */ @@ -1458,7 +1496,6 @@ { return (array)$this->coltypes[$field]['attributes']; } - /** * Convert a record data set into LDAP field attributes @@ -1512,9 +1549,22 @@ } } + foreach ($this->formats as $fld => $format) { + if (empty($ldap_data[$fld])) { + continue; + } + + switch ($format['type']) { + case 'date': + if ($dt = rcube_utils::anytodatetime($ldap_data[$fld])) { + $ldap_data[$fld] = $dt->format($format['format']); + } + break; + } + } + return $ldap_data; } - /** * Returns unified attribute name (resolving aliases) @@ -1532,6 +1582,7 @@ list($name, $limit) = explode(':', $namev, 2); $suffix = $limit ? ':'.$limit : ''; + $name = strtolower($name); return (isset($aliases[$name]) ? $aliases[$name] : $name) . $suffix; } @@ -1547,17 +1598,6 @@ } /** - * Prints debug info to the log - */ - private function _debug($str) - { - if ($this->debug) { - rcube::write_log('ldap', $str); - } - } - - - /** * Activate/deactivate debug mode * * @param boolean $dbg True if LDAP commands should be logged @@ -1570,7 +1610,6 @@ $this->ldap->config_set('debug', $dbg); } } - /** * Setter for the current group @@ -1609,7 +1648,7 @@ if ($search) { foreach ($group_cache as $group) { - if ($this->compare_search_value('name', $group['name'], $search, $mode)) { + if ($this->compare_search_value('name', $group['name'], mb_strtolower($search), $mode)) { $groups[] = $group; } } @@ -1661,7 +1700,7 @@ $filter = $this->prop['groups']['filter']; $scope = $this->prop['groups']['scope']; $name_attr = $this->prop['groups']['name_attr']; - $email_attr = $this->prop['groups']['email_attr'] ? $this->prop['groups']['email_attr'] : 'mail'; + $email_attr = $this->prop['groups']['email_attr'] ?: 'mail'; $sort_attrs = $this->prop['groups']['sort'] ? (array)$this->prop['groups']['sort'] : array($name_attr); $sort_attr = $sort_attrs[0]; @@ -1809,11 +1848,11 @@ $new_dn = 'cn=' . rcube_ldap_generic::quote_string($group_name, true) . ',' . $this->groups_base_dn; $new_gid = self::dn_encode($new_dn); $member_attr = $this->get_group_member_attr(); - $name_attr = $this->prop['groups']['name_attr'] ? $this->prop['groups']['name_attr'] : 'cn'; + $name_attr = $this->prop['groups']['name_attr'] ?: 'cn'; $new_entry = array( 'objectClass' => $this->prop['groups']['object_classes'], - $name_attr => $group_name, - $member_attr => '', + $name_attr => $group_name, + $member_attr => '', ); if (!$this->ldap->add_entry($new_dn, $new_entry)) { @@ -1965,7 +2004,7 @@ $base_dn = $this->groups_base_dn; $contact_dn = self::dn_decode($contact_id); - $name_attr = $this->prop['groups']['name_attr'] ? $this->prop['groups']['name_attr'] : 'cn'; + $name_attr = $this->prop['groups']['name_attr'] ?: 'cn'; $member_attr = $this->get_group_member_attr(); $add_filter = ''; @@ -1974,7 +2013,7 @@ $filter = strtr("(|(member=$contact_dn)(uniqueMember=$contact_dn)$add_filter)", array('\\' => '\\\\')); $ldap_data = $this->ldap->search($base_dn, $filter, 'sub', array('dn', $name_attr)); - if ($res === false) { + if ($ldap_data === false) { return array(); } @@ -2014,7 +2053,6 @@ return $default; } - /** * HTML-safe DN string encoding * @@ -2041,5 +2079,4 @@ $str = str_pad(strtr($str, '-_', '+/'), strlen($str) % 4, '=', STR_PAD_RIGHT); return base64_decode($str); } - } -- Gitblit v1.9.1