瀏覽代碼

Improve attachment file handling: use one new function to create a temp
file for storing the attachment. This replaces the same code in five
places. It also improves on the code, it's now much more safe against
overwriting existing attachments by chance.

Thijs Kinkhorst 18 年之前
父節點
當前提交
13c297bc93
共有 9 個文件被更改,包括 75 次插入54 次删除
  1. 1 0
      ChangeLog
  2. 46 0
      functions/compose.php
  3. 5 10
      functions/mailbox_display.php
  4. 3 14
      plugins/spamcop/functions.php
  5. 2 0
      plugins/spamcop/spamcop.php
  6. 15 30
      src/compose.php
  7. 1 0
      src/read_body.php
  8. 1 0
      src/right_main.php
  9. 1 0
      src/search.php

+ 1 - 0
ChangeLog

@@ -171,6 +171,7 @@ Version 1.5.2 - CVS
   - Drop obsolete ORDB RBL from filters plugin (#1629398).
   - Drop obsolete ORDB RBL from filters plugin (#1629398).
   - Add warning about magic_quotes_* in configtest.
   - Add warning about magic_quotes_* in configtest.
   - Unify accepted versions for imap_server_type and set_defaults (#1629722).
   - Unify accepted versions for imap_server_type and set_defaults (#1629722).
+  - Improve attachment temp file creation.
 
 
 Version 1.5.1 (branched on 2006-02-12)
 Version 1.5.1 (branched on 2006-02-12)
 --------------------------------------
 --------------------------------------

+ 46 - 0
functions/compose.php

@@ -13,3 +13,49 @@
  */
  */
 
 
 
 
+/**
+ * Get a new file to write an attachment to.
+ * This function makes sure it doesn't overwrite other attachments,
+ * preventing collisions and race conditions.
+ *
+ * @return filename
+ * @since 1.5.2
+ */
+function sq_get_attach_tempfile()
+{
+    global $username, $attachment_dir;
+
+    $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
+
+    // using PHP >= 4.3.2 we can be truly atomic here
+    $filemods = check_php_version ( 4,3,2 ) ? 'x' : 'w';
+
+    // give up after 1000 tries
+    $TMP_MAX = 1000;
+    for ($try=0; $try<$TMP_MAX; ++$try) {
+
+        $localfilename = GenerateRandomString(32, '', 7);
+        $full_localfilename = "$hashed_attachment_dir/$localfilename";
+
+        // filename collision. try again
+        if ( file_exists($full_localfilename) ) {
+            continue;
+        }
+
+        // try to open for (binary) writing
+        $fp = @fopen( $full_localfilename, $filemods);
+
+        if ( $fp !== FALSE ) {
+            // success! make sure it's not readable, close and return filename
+            chmod($full_localfilename, 0600);
+            fclose($fp);
+            return $full_localfilename;
+        }
+    }
+
+    // we tried 1000 times but didn't succeed.
+    error_box( _("Could not open temporary file to store attachment. Contact your system administrator to resolve this issue.") );
+    return FALSE;
+}
+
+

+ 5 - 10
functions/mailbox_display.php

@@ -1477,9 +1477,6 @@ function handleMessageListForm($imapConnection,&$aMailbox,$sButton='',$aUid = ar
  * @author Marc Groot Koerkamp
  * @author Marc Groot Koerkamp
  */
  */
 function attachSelectedMessages($imapConnection,$aMsgHeaders) {
 function attachSelectedMessages($imapConnection,$aMsgHeaders) {
-    global $username, $attachment_dir,
-           $data_dir;
-
 
 
     sqgetGlobalVar('composesession', $composesession, SQ_SESSION);
     sqgetGlobalVar('composesession', $composesession, SQ_SESSION);
     sqgetGlobalVar('compose_messages', $compose_messages, SQ_SESSION);
     sqgetGlobalVar('compose_messages', $compose_messages, SQ_SESSION);
@@ -1496,8 +1493,6 @@ function attachSelectedMessages($imapConnection,$aMsgHeaders) {
         sqsession_register($composesession,'composesession');
         sqsession_register($composesession,'composesession');
     }
     }
 
 
-    $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
-
     $composeMessage = new Message();
     $composeMessage = new Message();
     $rfc822_header = new Rfc822Header();
     $rfc822_header = new Rfc822Header();
     $composeMessage->rfc822_header = $rfc822_header;
     $composeMessage->rfc822_header = $rfc822_header;
@@ -1517,14 +1512,13 @@ function attachSelectedMessages($imapConnection,$aMsgHeaders) {
             $body = implode('', $body_a);
             $body = implode('', $body_a);
             $body .= "\r\n";
             $body .= "\r\n";
 
 
-            $localfilename = GenerateRandomString(32, 'FILE', 7);
-            $full_localfilename = "$hashed_attachment_dir/$localfilename";
-
-            $fp = fopen( $full_localfilename, 'wb');
+            $filename = sq_get_attach_tempfile();
+            $fp = fopen($filename, 'wb');
             fwrite ($fp, $body);
             fwrite ($fp, $body);
             fclose($fp);
             fclose($fp);
+
             $composeMessage->initAttachment('message/rfc822',$subject.'.msg',
             $composeMessage->initAttachment('message/rfc822',$subject.'.msg',
-                 $full_localfilename);
+                 $filename);
         }
         }
     }
     }
 
 
@@ -1532,3 +1526,4 @@ function attachSelectedMessages($imapConnection,$aMsgHeaders) {
     sqsession_register($compose_messages,'compose_messages');
     sqsession_register($compose_messages,'compose_messages');
     return $composesession;
     return $composesession;
 }
 }
+

+ 3 - 14
plugins/spamcop/functions.php

@@ -180,9 +180,7 @@ function spamcop_enable_disable($option,$disable_action,$enable_action) {
  */
  */
 function spamcop_getMessage_RFC822_Attachment($message, $composeMessage, $passed_id,
 function spamcop_getMessage_RFC822_Attachment($message, $composeMessage, $passed_id,
                                       $passed_ent_id='', $imapConnection) {
                                       $passed_ent_id='', $imapConnection) {
-    global $attachment_dir, $username;
 
 
-    $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
     if (!$passed_ent_id) {
     if (!$passed_ent_id) {
         $body_a = sqimap_run_command($imapConnection,
         $body_a = sqimap_run_command($imapConnection,
                                     'FETCH '.$passed_id.' RFC822',
                                     'FETCH '.$passed_id.' RFC822',
@@ -198,21 +196,12 @@ function spamcop_getMessage_RFC822_Attachment($message, $composeMessage, $passed
         array_shift($body_a);
         array_shift($body_a);
         $body = implode('', $body_a) . "\r\n";
         $body = implode('', $body_a) . "\r\n";
 
 
-        $localfilename = GenerateRandomString(32, 'FILE', 7);
-        $full_localfilename = "$hashed_attachment_dir/$localfilename";
-        $fp = fopen( $full_localfilename, 'w');
+        $filename = sq_get_attach_tempfile();
+        $fp = fopen($filename, 'wb');
         fwrite ($fp, $body);
         fwrite ($fp, $body);
         fclose($fp);
         fclose($fp);
-
-        /* dirty relative dir fix */
-        if (substr($attachment_dir,0,3) == '../') {
-           $attachment_dir = substr($attachment_dir,3);
-           $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
-        }
-        $full_localfilename = "$hashed_attachment_dir/$localfilename";
-
         $composeMessage->initAttachment('message/rfc822','email.txt',
         $composeMessage->initAttachment('message/rfc822','email.txt',
-                         $full_localfilename);
+                         $filename);
     }
     }
     return $composeMessage;
     return $composeMessage;
 }
 }

+ 2 - 0
plugins/spamcop/spamcop.php

@@ -23,6 +23,8 @@ include_once(SM_PATH . 'functions/imap_messages.php');
 /* plugin functions */
 /* plugin functions */
 include_once(SM_PATH . 'plugins/spamcop/functions.php');
 include_once(SM_PATH . 'plugins/spamcop/functions.php');
 
 
+include_once(SM_PATH . 'functions/compose.php');
+
 /* GLOBALS */
 /* GLOBALS */
 
 
 sqgetGlobalVar('mailbox', $mailbox, SQ_GET);
 sqgetGlobalVar('mailbox', $mailbox, SQ_GET);

+ 15 - 30
src/compose.php

@@ -26,6 +26,7 @@ require_once(SM_PATH . 'functions/imap_general.php');
 require_once(SM_PATH . 'functions/imap_messages.php');
 require_once(SM_PATH . 'functions/imap_messages.php');
 require_once(SM_PATH . 'functions/date.php');
 require_once(SM_PATH . 'functions/date.php');
 require_once(SM_PATH . 'functions/mime.php');
 require_once(SM_PATH . 'functions/mime.php');
+require_once(SM_PATH . 'functions/compose.php');
 require_once(SM_PATH . 'class/deliver/Deliver.class.php');
 require_once(SM_PATH . 'class/deliver/Deliver.class.php');
 require_once(SM_PATH . 'functions/addressbook.php');
 require_once(SM_PATH . 'functions/addressbook.php');
 require_once(SM_PATH . 'functions/forms.php');
 require_once(SM_PATH . 'functions/forms.php');
@@ -974,8 +975,8 @@ function newMail ($mailbox='', $passed_id='', $passed_ent_id='', $action='', $se
  * @return object
  * @return object
  */
  */
 function getAttachments($message, &$composeMessage, $passed_id, $entities, $imapConnection) {
 function getAttachments($message, &$composeMessage, $passed_id, $entities, $imapConnection) {
-    global $attachment_dir, $username, $data_dir, $squirrelmail_language, $languages;
-    $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
+    global $squirrelmail_language, $languages;
+
     if (!count($message->entities) ||
     if (!count($message->entities) ||
             ($message->type0 == 'message' && $message->type1 == 'rfc822')) {
             ($message->type0 == 'message' && $message->type1 == 'rfc822')) {
         if ( !in_array($message->entity_id, $entities) && $message->entity_id) {
         if ( !in_array($message->entity_id, $entities) && $message->entity_id) {
@@ -1003,19 +1004,14 @@ function getAttachments($message, &$composeMessage, $passed_id, $entities, $imap
                     function_exists($languages[$squirrelmail_language]['XTRA_CODE'] . '_encode')) {
                     function_exists($languages[$squirrelmail_language]['XTRA_CODE'] . '_encode')) {
                 $filename =  call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_encode', $filename);
                 $filename =  call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_encode', $filename);
             }
             }
-            $localfilename = GenerateRandomString(32, '', 7);
-            $full_localfilename = "$hashed_attachment_dir/$localfilename";
-            while (file_exists($full_localfilename)) {
-                $localfilename = GenerateRandomString(32, '', 7);
-                $full_localfilename = "$hashed_attachment_dir/$localfilename";
-            }
-            $message->att_local_name = $full_localfilename;
+            $localfilename = sq_get_attach_tempfile();
+            $message->att_local_name = $localfilename;
 
 
             $composeMessage->initAttachment($message->type0.'/'.$message->type1,$filename,
             $composeMessage->initAttachment($message->type0.'/'.$message->type1,$filename,
-                    $full_localfilename);
+                    $localfilename);
 
 
             /* Write Attachment to file */
             /* Write Attachment to file */
-            $fp = fopen ("$hashed_attachment_dir/$localfilename", 'wb');
+            $fp = fopen ($localfilename, 'wb');
             mime_print_body_lines ($imapConnection, $passed_id, $message->entity_id, $message->header->encoding, $fp);
             mime_print_body_lines ($imapConnection, $passed_id, $message->entity_id, $message->header->encoding, $fp);
             fclose ($fp);
             fclose ($fp);
         }
         }
@@ -1029,8 +1025,6 @@ function getAttachments($message, &$composeMessage, $passed_id, $entities, $imap
 
 
 function getMessage_RFC822_Attachment($message, $composeMessage, $passed_id,
 function getMessage_RFC822_Attachment($message, $composeMessage, $passed_id,
         $passed_ent_id='', $imapConnection) {
         $passed_ent_id='', $imapConnection) {
-    global $attachment_dir, $username, $data_dir;
-    $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
     if (!$passed_ent_id) {
     if (!$passed_ent_id) {
         $body_a = sqimap_run_command($imapConnection,
         $body_a = sqimap_run_command($imapConnection,
                 'FETCH '.$passed_id.' RFC822',
                 'FETCH '.$passed_id.' RFC822',
@@ -1048,14 +1042,12 @@ function getMessage_RFC822_Attachment($message, $composeMessage, $passed_id,
         array_pop($body_a);
         array_pop($body_a);
         $body = implode('', $body_a) . "\r\n";
         $body = implode('', $body_a) . "\r\n";
 
 
-        $localfilename = GenerateRandomString(32, 'FILE', 7);
-        $full_localfilename = "$hashed_attachment_dir/$localfilename";
-
-        $fp = fopen($full_localfilename, 'w');
+        $localfilename = sq_get_attach_tempfile();
+        $fp = fopen($localfilename, 'wb');
         fwrite ($fp, $body);
         fwrite ($fp, $body);
         fclose($fp);
         fclose($fp);
         $composeMessage->initAttachment('message/rfc822',$subject.'.msg',
         $composeMessage->initAttachment('message/rfc822',$subject.'.msg',
-                $full_localfilename);
+                $localfilename);
     }
     }
     return $composeMessage;
     return $composeMessage;
 }
 }
@@ -1381,33 +1373,26 @@ function checkInput ($show) {
 
 
 /* True if FAILURE */
 /* True if FAILURE */
 function saveAttachedFiles($session) {
 function saveAttachedFiles($session) {
-    global $_FILES, $attachment_dir, $username,
-        $data_dir, $compose_messages;
+    global $compose_messages;
 
 
     /* get out of here if no file was attached at all */
     /* get out of here if no file was attached at all */
     if (! is_uploaded_file($_FILES['attachfile']['tmp_name']) ) {
     if (! is_uploaded_file($_FILES['attachfile']['tmp_name']) ) {
         return true;
         return true;
     }
     }
 
 
-    $hashed_attachment_dir = getHashedDir($username, $attachment_dir);
-    $localfilename = GenerateRandomString(32, '', 7);
-    $full_localfilename = "$hashed_attachment_dir/$localfilename";
-    while (file_exists($full_localfilename)) {
-        $localfilename = GenerateRandomString(32, '', 7);
-        $full_localfilename = "$hashed_attachment_dir/$localfilename";
-    }
+    $localfilename = sq_get_attach_tempfile();
 
 
     // m_u_f works better with restricted PHP installs (safe_mode, open_basedir),
     // m_u_f works better with restricted PHP installs (safe_mode, open_basedir),
     // if that doesn't work, try a simple rename.
     // if that doesn't work, try a simple rename.
-    if (!@move_uploaded_file($_FILES['attachfile']['tmp_name'],$full_localfilename)) {
-        if (!@rename($_FILES['attachfile']['tmp_name'], $full_localfilename)) {
+    if (!@move_uploaded_file($_FILES['attachfile']['tmp_name'],$localfilename)) {
+        if (!@rename($_FILES['attachfile']['tmp_name'], $localfilename)) {
             return true;
             return true;
         }
         }
     }
     }
     $message = $compose_messages[$session];
     $message = $compose_messages[$session];
     $type = strtolower($_FILES['attachfile']['type']);
     $type = strtolower($_FILES['attachfile']['type']);
     $name = $_FILES['attachfile']['name'];
     $name = $_FILES['attachfile']['name'];
-    $message->initAttachment($type, $name, $full_localfilename);
+    $message->initAttachment($type, $name, $localfilename);
     $compose_messages[$session] = $message;
     $compose_messages[$session] = $message;
     sqsession_register($compose_messages , 'compose_messages');
     sqsession_register($compose_messages , 'compose_messages');
 }
 }

+ 1 - 0
src/read_body.php

@@ -27,6 +27,7 @@ require_once(SM_PATH . 'functions/identity.php');
 require_once(SM_PATH . 'functions/mailbox_display.php');
 require_once(SM_PATH . 'functions/mailbox_display.php');
 require_once(SM_PATH . 'functions/forms.php');
 require_once(SM_PATH . 'functions/forms.php');
 require_once(SM_PATH . 'functions/attachment_common.php');
 require_once(SM_PATH . 'functions/attachment_common.php');
+require_once(SM_PATH . 'functions/compose.php');
 
 
 /**
 /**
  * Given an IMAP message id number, this will look it up in the cached
  * Given an IMAP message id number, this will look it up in the cached

+ 1 - 0
src/right_main.php

@@ -27,6 +27,7 @@ require_once(SM_PATH . 'functions/imap_messages.php');
 require_once(SM_PATH . 'functions/date.php');
 require_once(SM_PATH . 'functions/date.php');
 require_once(SM_PATH . 'functions/mime.php');
 require_once(SM_PATH . 'functions/mime.php');
 require_once(SM_PATH . 'functions/mailbox_display.php');
 require_once(SM_PATH . 'functions/mailbox_display.php');
+require_once(SM_PATH . 'functions/compose.php');
 
 
 
 
 /* lets get the global vars we may need */
 /* lets get the global vars we may need */

+ 1 - 0
src/search.php

@@ -31,6 +31,7 @@ require_once(SM_PATH . 'functions/mime.php');
 require_once(SM_PATH . 'functions/mailbox_display.php'); //getButton()
 require_once(SM_PATH . 'functions/mailbox_display.php'); //getButton()
 require_once(SM_PATH . 'functions/forms.php');
 require_once(SM_PATH . 'functions/forms.php');
 require_once(SM_PATH . 'functions/date.php');
 require_once(SM_PATH . 'functions/date.php');
+require_once(SM_PATH . 'functions/compose.php');
 
 
 /** Prefs array ordinals. Must match $recent_prefkeys and $saved_prefkeys
 /** Prefs array ordinals. Must match $recent_prefkeys and $saved_prefkeys
  */
  */