From 197203727417a03d87053a47e5aa5175a76e3e0b Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Thu, 17 Oct 2013 04:24:53 -0400
Subject: [PATCH] Fix vulnerability in handling _session argument of utils/save-prefs (#1489382)

---
 program/include/rcube_imap.php |   36 ++++++++++++++++++++++++------------
 1 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 1c5dd2e..f06a8ee 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -687,8 +687,8 @@
     {
         $mode = strtoupper($mode);
 
-        // count search set
-        if ($this->search_string && $mailbox == $this->mailbox && ($mode == 'ALL' || $mode == 'THREADS') && !$force) {
+        // count search set, assume search set is always up-to-date (don't check $force flag)
+        if ($this->search_string && $mailbox == $this->mailbox && ($mode == 'ALL' || $mode == 'THREADS')) {
             if ($this->search_threads)
                 return $mode == 'ALL' ? count((array)$this->search_set['depth']) : count((array)$this->search_set['tree']);
             else
@@ -1636,6 +1636,7 @@
      * @param  string  $sort_field Header field to sort by
      * @return array   search results as list of message IDs
      * @access public
+     * @todo: Search criteria should be provided in non-IMAP format, eg. array
      */
     function search($mailbox='', $str=NULL, $charset=NULL, $sort_field=NULL)
     {
@@ -1721,7 +1722,7 @@
             // Error, try with US-ASCII (some servers may support only US-ASCII)
             if ($a_messages === false && $charset && $charset != 'US-ASCII')
                 $a_messages = $this->conn->search($mailbox,
-                    'CHARSET US-ASCII ' . $this->convert_criteria($criteria, $charset));
+                    $this->convert_criteria($criteria, $charset));
 
             // I didn't found that SEARCH should return sorted IDs
             if (is_array($a_messages) && !$this->sort_field)
@@ -1775,9 +1776,9 @@
                 $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n
                 $string = substr($str, $string_offset - 1, $m[0]);
                 $string = rcube_charset_convert($string, $charset, $dest_charset);
-                if (!$string)
+                if ($string === false)
                     continue;
-                $res .= sprintf("%s{%d}\r\n%s", substr($str, $last, $m[1] - $last - 1), strlen($string), $string);
+                $res .= substr($str, $last, $m[1] - $last - 1) . rcube_imap_generic::escape($string);
                 $last = $m[0] + $string_offset - 1;
             }
             if ($last < strlen($str))
@@ -3039,9 +3040,10 @@
                     NULL, array('SUBSCRIBED'));
 
                 // unsubscribe non-existent folders, remove from the list
-                if (is_array($a_folders) && $name == '*') {
+                // we can do this only when LIST response is available
+                if (is_array($a_folders) && $name == '*' && !empty($this->conn->data['LIST'])) {
                     foreach ($a_folders as $idx => $folder) {
-                        if ($this->conn->data['LIST'] && ($opts = $this->conn->data['LIST'][$folder])
+                        if (($opts = $this->conn->data['LIST'][$folder])
                             && in_array('\\NonExistent', $opts)
                         ) {
                             $this->conn->unsubscribe($folder);
@@ -3054,11 +3056,12 @@
             else {
                 $a_folders = $this->conn->listSubscribed($root, $name);
 
-                // unsubscribe non-existent folders, remove from the list
-                if (is_array($a_folders) && $name == '*') {
+                // unsubscribe non-existent folders, remove them from the list,
+                // we can do this only when LIST response is available
+                if (is_array($a_folders) && $name == '*' && !empty($this->conn->data['LIST'])) {
                     foreach ($a_folders as $idx => $folder) {
-                        if ($this->conn->data['LIST'] && ($opts = $this->conn->data['LIST'][$folder])
-                            && in_array('\\Noselect', $opts)
+                        if (!isset($this->conn->data['LIST'][$folder])
+                            || in_array('\\Noselect', $this->conn->data['LIST'][$folder])
                         ) {
                             // Some servers returns \Noselect for existing folders
                             if (!$this->mailbox_exists($folder)) {
@@ -3650,7 +3653,7 @@
         $options['rights']     = $acl && !$options['is_root'] ? (array)$this->my_rights($mailbox) : array();
         $options['special']    = in_array($mailbox, $this->default_folders);
 
-        // Set 'noselect' and 'norename' flags
+        // Set 'noselect' flag
         if (is_array($options['attributes'])) {
             foreach ($options['attributes'] as $attrib) {
                 $attrib = strtolower($attrib);
@@ -3663,6 +3666,15 @@
             $options['noselect'] = true;
         }
 
+        // Get folder rights (MYRIGHTS)
+        if ($acl && !$options['noselect']) {
+            // skip shared roots
+            if (!$options['is_root'] || $options['namespace'] == 'personal') {
+                $options['rights'] =  (array)$this->my_rights($mailbox);
+            }
+        }
+
+        // Set 'norename' flag
         if (!empty($options['rights'])) {
             $options['norename'] = !in_array('x', $options['rights']) && !in_array('d', $options['rights']);
 

--
Gitblit v1.9.1