Quoting Chuck Hagenbuch <[EMAIL PROTECTED]>:
I agree it would be nice, but that's more in the realm of an
enhancement than a security fix. We'll consider it for Turba 2.2, but
I'd like to get 2.1.7 out with the fixes now.
Finally, these should be the patches for the upcoming Turba 2.1.7 and
Turba 2.2-RC3 releases. I plan to roll them tomorrow (Friday) morning,
U.S Eastern time. I'm also attaching a patch for HEAD for anyone who
wants/needs it.
Thanks to Peter, and also Michael R. for the count checks.
-chuck
? urls
Index: docs/CHANGES
===================================================================
RCS file: /repository/turba/docs/CHANGES,v
retrieving revision 1.384
diff -u -r1.384 CHANGES
--- docs/CHANGES 10 Feb 2008 16:01:44 -0000 1.384
+++ docs/CHANGES 15 Feb 2008 05:56:34 -0000
@@ -9,6 +9,8 @@
v2.2-cvs
--------
+[cjh] SECURITY: Fix unchecked access to contacts in the same SQL table
+ (Bug #6208).
[jan] Add configuration to more flexibly parse full names into the name parts.
Index: lib/Driver.php
===================================================================
RCS file: /repository/turba/lib/Driver.php,v
retrieving revision 1.181
diff -u -r1.181 Driver.php
--- lib/Driver.php 11 Feb 2008 00:40:39 -0000 1.181
+++ lib/Driver.php 15 Feb 2008 05:56:34 -0000
@@ -618,9 +618,8 @@
*/
function &getObjects($objectIds)
{
- $criteria = $this->map['__key'];
-
- $objects = $this->_read($criteria, $objectIds,
+ $objects = $this->_read($this->map['__key'], $objectIds,
+ $this->getContactOwner(),
array_values($this->fields));
if (is_a($objects, 'PEAR_Error')) {
return $objects;
@@ -1573,22 +1572,22 @@
}
/**
- * Reads the given data from the address book and returns the result's
- * fields.
+ * Reads the given data from the address book and returns the results.
*
- * @param array $criteria Search criteria.
- * @param string $id Data identifier.
- * @param array $fields List of fields to return.
+ * @param string $key The primary key field to use.
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
- * @return Hash containing the search results.
+ * @return array Hash containing the search results.
*/
- function _read($criteria, $id, $fields)
+ function _read($key, $ids, $owner, $fields)
{
return PEAR::raiseError(_("Reading contacts is not available."));
}
/**
- * Adds the specified object to the SQL database.
+ * Adds the specified contact to the SQL database.
*/
function _add($attributes)
{
@@ -1596,7 +1595,7 @@
}
/**
- * Deletes the specified object from the SQL database.
+ * Deletes the specified contact from the SQL database.
*/
function _delete($object_key, $object_id)
{
Index: lib/Driver/imsp.php
===================================================================
RCS file: /repository/turba/lib/Driver/imsp.php,v
retrieving revision 1.61
diff -u -r1.61 imsp.php
--- lib/Driver/imsp.php 4 Jan 2008 18:53:28 -0000 1.61
+++ lib/Driver/imsp.php 15 Feb 2008 05:56:34 -0000
@@ -131,7 +131,7 @@
}
/* Now we have a list of names, get the rest. */
- $result = $this->_read('name', $names, $fields);
+ $result = $this->_read('name', $names, null, $fields);
if (is_array($result)) {
$results = $result;
}
@@ -143,32 +143,33 @@
/**
* Reads the given data from the IMSP server and returns the
- * result's fields.
+ * results.
*
- * @param array $criteria (Ignored: Always 'name' for IMSP) Search criteria.
- * @param array $id Array of data identifiers.
- * @param array $fields List of fields to return.
+ * @param string $key The primary key field to use (always 'name' for IMSP).
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
* @return array Hash containing the search results.
*/
- function _read($criteria, $id, $fields)
+ function _read($key, $ids, $owner, $fields)
{
$results = array();
if (!$this->_authenticated) {
return $results;
}
- $id = array_values($id);
- $idCount = count($id);
+ $ids = array_values($ids);
+ $idCount = count($ids);
$members = array();
$tmembers = array();
$IMSPGroups = array();
for ($i = 0; $i < $idCount; $i++) {
$result = array();
- if (!isset($IMSPGroups[$id[$i]])) {
- $temp = $this->_imsp->getEntry($this->_bookName, $id[$i]);
+ if (!isset($IMSPGroups[$ids[$i]])) {
+ $temp = $this->_imsp->getEntry($this->_bookName, $ids[$i]);
} else {
- $temp = $IMSPGroups[$id[$i]];
+ $temp = $IMSPGroups[$ids[$i]];
}
if (is_a($temp, 'PEAR_Error')) {
continue;
@@ -184,15 +185,15 @@
if ($this->_noGroups) {
continue;
}
- if (!isset($IMSPGroups[$id[$i]])) {
- $IMSPGroups[$id[$i]] = $temp;
+ if (!isset($IMSPGroups[$ids[$i]])) {
+ $IMSPGroups[$ids[$i]] = $temp;
}
// move group ids to end of list
if ($idCount > count($IMSPGroups) &&
$idCount - count($IMSPGroups) > $i) {
- $id[] = $id[$i];
- unset($id[$i]);
- $id = array_values($id);
+ $ids[] = $ids[$i];
+ unset($ids[$i]);
+ $ids = array_values($ids);
$i--;
continue;
}
@@ -289,7 +290,7 @@
// generally require an existing conact entry in the current
// address book for each group member (this is necessary for
// those sources that may be used both in AND out of Horde).
- $result = $this->_read('name', $members, array('email'));
+ $result = $this->_read('name', $members, null, array('email'));
if (!is_a($result, 'PEAR_Error')) {
$count = count($result);
for ($i = 0; $i < $count; $i++) {
Index: lib/Driver/kolab.php
===================================================================
RCS file: /repository/turba/lib/Driver/kolab.php,v
retrieving revision 1.32
diff -u -r1.32 kolab.php
--- lib/Driver/kolab.php 2 Jan 2008 11:14:04 -0000 1.32
+++ lib/Driver/kolab.php 15 Feb 2008 05:56:34 -0000
@@ -75,17 +75,18 @@
/**
* Read the given data from the Kolab message store and returns the
- * result's fields.
+ * results.
*
- * @param $criteria Search criteria.
- * @param $id Data identifier.
- * @param $fields List of fields to return.
+ * @param string $key The primary key field to use.
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
- * @return Hash containing the search results.
+ * @return array Hash containing the search results.
*/
- function _read($criteria, $id_list, $fields)
+ function _read($key, $ids, $owner, $fields)
{
- return $this->_wrapper->_read($criteria, $id_list, $fields);
+ return $this->_wrapper->_read($key, $ids, $fields);
}
/**
@@ -164,7 +165,7 @@
if (isset($params['params']['default']) && $params['params']['default'] === true) {
$share_id = Auth::getAuth();
}
-
+
$result = &Turba::createShare($share_id, $params);
return $result;
}
Index: lib/Driver/ldap.php
===================================================================
RCS file: /repository/turba/lib/Driver/ldap.php,v
retrieving revision 1.87
diff -u -r1.87 ldap.php
--- lib/Driver/ldap.php 4 Jan 2007 05:08:59 -0000 1.87
+++ lib/Driver/ldap.php 15 Feb 2008 05:56:34 -0000
@@ -167,18 +167,19 @@
/**
* Reads the LDAP directory for a given element and returns
- * the result's fields.
+ * the results.
*
- * @param string $criteria Search criteria (must be 'dn').
- * @param mixed $dn The dn of the object to read.
- * @param array $fields List of fields to return.
+ * @param string $key The primary key field to use.
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
* @return array Hash containing the search results.
*/
- function _read($criteria, $dn, $fields)
+ function _read($key, $ids, $owner, $fields)
{
/* Only DN. */
- if ($criteria != 'dn') {
+ if ($key != 'dn') {
return array();
}
@@ -192,9 +193,9 @@
}
/* Handle a request for multiple records. */
- if (is_array($dn)) {
+ if (is_array($ids)) {
$results = array();
- foreach ($dn as $d) {
+ foreach ($ids as $d) {
$res = @ldap_read($this->_ds, String::convertCharset($d, NLS::getCharset(), $this->_params['charset']), $filter, $attr);
if ($res) {
if (!is_a($result = $this->_getResults($fields, $res), 'PEAR_Error')) {
@@ -209,7 +210,7 @@
return $results;
}
- $res = @ldap_read($this->_ds, String::convertCharset($dn, NLS::getCharset(), $this->_params['charset']), $filter, $attr);
+ $res = @ldap_read($this->_ds, String::convertCharset($ids, NLS::getCharset(), $this->_params['charset']), $filter, $attr);
if (!$res) {
return PEAR::raiseError(sprintf(_("Read failed: (%s) %s"), ldap_errno($this->_ds), ldap_error($this->_ds)));
}
Index: lib/Driver/share.php
===================================================================
RCS file: /repository/turba/lib/Driver/share.php,v
retrieving revision 1.13
diff -u -r1.13 share.php
--- lib/Driver/share.php 4 Jan 2008 18:53:28 -0000 1.13
+++ lib/Driver/share.php 15 Feb 2008 05:56:34 -0000
@@ -106,18 +106,19 @@
}
/**
- * Reads the given data from the address book and returns the result's
- * fields.
+ * Reads the given data from the address book and returns the
+ * results.
*
- * @param array $criteria Search criteria.
- * @param string $id Data identifier.
- * @param array $fields List of fields to return.
+ * @param string $key The primary key field to use.
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
- * @return Hash containing the search results.
+ * @return array Hash containing the search results.
*/
- function _read($criteria, $id, $fields)
+ function _read($key, $ids, $owner, $fields)
{
- return $this->_driver->_read($criteria, $id, $fields);
+ return $this->_driver->_read($key, $ids, $owner, $fields);
}
/**
Index: lib/Driver/sql.php
===================================================================
RCS file: /repository/turba/lib/Driver/sql.php,v
retrieving revision 1.112
diff -u -r1.112 sql.php
--- lib/Driver/sql.php 4 Jan 2008 18:53:28 -0000 1.112
+++ lib/Driver/sql.php 15 Feb 2008 05:56:34 -0000
@@ -194,33 +194,38 @@
}
/**
- * Reads the given data from the SQL database and returns the result's
- * fields.
+ * Reads the given data from the SQL database and returns the
+ * results.
*
- * @param array $criteria Search criteria.
- * @param string $id Data identifier.
- * @param array $fields List of fields to return.
+ * @param string $key The primary key field to use.
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
- * @return Hash containing the search results.
+ * @return array Hash containing the search results.
*/
- function _read($criteria, $id, $fields)
+ function _read($key, $ids, $owner, $fields)
{
$values = array();
$in = '';
- if (is_array($id)) {
- if (!count($id)) {
+ if (is_array($ids)) {
+ if (!count($ids)) {
return array();
}
- foreach ($id as $key) {
+ foreach ($ids as $id) {
$in .= empty($in) ? '?' : ', ?';
- $values[] = $this->_convertToDriver($key);
+ $values[] = $this->_convertToDriver($id);
}
- $where = $criteria . ' IN (' . $in . ')';
+ $where = $key . ' IN (' . $in . ')';
} else {
- $where = $criteria . ' = ?';
- $values[] = $this->_convertToDriver($id);
+ $where = $key . ' = ?';
+ $values[] = $this->_convertToDriver($ids);
+ }
+ if (isset($this->map['__owner'])) {
+ $where .= ' AND ' . $this->map['__owner'] . ' = ?';
+ $values[] = $this->_convertToDriver($owner);
}
if (!empty($this->_params['filter'])) {
$where .= ' AND ' . $this->_params['filter'];
Index: lib/Driver/vbook.php
===================================================================
RCS file: /repository/turba/lib/Driver/vbook.php,v
retrieving revision 1.10
diff -u -r1.10 vbook.php
--- lib/Driver/vbook.php 4 Jan 2008 18:53:28 -0000 1.10
+++ lib/Driver/vbook.php 15 Feb 2008 05:56:34 -0000
@@ -99,18 +99,18 @@
}
/**
- * Reads the requested entries from the underlying source
+ * Reads the requested entries from the underlying source.
*
- * @param array $criteria The field to check against.
- * @param array $id Array of data identifiers.
- * @param array $fields List of fields to return.
+ * @param string $key The primary key field to use.
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
* @return array Hash containing the search results.
*/
- function _read($criteria, $id, $fields)
+ function _read($key, $ids, $owner, $fields)
{
- $results = $this->_driver->_read($criteria, $id, $fields);
- return $results;
+ return $this->_driver->_read($key, $ids, $owner, $fields);
}
/**
Index: lib/Object/Group.php
===================================================================
RCS file: /repository/turba/lib/Object/Group.php,v
retrieving revision 1.14
diff -u -r1.14 Group.php
--- lib/Object/Group.php 17 Jun 2007 18:21:18 -0000 1.14
+++ lib/Object/Group.php 15 Feb 2008 05:56:34 -0000
@@ -135,6 +135,23 @@
}
/**
+ * Count the number of contacts in this group.
+ *
+ * @return integer
+ *
+ * @since Turba 2.1.7
+ */
+ function count()
+ {
+ $children = @unserialize($this->attributes['__members']);
+ if (!is_array($children)) {
+ return 0;
+ } else {
+ return count($children);
+ }
+ }
+
+ /**
* Retrieve the Objects in this group
*
* @param array $sort The requested sort order which is passed to
@@ -171,14 +188,10 @@
$sourceId .= ':' . $owner;
}
$driver = &Turba_Driver::singleton($sourceId);
- // Don't prune contacts if the source is not
- // found, could just be temporarily unavailable.
if (!is_a($driver, 'PEAR_Error')) {
$contact = $driver->getObject($contactId);
if (is_a($contact, 'PEAR_Error')) {
- // Remove the contact if it no longer exists
- $this->removeMember($contactId, $sourceId);
- $modified = true;
+ continue;
}
} else {
continue;
Index: lib/Views/Browse.php
===================================================================
RCS file: /repository/turba/lib/Views/Browse.php,v
retrieving revision 1.14
diff -u -r1.14 Browse.php
--- lib/Views/Browse.php 2 Jan 2008 11:14:04 -0000 1.14
+++ lib/Views/Browse.php 15 Feb 2008 05:56:34 -0000
@@ -343,6 +343,10 @@
if (!is_object($results = $list->listMembers($sortorder))) {
$notification->push(_("Failed to browse list"), 'horde.error');
} else {
+ if ($results->count() != $list->count()) {
+ $notification->push(sprintf(_("There are %d contact(s) in this list that are not viewable to you"),
+ ($list->count() - $results->count())), 'horde.message');
+ }
$view = &new Turba_ListView($results, null, $columns);
$view->setType('list');
}Index: docs/CHANGES
===================================================================
RCS file: /repository/turba/docs/CHANGES,v
retrieving revision 1.181.2.130
diff -u -r1.181.2.130 CHANGES
--- docs/CHANGES 10 Feb 2008 16:11:37 -0000 1.181.2.130
+++ docs/CHANGES 15 Feb 2008 05:56:45 -0000
@@ -2,6 +2,8 @@
v2.2-cvs
--------
+[cjh] SECURITY: Fix unchecked access to contacts in the same SQL table
+ (Bug #6208).
[jan] Add configuration to more flexibly parse full names into the name parts.
Index: docs/RELEASE_NOTES
===================================================================
RCS file: /repository/turba/docs/RELEASE_NOTES,v
retrieving revision 1.22.2.30
diff -u -r1.22.2.30 RELEASE_NOTES
--- docs/RELEASE_NOTES 20 Jan 2008 16:27:41 -0000 1.22.2.30
+++ docs/RELEASE_NOTES 15 Feb 2008 05:56:45 -0000
@@ -12,11 +12,11 @@
* 8 - Minor security fixes
* 9 - Major security fixes
*/
-$this->notes['fm']['focus'] = 4;
+$this->notes['fm']['focus'] = 8;
/* Mailing list release notes. */
$this->notes['ml']['changes'] = <<<ML
-The Horde Team is pleased to announce the second release candidate of the Turba
+The Horde Team is pleased to announce the third release candidate of the Turba
Contact Manager version H3 (2.2).
Turba is the Horde contact management application. It is a production level
@@ -28,20 +28,13 @@
Testing is requested and comments are encouraged.
Updated translations would also be great.
-The major changes compared to the Turba version H3 (2.2-RC1) are:
- * Fixed privilege escalation in the Horde API.
- * Fixed several issues with composite fields.
- * Improved address book management.
- * Improved listTimeObjects API.
- * Further bugfixes and improvements.
+The major changes compared to the Turba version H3 (2.2-RC2) are:
+ * Fixed unchecked access to contacts in the same SQL table (Bug #6208).
ML;
/* Freshmeat release notes, not more than 600 characters. */
$this->notes['fm']['changes'] = <<<FM
-A privilege escalation in the Horde API has been fixed.
-Several issues with composite fields have been fixed.
-The address book management and the listTimeObjects API have been improved.
-Further bugfixes and improvements have been made.
+Fix unchecked access to contacts in the same SQL table.
FM;
$this->notes['name'] = 'Turba';
Index: lib/Driver.php
===================================================================
RCS file: /repository/turba/lib/Driver.php,v
retrieving revision 1.57.2.43
diff -u -r1.57.2.43 Driver.php
--- lib/Driver.php 11 Feb 2008 00:47:39 -0000 1.57.2.43
+++ lib/Driver.php 15 Feb 2008 05:56:45 -0000
@@ -599,9 +599,8 @@
*/
function &getObjects($objectIds)
{
- $criteria = $this->map['__key'];
-
- $objects = $this->_read($criteria, $objectIds,
+ $objects = $this->_read($this->map['__key'], $objectIds,
+ $this->getContactOwner(),
array_values($this->fields));
if (is_a($objects, 'PEAR_Error')) {
return $objects;
@@ -1554,22 +1553,22 @@
}
/**
- * Reads the given data from the address book and returns the result's
- * fields.
+ * Reads the given data from the address book and returns the results.
*
- * @param array $criteria Search criteria.
- * @param string $id Data identifier.
- * @param array $fields List of fields to return.
+ * @param string $key The primary key field to use.
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
- * @return Hash containing the search results.
+ * @return array Hash containing the search results.
*/
- function _read($criteria, $id, $fields)
+ function _read($key, $ids, $owner, $fields)
{
return PEAR::raiseError(_("Reading contacts is not available."));
}
/**
- * Adds the specified object to the SQL database.
+ * Adds the specified contact to the SQL database.
*/
function _add($attributes)
{
@@ -1577,7 +1576,7 @@
}
/**
- * Deletes the specified object from the SQL database.
+ * Deletes the specified contact from the SQL database.
*/
function _delete($object_key, $object_id)
{
Index: lib/Driver/imsp.php
===================================================================
RCS file: /repository/turba/lib/Driver/imsp.php,v
retrieving revision 1.21.4.19
diff -u -r1.21.4.19 imsp.php
--- lib/Driver/imsp.php 4 Jan 2008 19:13:21 -0000 1.21.4.19
+++ lib/Driver/imsp.php 15 Feb 2008 05:56:45 -0000
@@ -131,7 +131,7 @@
}
/* Now we have a list of names, get the rest. */
- $result = $this->_read('name', $names, $fields);
+ $result = $this->_read('name', $names, null, $fields);
if (is_array($result)) {
$results = $result;
}
@@ -143,32 +143,33 @@
/**
* Reads the given data from the IMSP server and returns the
- * result's fields.
+ * results.
*
- * @param array $criteria (Ignored: Always 'name' for IMSP) Search criteria.
- * @param array $id Array of data identifiers.
- * @param array $fields List of fields to return.
+ * @param string $key The primary key field to use (always 'name' for IMSP).
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
* @return array Hash containing the search results.
*/
- function _read($criteria, $id, $fields)
+ function _read($key, $ids, $owner, $fields)
{
$results = array();
if (!$this->_authenticated) {
return $results;
}
- $id = array_values($id);
- $idCount = count($id);
+ $ids = array_values($ids);
+ $idCount = count($ids);
$members = array();
$tmembers = array();
$IMSPGroups = array();
for ($i = 0; $i < $idCount; $i++) {
$result = array();
- if (!isset($IMSPGroups[$id[$i]])) {
- $temp = $this->_imsp->getEntry($this->_bookName, $id[$i]);
+ if (!isset($IMSPGroups[$ids[$i]])) {
+ $temp = $this->_imsp->getEntry($this->_bookName, $ids[$i]);
} else {
- $temp = $IMSPGroups[$id[$i]];
+ $temp = $IMSPGroups[$ids[$i]];
}
if (is_a($temp, 'PEAR_Error')) {
continue;
@@ -184,15 +185,15 @@
if ($this->_noGroups) {
continue;
}
- if (!isset($IMSPGroups[$id[$i]])) {
- $IMSPGroups[$id[$i]] = $temp;
+ if (!isset($IMSPGroups[$ids[$i]])) {
+ $IMSPGroups[$ids[$i]] = $temp;
}
// move group ids to end of list
if ($idCount > count($IMSPGroups) &&
$idCount - count($IMSPGroups) > $i) {
- $id[] = $id[$i];
- unset($id[$i]);
- $id = array_values($id);
+ $ids[] = $ids[$i];
+ unset($ids[$i]);
+ $ids = array_values($ids);
$i--;
continue;
}
@@ -289,7 +290,7 @@
// generally require an existing conact entry in the current
// address book for each group member (this is necessary for
// those sources that may be used both in AND out of Horde).
- $result = $this->_read('name', $members, array('email'));
+ $result = $this->_read('name', $members, null, array('email'));
if (!is_a($result, 'PEAR_Error')) {
$count = count($result);
for ($i = 0; $i < $count; $i++) {
Index: lib/Driver/kolab.php
===================================================================
RCS file: /repository/turba/lib/Driver/kolab.php,v
retrieving revision 1.5.10.11
diff -u -r1.5.10.11 kolab.php
--- lib/Driver/kolab.php 2 Jan 2008 11:32:40 -0000 1.5.10.11
+++ lib/Driver/kolab.php 15 Feb 2008 05:56:46 -0000
@@ -75,17 +75,18 @@
/**
* Read the given data from the Kolab message store and returns the
- * result's fields.
+ * results.
*
- * @param $criteria Search criteria.
- * @param $id Data identifier.
- * @param $fields List of fields to return.
+ * @param string $key The primary key field to use.
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
- * @return Hash containing the search results.
+ * @return array Hash containing the search results.
*/
- function _read($criteria, $id_list, $fields)
+ function _read($key, $ids, $owner, $fields)
{
- return $this->_wrapper->_read($criteria, $id_list, $fields);
+ return $this->_wrapper->_read($key, $ids, $fields);
}
/**
@@ -164,7 +165,7 @@
if (isset($params['params']['default']) && $params['params']['default'] === true) {
$share_id = Auth::getAuth();
}
-
+
$result = &Turba::createShare($share_id, $params);
return $result;
}
Index: lib/Driver/ldap.php
===================================================================
RCS file: /repository/turba/lib/Driver/ldap.php,v
retrieving revision 1.54.4.17
diff -u -r1.54.4.17 ldap.php
--- lib/Driver/ldap.php 20 Dec 2007 14:34:30 -0000 1.54.4.17
+++ lib/Driver/ldap.php 15 Feb 2008 05:56:46 -0000
@@ -167,18 +167,19 @@
/**
* Reads the LDAP directory for a given element and returns
- * the result's fields.
+ * the results.
*
- * @param string $criteria Search criteria (must be 'dn').
- * @param mixed $dn The dn of the object to read.
- * @param array $fields List of fields to return.
+ * @param string $key The primary key field to use.
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
* @return array Hash containing the search results.
*/
- function _read($criteria, $dn, $fields)
+ function _read($key, $ids, $owner, $fields)
{
/* Only DN. */
- if ($criteria != 'dn') {
+ if ($key != 'dn') {
return array();
}
@@ -192,9 +193,9 @@
}
/* Handle a request for multiple records. */
- if (is_array($dn)) {
+ if (is_array($ids)) {
$results = array();
- foreach ($dn as $d) {
+ foreach ($ids as $d) {
$res = @ldap_read($this->_ds, String::convertCharset($d, NLS::getCharset(), $this->_params['charset']), $filter, $attr);
if ($res) {
if (!is_a($result = $this->_getResults($fields, $res), 'PEAR_Error')) {
@@ -209,7 +210,7 @@
return $results;
}
- $res = @ldap_read($this->_ds, String::convertCharset($dn, NLS::getCharset(), $this->_params['charset']), $filter, $attr);
+ $res = @ldap_read($this->_ds, String::convertCharset($ids, NLS::getCharset(), $this->_params['charset']), $filter, $attr);
if (!$res) {
return PEAR::raiseError(sprintf(_("Read failed: (%s) %s"), ldap_errno($this->_ds), ldap_error($this->_ds)));
}
Index: lib/Driver/share.php
===================================================================
RCS file: /repository/turba/lib/Driver/share.php,v
retrieving revision 1.11.2.3
diff -u -r1.11.2.3 share.php
--- lib/Driver/share.php 4 Jan 2008 19:13:21 -0000 1.11.2.3
+++ lib/Driver/share.php 15 Feb 2008 05:56:46 -0000
@@ -106,18 +106,19 @@
}
/**
- * Reads the given data from the address book and returns the result's
- * fields.
+ * Reads the given data from the address book and returns the
+ * results.
*
- * @param array $criteria Search criteria.
- * @param string $id Data identifier.
- * @param array $fields List of fields to return.
+ * @param string $key The primary key field to use.
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
- * @return Hash containing the search results.
+ * @return array Hash containing the search results.
*/
- function _read($criteria, $id, $fields)
+ function _read($key, $ids, $owner, $fields)
{
- return $this->_driver->_read($criteria, $id, $fields);
+ return $this->_driver->_read($key, $ids, $owner, $fields);
}
/**
Index: lib/Driver/sql.php
===================================================================
RCS file: /repository/turba/lib/Driver/sql.php,v
retrieving revision 1.59.10.21
diff -u -r1.59.10.21 sql.php
--- lib/Driver/sql.php 4 Jan 2008 19:13:21 -0000 1.59.10.21
+++ lib/Driver/sql.php 15 Feb 2008 05:56:46 -0000
@@ -194,33 +194,38 @@
}
/**
- * Reads the given data from the SQL database and returns the result's
- * fields.
+ * Reads the given data from the SQL database and returns the
+ * results.
*
- * @param array $criteria Search criteria.
- * @param string $id Data identifier.
- * @param array $fields List of fields to return.
+ * @param string $key The primary key field to use.
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
- * @return Hash containing the search results.
+ * @return array Hash containing the search results.
*/
- function _read($criteria, $id, $fields)
+ function _read($key, $ids, $owner, $fields)
{
$values = array();
$in = '';
- if (is_array($id)) {
- if (!count($id)) {
+ if (is_array($ids)) {
+ if (!count($ids)) {
return array();
}
- foreach ($id as $key) {
+ foreach ($ids as $id) {
$in .= empty($in) ? '?' : ', ?';
- $values[] = $this->_convertToDriver($key);
+ $values[] = $this->_convertToDriver($id);
}
- $where = $criteria . ' IN (' . $in . ')';
+ $where = $key . ' IN (' . $in . ')';
} else {
- $where = $criteria . ' = ?';
- $values[] = $this->_convertToDriver($id);
+ $where = $key . ' = ?';
+ $values[] = $this->_convertToDriver($ids);
+ }
+ if (isset($this->map['__owner'])) {
+ $where .= ' AND ' . $this->map['__owner'] . ' = ?';
+ $values[] = $this->_convertToDriver($owner);
}
if (!empty($this->_params['filter'])) {
$where .= ' AND ' . $this->_params['filter'];
Index: lib/Driver/vbook.php
===================================================================
RCS file: /repository/turba/lib/Driver/vbook.php,v
retrieving revision 1.8.2.3
diff -u -r1.8.2.3 vbook.php
--- lib/Driver/vbook.php 4 Jan 2008 19:13:21 -0000 1.8.2.3
+++ lib/Driver/vbook.php 15 Feb 2008 05:56:46 -0000
@@ -99,18 +99,18 @@
}
/**
- * Reads the requested entries from the underlying source
+ * Reads the requested entries from the underlying source.
*
- * @param array $criteria The field to check against.
- * @param array $id Array of data identifiers.
- * @param array $fields List of fields to return.
+ * @param string $key The primary key field to use.
+ * @param mixed $ids The ids of the contacts to load.
+ * @param string $owner Only return contacts owned by this user.
+ * @param array $fields List of fields to return.
*
* @return array Hash containing the search results.
*/
- function _read($criteria, $id, $fields)
+ function _read($key, $ids, $owner, $fields)
{
- $results = $this->_driver->_read($criteria, $id, $fields);
- return $results;
+ return $this->_driver->_read($key, $ids, $owner, $fields);
}
/**
Index: lib/Object/Group.php
===================================================================
RCS file: /repository/turba/lib/Object/Group.php,v
retrieving revision 1.9.2.3
diff -u -r1.9.2.3 Group.php
--- lib/Object/Group.php 20 Dec 2007 14:34:31 -0000 1.9.2.3
+++ lib/Object/Group.php 15 Feb 2008 05:56:46 -0000
@@ -135,6 +135,23 @@
}
/**
+ * Count the number of contacts in this group.
+ *
+ * @return integer
+ *
+ * @since Turba 2.1.7
+ */
+ function count()
+ {
+ $children = @unserialize($this->attributes['__members']);
+ if (!is_array($children)) {
+ return 0;
+ } else {
+ return count($children);
+ }
+ }
+
+ /**
* Retrieve the Objects in this group
*
* @param array $sort The requested sort order which is passed to
@@ -171,14 +188,10 @@
$sourceId .= ':' . $owner;
}
$driver = &Turba_Driver::singleton($sourceId);
- // Don't prune contacts if the source is not
- // found, could just be temporarily unavailable.
if (!is_a($driver, 'PEAR_Error')) {
$contact = $driver->getObject($contactId);
if (is_a($contact, 'PEAR_Error')) {
- // Remove the contact if it no longer exists
- $this->removeMember($contactId, $sourceId);
- $modified = true;
+ continue;
}
} else {
continue;
Index: lib/Views/Browse.php
===================================================================
RCS file: /repository/turba/lib/Views/Browse.php,v
retrieving revision 1.12.2.3
diff -u -r1.12.2.3 Browse.php
--- lib/Views/Browse.php 2 Jan 2008 11:32:40 -0000 1.12.2.3
+++ lib/Views/Browse.php 15 Feb 2008 05:56:46 -0000
@@ -343,6 +343,10 @@
if (!is_object($results = $list->listMembers($sortorder))) {
$notification->push(_("Failed to browse list"), 'horde.error');
} else {
+ if ($results->count() != $list->count()) {
+ $notification->push(sprintf(_("There are %d contact(s) in this list that are not viewable to you"),
+ ($list->count() - $results->count())), 'horde.message');
+ }
$view = &new Turba_ListView($results, null, $columns);
$view->setType('list');
}Index: browse.php
===================================================================
RCS file: /repository/turba/browse.php,v
retrieving revision 1.76.2.25
diff -u -r1.76.2.25 browse.php
--- browse.php 3 Aug 2007 23:54:05 -0000 1.76.2.25
+++ browse.php 15 Feb 2008 05:56:26 -0000
@@ -315,6 +315,10 @@
if (!is_object($results = $list->listMembers($sortcolumn, $prefs->getValue('sortdir')))) {
$notification->push(_("Failed to browse list"), 'horde.error');
} else {
+ if ($results->count() != $list->count()) {
+ $notification->push(sprintf(_("There are %d contact(s) in this list that are not viewable to you"),
+ ($list->count() - $results->count())), 'horde.message');
+ }
$view = &new Turba_ListView($results);
$view->setType('list');
}
Index: docs/CHANGES
===================================================================
RCS file: /repository/turba/docs/CHANGES,v
retrieving revision 1.181.2.114.2.3
diff -u -r1.181.2.114.2.3 CHANGES
--- docs/CHANGES 9 Jan 2008 22:41:10 -0000 1.181.2.114.2.3
+++ docs/CHANGES 15 Feb 2008 05:56:26 -0000
@@ -2,7 +2,8 @@
v2.1.7-cvs
----------
-
+[cjh] SECURITY: Fix unchecked access to contacts in the same SQL table
+ (Bug #6208).
------
Index: docs/RELEASE_NOTES
===================================================================
RCS file: /repository/turba/docs/RELEASE_NOTES,v
retrieving revision 1.22.2.28.2.2
diff -u -r1.22.2.28.2.2 RELEASE_NOTES
--- docs/RELEASE_NOTES 9 Jan 2008 13:33:07 -0000 1.22.2.28.2.2
+++ docs/RELEASE_NOTES 15 Feb 2008 05:56:26 -0000
@@ -17,25 +17,24 @@
/* Mailing list release notes. */
$this->notes['ml']['changes'] = <<<ML
The Horde Team is pleased to announce the final release of the Turba Contact
-Manager version H3 (2.1.6).
+Manager version H3 (2.1.7).
-This is a security release that fixes a privilege escalation in the Horde
-API. All users are encouraged to upgrade to this version.
+This is a security release that fixes unchecked access to contacts in
+the same SQL table, if the unique key of another user's contact can be
+guessed. All users are encouraged to upgrade to this version.
Turba is the Horde contact management application. It is a production level
address book, and makes heavy use of the Horde framework to provide
integration with IMP and other Horde applications. It supports SQL, LDAP,
Kolab, and IMSP address books.
-Major changes compared to the Turba H3 (2.1.5) version are:
- * Fixed privilege escalation in the Horde API.
- * Updated Japanese translation.
+Major changes compared to the Turba H3 (2.1.6) version are:
+ * Fixed unchecked access to contacts in the same SQL table (Bug #6208).
ML;
/* Freshmeat release notes, not more than 600 characters. */
$this->notes['fm']['changes'] = <<<FM
-A privilege escalation in the Horde API has been fixed.
-The Japanese translation has been updated.
+Fix unchecked access to contacts in the same SQL table.
FM;
$this->notes['name'] = 'Turba';
Index: lib/Driver/sql.php
===================================================================
RCS file: /repository/turba/lib/Driver/sql.php,v
retrieving revision 1.59.10.17
diff -u -r1.59.10.17 sql.php
--- lib/Driver/sql.php 30 Nov 2006 21:33:47 -0000 1.59.10.17
+++ lib/Driver/sql.php 15 Feb 2008 05:56:26 -0000
@@ -182,6 +182,15 @@
$where = $criteria . ' = ?';
$values[] = $this->_convertToDriver($id);
}
+ if (isset($this->map['__owner'])) {
+ if ($this->usingShares) {
+ $owner = $this->share->get('uid');
+ } else {
+ $owner = Auth::getAuth();
+ }
+ $where .= ' AND ' . $this->map['__owner'] . ' = ?';
+ $values[] = $this->_convertToDriver($owner);
+ }
if (!empty($this->_params['filter'])) {
$where .= ' AND ' . $this->_params['filter'];
}
Index: lib/Object/Group.php
===================================================================
RCS file: /repository/turba/lib/Object/Group.php,v
retrieving revision 1.9.2.2
diff -u -r1.9.2.2 Group.php
--- lib/Object/Group.php 14 Nov 2005 21:03:27 -0000 1.9.2.2
+++ lib/Object/Group.php 15 Feb 2008 05:56:26 -0000
@@ -124,6 +124,23 @@
}
/**
+ * Count the number of contacts in this group.
+ *
+ * @return integer
+ *
+ * @since Turba 2.1.7
+ */
+ function count()
+ {
+ $children = @unserialize($this->attributes['__members']);
+ if (!is_array($children)) {
+ return 0;
+ } else {
+ return count($children);
+ }
+ }
+
+ /**
* Retrieve the Objects in this group
*
* @param $sort_criteria The requested sort order which is passed to
@@ -163,14 +180,10 @@
$sourceId .= ':' . $owner;
}
$driver = &Turba_Driver::singleton($sourceId);
- // Don't prune contacts if the source is not
- // found, could just be temporarily unavailable.
if (!is_a($driver, 'PEAR_Error')) {
$contact = $driver->getObject($contactId);
if (is_a($contact, 'PEAR_Error')) {
- // Remove the contact if it no longer exists
- $this->removeMember($contactId, $sourceId);
- $modified = true;
+ continue;
}
} else {
continue;