From a7c4ebf15d411e8958d0d56a94c6407db7197317 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 12 Dec 2013 09:45:18 +0100 Subject: [PATCH] Fix kolab cache issues with malformed/unsupported character sequences being stored in data, xml and words columns, which caused malformed (and inaccessible) objects (Bug #1912, #2662) --- plugins/libkolab/SQL/mysql.initial.sql | 18 ++++++------- plugins/libkolab/SQL/mysql/2013121100.sql | 13 ++++++++++ plugins/libkolab/lib/kolab_storage_cache.php | 27 ++++++++++++++++---- 3 files changed, 44 insertions(+), 14 deletions(-) create mode 100644 plugins/libkolab/SQL/mysql/2013121100.sql diff --git a/plugins/libkolab/SQL/mysql.initial.sql b/plugins/libkolab/SQL/mysql.initial.sql index fcb51b0e..40b86316 100644 --- a/plugins/libkolab/SQL/mysql.initial.sql +++ b/plugins/libkolab/SQL/mysql.initial.sql @@ -30,7 +30,7 @@ CREATE TABLE `kolab_cache_contact` ( `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` TEXT NOT NULL, - `xml` LONGTEXT NOT NULL, + `xml` LONGBLOB NOT NULL, `tags` VARCHAR(255) NOT NULL, `words` TEXT NOT NULL, `type` VARCHAR(32) CHARACTER SET ascii NOT NULL, @@ -49,7 +49,7 @@ CREATE TABLE `kolab_cache_event` ( `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` TEXT NOT NULL, - `xml` TEXT NOT NULL, + `xml` LONGBLOB NOT NULL, `tags` VARCHAR(255) NOT NULL, `words` TEXT NOT NULL, `dtstart` DATETIME, @@ -68,7 +68,7 @@ CREATE TABLE `kolab_cache_task` ( `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` TEXT NOT NULL, - `xml` TEXT NOT NULL, + `xml` LONGBLOB NOT NULL, `tags` VARCHAR(255) NOT NULL, `words` TEXT NOT NULL, `dtstart` DATETIME, @@ -87,7 +87,7 @@ CREATE TABLE `kolab_cache_journal` ( `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` TEXT NOT NULL, - `xml` TEXT NOT NULL, + `xml` LONGBLOB NOT NULL, `tags` VARCHAR(255) NOT NULL, `words` TEXT NOT NULL, `dtstart` DATETIME, @@ -106,7 +106,7 @@ CREATE TABLE `kolab_cache_note` ( `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` TEXT NOT NULL, - `xml` TEXT NOT NULL, + `xml` LONGBLOB NOT NULL, `tags` VARCHAR(255) NOT NULL, `words` TEXT NOT NULL, CONSTRAINT `fk_kolab_cache_note_folder` FOREIGN KEY (`folder_id`) @@ -123,7 +123,7 @@ CREATE TABLE `kolab_cache_file` ( `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` TEXT NOT NULL, - `xml` TEXT NOT NULL, + `xml` LONGBLOB NOT NULL, `tags` VARCHAR(255) NOT NULL, `words` TEXT NOT NULL, `filename` varchar(255) DEFAULT NULL, @@ -142,7 +142,7 @@ CREATE TABLE `kolab_cache_configuration` ( `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` TEXT NOT NULL, - `xml` TEXT NOT NULL, + `xml` LONGBLOB NOT NULL, `tags` VARCHAR(255) NOT NULL, `words` TEXT NOT NULL, `type` VARCHAR(32) CHARACTER SET ascii NOT NULL, @@ -161,7 +161,7 @@ CREATE TABLE `kolab_cache_freebusy` ( `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` TEXT NOT NULL, - `xml` TEXT NOT NULL, + `xml` LONGBLOB NOT NULL, `tags` VARCHAR(255) NOT NULL, `words` TEXT NOT NULL, `dtstart` DATETIME, @@ -172,4 +172,4 @@ CREATE TABLE `kolab_cache_freebusy` ( ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; -INSERT INTO `system` (`name`, `value`) VALUES ('libkolab-version', '2013110400'); +INSERT INTO `system` (`name`, `value`) VALUES ('libkolab-version', '2013121100'); diff --git a/plugins/libkolab/SQL/mysql/2013121100.sql b/plugins/libkolab/SQL/mysql/2013121100.sql new file mode 100644 index 00000000..8cab5ef3 --- /dev/null +++ b/plugins/libkolab/SQL/mysql/2013121100.sql @@ -0,0 +1,13 @@ +-- well, these deletes are really optional +-- we can clear all caches or only contacts/events/tasks +-- the issue we're fixing here was about contacts (Bug #2662) +DELETE FROM `kolab_folders` WHERE `type` IN ('contact', 'event', 'task'); + +ALTER TABLE `kolab_cache_contact` CHANGE `xml` `xml` LONGBLOB NOT NULL; +ALTER TABLE `kolab_cache_event` CHANGE `xml` `xml` LONGBLOB NOT NULL; +ALTER TABLE `kolab_cache_task` CHANGE `xml` `xml` LONGBLOB NOT NULL; +ALTER TABLE `kolab_cache_journal` CHANGE `xml` `xml` LONGBLOB NOT NULL; +ALTER TABLE `kolab_cache_note` CHANGE `xml` `xml` LONGBLOB NOT NULL; +ALTER TABLE `kolab_cache_file` CHANGE `xml` `xml` LONGBLOB NOT NULL; +ALTER TABLE `kolab_cache_configuration` CHANGE `xml` `xml` LONGBLOB NOT NULL; +ALTER TABLE `kolab_cache_freebusy` CHANGE `xml` `xml` LONGBLOB NOT NULL; diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php index e8ceed1e..3b4f8253 100644 --- a/plugins/libkolab/lib/kolab_storage_cache.php +++ b/plugins/libkolab/lib/kolab_storage_cache.php @@ -661,7 +661,9 @@ class kolab_storage_cache } } - $sql_data['data'] = serialize($data); + // use base64 encoding (Bug #1912, #2662) + $sql_data['data'] = base64_encode(serialize($data)); + return $sql_data; } @@ -670,8 +672,23 @@ class kolab_storage_cache */ protected function _unserialize($sql_arr) { + // check if data is a base64-encoded string, for backward compat. + if (strpos(substr($sql_arr['data'], 0, 64), ':') === false) { + $sql_arr['data'] = base64_decode($sql_arr['data']); + } + $object = unserialize($sql_arr['data']); + // de-serialization failed + if ($object === false) { + rcube::raise_error(array( + 'code' => 900, 'type' => 'php', + 'message' => "Malformed data for {$this->resource_uri}/{$sql_arr['msguid']} object." + ), true); + + return null; + } + // decode binary properties foreach ($this->binary_items as $key => $regexp) { if (!empty($object[$key]) && preg_match($regexp, $sql_arr['xml'], $m)) { @@ -680,10 +697,10 @@ class kolab_storage_cache } // add meta data - $object['_type'] = $sql_arr['type'] ?: $this->folder->type; - $object['_msguid'] = $sql_arr['msguid']; - $object['_mailbox'] = $this->folder->name; - $object['_size'] = strlen($sql_arr['xml']); + $object['_type'] = $sql_arr['type'] ?: $this->folder->type; + $object['_msguid'] = $sql_arr['msguid']; + $object['_mailbox'] = $this->folder->name; + $object['_size'] = strlen($sql_arr['xml']); $object['_formatobj'] = kolab_format::factory($object['_type'], 3.0, $sql_arr['xml']); return $object;