| +-----------------------------------------------------------------------+ */ // show loading page if (!empty($_GET['_preload'])) { $_get = $_GET + array('_mimewarning' => 1, '_embed' => 1); unset($_get['_preload']); $url = $RCMAIL->url($_get); $message = $RCMAIL->gettext('loadingdata'); header('Content-Type: text/html; charset=' . RCUBE_CHARSET); print "\n
\n" . '' . "\n" . '' . "\n" . "\n\n$message\n\n"; exit; } ob_end_clean(); // similar code as in program/steps/mail/show.inc if (!empty($_GET['_uid'])) { $uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET); $RCMAIL->config->set('prefer_html', true); $MESSAGE = new rcube_message($uid, null, intval($_GET['_safe'])); } // check connection status check_storage_status(); $part_id = rcube_utils::get_input_value('_part', rcube_utils::INPUT_GPC); // show part page if (!empty($_GET['_frame'])) { if ($part_id && ($part = $MESSAGE->mime_parts[$part_id])) { $filename = rcmail_attachment_name($part); $OUTPUT->set_pagetitle($filename); } // register UI objects $OUTPUT->add_handlers(array( 'messagepartframe' => 'rcmail_message_part_frame', 'messagepartcontrols' => 'rcmail_message_part_controls', )); $mimetype = $part ? rcmail_fix_mimetype($part->mimetype) : ''; // message/rfc822 preview (Note: handle also multipart/ parts, they can // come from Enigma, which replaces message/rfc822 with real mimetype) if ($part_id && ($mimetype == 'message/rfc822' || strpos($mimetype, 'multipart/') === 0)) { $uid = preg_replace('/\.[0-9.]+/', '', $uid); $uid .= '.' . $part_id; $OUTPUT->set_env('is_message', true); } $OUTPUT->set_env('mailbox', $RCMAIL->storage->get_folder()); $OUTPUT->set_env('uid', $uid); $OUTPUT->set_env('part', $part_id); $OUTPUT->set_env('filename', $filename); $OUTPUT->set_env('mimetype', $mimetype); $OUTPUT->send('messagepart'); exit; } // render thumbnail of an image attachment else if ($_GET['_thumb']) { $pid = rcube_utils::get_input_value('_part', rcube_utils::INPUT_GET); if ($part = $MESSAGE->mime_parts[$pid]) { $thumbnail_size = $RCMAIL->config->get('image_thumbnail_size', 240); $temp_dir = $RCMAIL->config->get('temp_dir'); $mimetype = $part->mimetype; $file_ident = $MESSAGE->headers->messageID . ':' . $part->mime_id . ':' . $part->size . ':' . $part->mimetype; $cache_basename = $temp_dir . '/' . md5($file_ident . ':' . $RCMAIL->user->ID . ':' . $thumbnail_size); $cache_file = $cache_basename . '.thumb'; // render thumbnail image if not done yet if (!is_file($cache_file)) { if ($fp = fopen(($orig_name = $cache_basename . '.tmp'), 'w')) { $MESSAGE->get_part_body($part->mime_id, false, 0, $fp); fclose($fp); $image = new rcube_image($orig_name); if ($imgtype = $image->resize($thumbnail_size, $cache_file, true)) { $mimetype = 'image/' . $imgtype; unlink($orig_name); } else if (stripos($mimetype, 'image/svg') === 0) { $content = rcmail_svg_filter(file_get_contents($orig_name)); file_put_contents($cache_file, $content); unlink($orig_name); } else { rename($orig_name, $cache_file); } } } if (is_file($cache_file)) { header('Content-Type: ' . $mimetype); readfile($cache_file); } } exit; } else if (strlen($part_id)) { if ($part = $MESSAGE->mime_parts[$part_id]) { $mimetype = rcmail_fix_mimetype($part->mimetype); // allow post-processing of the message body $plugin = $RCMAIL->plugins->exec_hook('message_part_get', array( 'uid' => $MESSAGE->uid, 'id' => $part->mime_id, 'mimetype' => $mimetype, 'part' => $part, 'download' => !empty($_GET['_download']) )); if ($plugin['abort']) { exit; } // require CSRF protected url for downloads if ($plugin['download']) $RCMAIL->request_security_check(rcube_utils::INPUT_GET); // overwrite modified vars from plugin $mimetype = $plugin['mimetype']; $extensions = rcube_mime::get_mime_extensions($mimetype); if ($plugin['body']) { $body = $plugin['body']; } // compare file mimetype with the stated content-type headers and file extension to avoid malicious operations if (!empty($_REQUEST['_embed']) && empty($_REQUEST['_nocheck'])) { $file_extension = strtolower(pathinfo($part->filename, PATHINFO_EXTENSION)); // 1. compare filename suffix with expected suffix derived from mimetype $valid = $file_extension && in_array($file_extension, (array)$extensions) || empty($extensions) || !empty($_REQUEST['_mimeclass']); // 2. detect the real mimetype of the attachment part and compare it with the stated mimetype and filename extension if ($valid || !$file_extension || $mimetype == 'application/octet-stream' || stripos($mimetype, 'text/') === 0) { $tmp_body = $body ?: $MESSAGE->get_part_body($part->mime_id, false, 2048); // detect message part mimetype $real_mimetype = rcube_mime::file_content_type($tmp_body, $part->filename, $mimetype, true, true); list($real_ctype_primary, $real_ctype_secondary) = explode('/', $real_mimetype); // accept text/plain with any extension if ($real_mimetype == 'text/plain' && $real_mimetype == $mimetype) { $valid_extension = true; } // ignore differences in text/* mimetypes. Filetype detection isn't very reliable here else if ($real_ctype_primary == 'text' && strpos($mimetype, $real_ctype_primary) === 0) { $real_mimetype = $mimetype; $valid_extension = true; } // ignore filename extension if mimeclass matches (#1489029) else if (!empty($_REQUEST['_mimeclass']) && $real_ctype_primary == $_REQUEST['_mimeclass']) { $valid_extension = true; } else { // get valid file extensions $extensions = rcube_mime::get_mime_extensions($real_mimetype); $valid_extension = !$file_extension || empty($extensions) || in_array($file_extension, (array)$extensions); } // fix mimetype for images wrongly declared as octet-stream if ($mimetype == 'application/octet-stream' && strpos($real_mimetype, 'image/') === 0 && $valid_extension) { $mimetype = $real_mimetype; } // "fix" real mimetype the same way the original is before comparison $real_mimetype = rcmail_fix_mimetype($real_mimetype); $valid = $real_mimetype == $mimetype && $valid_extension; } else { $real_mimetype = $mimetype; } // show warning if validity checks failed if (!$valid) { // send blocked.gif for expected images if (empty($_REQUEST['_mimewarning']) && strpos($mimetype, 'image/') === 0) { // Do not cache. Failure might be the result of a misconfiguration, thus real content should be returned once fixed. $content = $RCMAIL->get_resource_content('blocked.gif'); $OUTPUT->nocacheing_headers(); header("Content-Type: image/gif"); header("Content-Transfer-Encoding: binary"); header("Content-Length: " . strlen($content)); echo $content; } else { // html warning with a button to load the file anyway $OUTPUT = new rcmail_html_page(); $OUTPUT->write(html::tag('html', null, html::tag('body', 'embed', html::div(array('class' => 'rcmail-inline-message rcmail-inline-warning'), $RCMAIL->gettext(array( 'name' => 'attachmentvalidationerror', 'vars' => array( 'expected' => $mimetype . ($file_extension ? " (.$file_extension)" : ''), 'detected' => $real_mimetype . ($extensions[0] ? " (.$extensions[0])" : ''), ) )) . html::p(array('class' => 'rcmail-inline-buttons'), html::tag('button', array( 'onclick' => "location.href='" . $RCMAIL->url(array_merge($_GET, array('_nocheck' => 1))) . "'" ), $RCMAIL->gettext('showanyway')) ) )))); } exit; } } // TIFF/WEBP to JPEG conversion, if needed foreach (array('tiff', 'webp') as $type) { $img_support = !empty($_SESSION['browser_caps']) && !empty($_SESSION['browser_caps'][$type]); if (!empty($_REQUEST['_embed']) && !$img_support && rcmail_part_image_type($part) == 'image/' . $type && rcube_image::is_convertable('image/' . $type) ) { $convert2jpeg = true; $mimetype = 'image/jpeg'; break; } } $browser = $RCMAIL->output->browser; list($ctype_primary, $ctype_secondary) = explode('/', $mimetype); if (!$plugin['download'] && $ctype_primary == 'text') { header("Content-Type: text/$ctype_secondary; charset=" . ($part->charset ?: RCUBE_CHARSET)); } else { header("Content-Type: $mimetype"); header("Content-Transfer-Encoding: binary"); } // deliver part content if ($ctype_primary == 'text' && $ctype_secondary == 'html' && empty($plugin['download'])) { // Check if we have enough memory to handle the message in it // #1487424: we need up to 10x more memory than the body if (!rcube_utils::mem_check($part->size * 10)) { $out = '' . $RCMAIL->gettext('messagetoobig'). ' ' . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part='.$part->mime_id .'&_mbox='. urlencode($MESSAGE->folder), $RCMAIL->gettext('download')) . '