From bbd636740eecefcb596ce2ad51307263acbb791b Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Thu, 23 May 2013 09:34:51 -0400
Subject: [PATCH] Fix fatal error when parsing UUencoded messages (#1489119)
---
program/lib/Roundcube/rcube.php | 320 +++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 294 insertions(+), 26 deletions(-)
diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php
index 9c1a6d8..eea2fde 100644
--- a/program/lib/Roundcube/rcube.php
+++ b/program/lib/Roundcube/rcube.php
@@ -2,8 +2,6 @@
/*
+-----------------------------------------------------------------------+
- | program/include/rcube.php |
- | |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2008-2012, The Roundcube Dev Team |
| Copyright (C) 2011-2012, Kolab Systems AG |
@@ -36,7 +34,7 @@
/**
* Singleton instace of rcube
*
- * @var rcmail
+ * @var rcube
*/
static protected $instance;
@@ -379,7 +377,7 @@
{
$storage = $this->get_storage();
- $storage->set_charset($this->config->get('default_charset', RCMAIL_CHARSET));
+ $storage->set_charset($this->config->get('default_charset', RCUBE_CHARSET));
if ($default_folders = $this->config->get('default_folders')) {
$storage->set_default_folders($default_folders);
@@ -407,6 +405,7 @@
$sess_domain = $this->config->get('session_domain');
$sess_path = $this->config->get('session_path');
$lifetime = $this->config->get('session_lifetime', 0) * 60;
+ $is_secure = $this->config->get('use_https') || rcube_utils::https_check();
// set session domain
if ($sess_domain) {
@@ -421,7 +420,7 @@
ini_set('session.gc_maxlifetime', $lifetime * 2);
}
- ini_set('session.cookie_secure', rcube_utils::https_check());
+ ini_set('session.cookie_secure', $is_secure);
ini_set('session.name', $sess_name ? $sess_name : 'roundcube_sessid');
ini_set('session.use_cookies', 1);
ini_set('session.use_only_cookies', 1);
@@ -596,8 +595,8 @@
ob_start();
// get english labels (these should be complete)
- @include(INSTALL_PATH . 'program/localization/en_US/labels.inc');
- @include(INSTALL_PATH . 'program/localization/en_US/messages.inc');
+ @include(RCUBE_LOCALIZATION_DIR . 'en_US/labels.inc');
+ @include(RCUBE_LOCALIZATION_DIR . 'en_US/messages.inc');
if (is_array($labels))
$this->texts = $labels;
@@ -605,9 +604,9 @@
$this->texts = array_merge($this->texts, $messages);
// include user language files
- if ($lang != 'en' && $lang != 'en_US' && is_dir(INSTALL_PATH . 'program/localization/' . $lang)) {
- include_once(INSTALL_PATH . 'program/localization/' . $lang . '/labels.inc');
- include_once(INSTALL_PATH . 'program/localization/' . $lang . '/messages.inc');
+ if ($lang != 'en' && $lang != 'en_US' && is_dir(RCUBE_LOCALIZATION_DIR . $lang)) {
+ include_once(RCUBE_LOCALIZATION_DIR . $lang . '/labels.inc');
+ include_once(RCUBE_LOCALIZATION_DIR . $lang . '/messages.inc');
if (is_array($labels))
$this->texts = array_merge($this->texts, $labels);
@@ -645,7 +644,7 @@
}
if (empty($rcube_languages)) {
- @include(INSTALL_PATH . 'program/localization/index.inc');
+ @include(RCUBE_LOCALIZATION_DIR . 'index.inc');
}
// check if we have an alias for that language
@@ -666,7 +665,7 @@
}
}
- if (!isset($rcube_languages[$lang]) || !is_dir(INSTALL_PATH . 'program/localization/' . $lang)) {
+ if (!isset($rcube_languages[$lang]) || !is_dir(RCUBE_LOCALIZATION_DIR . $lang)) {
$lang = 'en_US';
}
@@ -684,11 +683,11 @@
static $sa_languages = array();
if (!sizeof($sa_languages)) {
- @include(INSTALL_PATH . 'program/localization/index.inc');
+ @include(RCUBE_LOCALIZATION_DIR . 'index.inc');
- if ($dh = @opendir(INSTALL_PATH . 'program/localization')) {
+ if ($dh = @opendir(RCUBE_LOCALIZATION_DIR)) {
while (($name = readdir($dh)) !== false) {
- if ($name[0] == '.' || !is_dir(INSTALL_PATH . 'program/localization/' . $name)) {
+ if ($name[0] == '.' || !is_dir(RCUBE_LOCALIZATION_DIR . $name)) {
continue;
}
@@ -894,6 +893,30 @@
/**
+ * Quote a given string.
+ * Shortcut function for rcube_utils::rep_specialchars_output()
+ *
+ * @return string HTML-quoted string
+ */
+ public static function Q($str, $mode = 'strict', $newlines = true)
+ {
+ return rcube_utils::rep_specialchars_output($str, 'html', $mode, $newlines);
+ }
+
+
+ /**
+ * Quote a given string for javascript output.
+ * Shortcut function for rcube_utils::rep_specialchars_output()
+ *
+ * @return string JS-quoted string
+ */
+ public static function JQ($str)
+ {
+ return rcube_utils::rep_specialchars_output($str, 'js');
+ }
+
+
+ /**
* Construct shell command, execute it and return output as string.
* Keywords {keyword} are replaced with arguments
*
@@ -1017,7 +1040,7 @@
$log_dir = self::$instance ? self::$instance->config->get('log_dir') : null;
if (empty($log_dir)) {
- $log_dir = INSTALL_PATH . 'logs';
+ $log_dir = RCUBE_INSTALL_PATH . 'logs';
}
// try to open specific log file for writing
@@ -1051,14 +1074,20 @@
{
// handle PHP exceptions
if (is_object($arg) && is_a($arg, 'Exception')) {
- $err = array(
+ $arg = array(
'type' => 'php',
'code' => $arg->getCode(),
'line' => $arg->getLine(),
'file' => $arg->getFile(),
'message' => $arg->getMessage(),
);
- $arg = $err;
+ }
+ else if (is_string($arg)) {
+ $arg = array('message' => $arg, 'type' => 'php');
+ }
+
+ if (empty($arg['code'])) {
+ $arg['code'] = 500;
}
// installer
@@ -1068,14 +1097,24 @@
return;
}
- if (($log || $terminate) && $arg['type'] && $arg['message']) {
+ $cli = php_sapi_name() == 'cli';
+
+ if (($log || $terminate) && !$cli && $arg['type'] && $arg['message']) {
$arg['fatal'] = $terminate;
self::log_bug($arg);
}
- // display error page and terminate script
- if ($terminate && is_object(self::$instance->output)) {
- self::$instance->output->raise_error($arg['code'], $arg['message']);
+ // terminate script
+ if ($terminate) {
+ // display error page
+ if (is_object(self::$instance->output)) {
+ self::$instance->output->raise_error($arg['code'], $arg['message']);
+ }
+ else if ($cli) {
+ fwrite(STDERR, 'ERROR: ' . $arg['message']);
+ }
+
+ exit(1);
}
}
@@ -1114,7 +1153,7 @@
if (!self::write_log('errors', $log_entry)) {
// send error to PHPs error handler if write_log didn't succeed
- trigger_error($arg_arr['message']);
+ trigger_error($arg_arr['message'], E_USER_WARNING);
}
}
@@ -1203,16 +1242,245 @@
if (is_object($this->user)) {
return $this->user->get_username();
}
-
- return null;
+ else if (isset($_SESSION['username'])) {
+ return $_SESSION['username'];
+ }
}
+
+
+ /**
+ * Getter for logged user email (derived from user name not identity).
+ *
+ * @return string User email address
+ */
+ public function get_user_email()
+ {
+ if (is_object($this->user)) {
+ return $this->user->get_username('mail');
+ }
+ }
+
+
+ /**
+ * Getter for logged user password.
+ *
+ * @return string User password
+ */
+ public function get_user_password()
+ {
+ if ($this->password) {
+ return $this->password;
+ }
+ else if ($_SESSION['password']) {
+ return $this->decrypt($_SESSION['password']);
+ }
+ }
+
+
+ /**
+ * Getter for logged user language code.
+ *
+ * @return string User language code
+ */
+ public function get_user_language()
+ {
+ if (is_object($this->user)) {
+ return $this->user->language;
+ }
+ else if (isset($_SESSION['language'])) {
+ return $_SESSION['language'];
+ }
+ }
+
+ /**
+ * Unique Message-ID generator.
+ *
+ * @return string Message-ID
+ */
+ public function gen_message_id()
+ {
+ $local_part = md5(uniqid('rcube'.mt_rand(), true));
+ $domain_part = $this->user->get_username('domain');
+
+ // Try to find FQDN, some spamfilters doesn't like 'localhost' (#1486924)
+ if (!preg_match('/\.[a-z]+$/i', $domain_part)) {
+ foreach (array($_SERVER['HTTP_HOST'], $_SERVER['SERVER_NAME']) as $host) {
+ $host = preg_replace('/:[0-9]+$/', '', $host);
+ if ($host && preg_match('/\.[a-z]+$/i', $host)) {
+ $domain_part = $host;
+ }
+ }
+ }
+
+ return sprintf('<%s@%s>', $local_part, $domain_part);
+ }
+
+ /**
+ * Send the given message using the configured method.
+ *
+ * @param object $message Reference to Mail_MIME object
+ * @param string $from Sender address string
+ * @param array $mailto Array of recipient address strings
+ * @param array $error SMTP error array (reference)
+ * @param string $body_file Location of file with saved message body (reference),
+ * used when delay_file_io is enabled
+ * @param array $options SMTP options (e.g. DSN request)
+ *
+ * @return boolean Send status.
+ */
+ public function deliver_message(&$message, $from, $mailto, &$error, &$body_file = null, $options = null)
+ {
+ $plugin = $this->plugins->exec_hook('message_before_send', array(
+ 'message' => $message,
+ 'from' => $from,
+ 'mailto' => $mailto,
+ 'options' => $options,
+ ));
+
+ $from = $plugin['from'];
+ $mailto = $plugin['mailto'];
+ $options = $plugin['options'];
+ $message = $plugin['message'];
+ $headers = $message->headers();
+
+ // send thru SMTP server using custom SMTP library
+ if ($this->config->get('smtp_server')) {
+ // generate list of recipients
+ $a_recipients = array($mailto);
+
+ if (strlen($headers['Cc']))
+ $a_recipients[] = $headers['Cc'];
+ if (strlen($headers['Bcc']))
+ $a_recipients[] = $headers['Bcc'];
+
+ // clean Bcc from header for recipients
+ $send_headers = $headers;
+ unset($send_headers['Bcc']);
+ // here too, it because txtHeaders() below use $message->_headers not only $send_headers
+ unset($message->_headers['Bcc']);
+
+ $smtp_headers = $message->txtHeaders($send_headers, true);
+
+ if ($message->getParam('delay_file_io')) {
+ // use common temp dir
+ $temp_dir = $this->config->get('temp_dir');
+ $body_file = tempnam($temp_dir, 'rcmMsg');
+ if (PEAR::isError($mime_result = $message->saveMessageBody($body_file))) {
+ self::raise_error(array('code' => 650, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Could not create message: ".$mime_result->getMessage()),
+ TRUE, FALSE);
+ return false;
+ }
+ $msg_body = fopen($body_file, 'r');
+ }
+ else {
+ $msg_body = $message->get();
+ }
+
+ // send message
+ if (!is_object($this->smtp)) {
+ $this->smtp_init(true);
+ }
+
+ $sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $options);
+ $response = $this->smtp->get_response();
+ $error = $this->smtp->get_error();
+
+ // log error
+ if (!$sent) {
+ self::raise_error(array('code' => 800, 'type' => 'smtp',
+ 'line' => __LINE__, 'file' => __FILE__,
+ 'message' => "SMTP error: ".join("\n", $response)), TRUE, FALSE);
+ }
+ }
+ // send mail using PHP's mail() function
+ else {
+ // unset some headers because they will be added by the mail() function
+ $headers_enc = $message->headers($headers);
+ $headers_php = $message->_headers;
+ unset($headers_php['To'], $headers_php['Subject']);
+
+ // reset stored headers and overwrite
+ $message->_headers = array();
+ $header_str = $message->txtHeaders($headers_php);
+
+ // #1485779
+ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+ if (preg_match_all('/<([^@]+@[^>]+)>/', $headers_enc['To'], $m)) {
+ $headers_enc['To'] = implode(', ', $m[1]);
+ }
+ }
+
+ $msg_body = $message->get();
+
+ if (PEAR::isError($msg_body)) {
+ self::raise_error(array('code' => 650, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Could not create message: ".$msg_body->getMessage()),
+ TRUE, FALSE);
+ }
+ else {
+ $delim = $this->config->header_delimiter();
+ $to = $headers_enc['To'];
+ $subject = $headers_enc['Subject'];
+ $header_str = rtrim($header_str);
+
+ if ($delim != "\r\n") {
+ $header_str = str_replace("\r\n", $delim, $header_str);
+ $msg_body = str_replace("\r\n", $delim, $msg_body);
+ $to = str_replace("\r\n", $delim, $to);
+ $subject = str_replace("\r\n", $delim, $subject);
+ }
+
+ if (ini_get('safe_mode'))
+ $sent = mail($to, $subject, $msg_body, $header_str);
+ else
+ $sent = mail($to, $subject, $msg_body, $header_str, "-f$from");
+ }
+ }
+
+ if ($sent) {
+ $this->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body));
+
+ // remove MDN headers after sending
+ unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']);
+
+ // get all recipients
+ if ($headers['Cc'])
+ $mailto .= $headers['Cc'];
+ if ($headers['Bcc'])
+ $mailto .= $headers['Bcc'];
+ if (preg_match_all('/<([^@]+@[^>]+)>/', $mailto, $m))
+ $mailto = implode(', ', array_unique($m[1]));
+
+ if ($this->config->get('smtp_log')) {
+ self::write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s",
+ $this->user->get_username(),
+ $_SERVER['REMOTE_ADDR'],
+ $mailto,
+ !empty($response) ? join('; ', $response) : ''));
+ }
+ }
+
+ if (is_resource($msg_body)) {
+ fclose($msg_body);
+ }
+
+ $message->_headers = array();
+ $message->headers($headers);
+
+ return $sent;
+ }
+
}
/**
* Lightweight plugin API class serving as a dummy if plugins are not enabled
*
- * @package Core
+ * @package Framework
+ * @subpackage Core
*/
class rcube_dummy_plugin_api
{
--
Gitblit v1.9.1