Latest Tweets

SquirrelMail 1.4.17 / 1.4.21 & G/PGP Plugin 2.1 (2): The attachments are not renamed as “.asc” and incorrect mime type associated

Preamble

According to my first and long time ago code analysis, the G/PGP plugin for the SquirrelMail 1.4.17 version did not work properly. Among other small issues, there was an important one being widely discussed in this previous post: https://disbauxes.upc.es/?p=1337. The small alterations I came to make on its source code allowed us to encrypt, sign and send messages using PGP. The attachments were also encrypted. However, the attachments were not renamed as “attachment.name.extension.ASC”, therefore they could not be decrypted from inside the SquirrelMail interface, nor their mime type fixed accordingly. This was annoying enough, because the email messages were being sent with an incorrect mime type associated with every single of their attachments, causing trouble. This can be clearly seen in the screenshot below:

The attachment, though it is not obvious, has also been encrypted but it keeps its original name and mime type.

The attachment, though it is not obvious, has also been encrypted but it keeps its original name and mime type.

Whenever opening the email after sending it, or even when someone sent us an encrypted message with an encrypted attachment, we could not decrypt the attachment from within the SquirrelMail interface, nor even know beforehand whether the attachment had been previously encrypted or not, because its mime type was not correct. This problem also affected every kind of email client, like Thunderbird, for obvious reasons.

Enabling debug mode

This time, I had to enable the P/GPG plugin’s debug facilities in order to analyse the Message object generated after pushing the “Encrypt” button. To do that, I edited the plugins/gpg/gpg_local_prefs.txt in order to set this option:

debug=1

After trying to encrypt a new message with an attachment, this is what I got:

message Object
(
    [rfc822_header] => 
    [reply_rfc822_header] => 
    [mime_header] => 
    [flags] => 
    [type0] => 
    [type1] => 
    [entities] => Array
        (
            [0] => message Object
                (
                    [rfc822_header] => 
                    [reply_rfc822_header] => 
                    [mime_header] => messageheader Object
                        (
                            [type0] => application
                            [type1] => vnd.oasis.opendocument.text
                            [parameters] => Array
                                (
                                    [name] => back_alley.odt
                                )

                            [id] => 0
                            [description] => 
                            [encoding] => 
                            [size] => 0
                            [md5] => 
                            [disposition] => disposition Object
                                (
                                    [name] => attachment
                                    [properties] => Array
                                        (
                                            [filename] => back_alley.odt
                                        )

 Clearly, our new Message object did not have either its mime type nor its filename correctly set for its attachments after encrypting them. In this particular case, the Message object has only one attachment, with index key 0, being its mime type application/vnd.oasis.opendocument.text.

The code in charge of renaming and altering these object’s structures

 P/GPG does rename and alter the mime type associated with every attachment present inside the email message. However, the mistake was located precisely in the way this was done: by value, and not by reference! Below, a code snippet showing the code in charge of altering the $newMessage data structures inside the plugins/gpg/gpg_encrypt.php source code file:

                    $entity = $newMessage->entities[$entity_id];
                    if (trim($entity->att_local_name) == trim($attachment->att_local_name)) {
                        //set the mime type
                        $entity->mime_header->type0 = 'application';
                        $entity->mime_header->type1 = 'pgp-encrypted';
                        $newfilename = $attachment->mime_header->disposition->properties['filename'].'.asc';
                        $entity->mime_header->disposition->properties['name'] = $newfilename;
                        $entity->mime_header->disposition->properties['filename'] = $newfilename;
                        $entity->mime_header->parameters['name'] = $newfilename;
                        $entity->mime_header->parameters['filename'] = $newfilename;
                        //set the name of the attachment to be the .asc file
                        $entity->att_local_name = $attachment->att_local_name . '.asc';

The first line, in theory, is referencing the $newMessage->entities[index] object, where the nth attachment’s information resides. But it clearly fails in doing so, because the variable $entity is just a copy of $newMessage->entities[index] object, therefore not altering the actual $newMessage->entities[index] data. In order to fix this first issue all I had to do was to modify this first line this way:

$entity = &$newMessage->entities[$entity_id];

Thus, now $entity was a reference to $newMessage->entities[$entity_id] and, being so, its entire structure was indeed altered. We can clearly see this after pushing the “Encrypt” button once again:

   [type0] => application
                            [type1] => pgp-encrypted
                            [parameters] => Array
                                (
                                    [name] => back_alley.odt.asc
                                    [filename] => back_alley.odt.asc
                                )

                            [id] => 0
                            [description] => 
                            [encoding] => 
                            [size] => 0
                            [md5] => 
                            [disposition] => disposition Object
                                (
                                    [name] => attachment
                                    [properties] => Array
                                        (
                                            [filename] => back_alley.odt.asc
                                            [name] => back_alley.odt.asc
                                        )

                                )

However, the attachment’s list on the bottom top of the page was still showing the same filename and with a filesize of 0 bytes, because it was still trying to find a file with its original name. According to the apache log file:

[error] PHP Warning:  filesize() [<a href=’function.filesize’>function.filesize</a>]: Stat failed for ../../data/FUUg9uPmvhB8LdZSzRBLHn333r8ajEIJ.asc (errno=2 – No such file or directory) in /path/to/squirrelmail/src/compose.php on line 1244

So, apparently, the $newMessage object was already being altered but the attachment’s list was not aware of it.

Altering the attachments serialized object

 As we already know from my original post, the global serialized object attachments has the information concerning all the attachments inside the message. We could get any message’s attachments by using this code snippet – as I already did in my previous post -:

   sqGetGlobalVar('attachments',$attachments,SQ_INORDER);
    if (!empty($attachments)) {
        $attachments = unserialize($attachments);
        if (!empty($attachments) && is_array($attachments))
                 $newMessage->entities = $attachments;
    }
    $messageAttachments = &$newMessage->getAttachments();

And, in fact, the attachment’s bottom page list is a direct result of calling the function formatAttachments, inside the functions/mime.php source code file. The problem seemed very simple to solve: the attachments object was not modified and so, the formatAttachments function could not show the new changes. To fix this second and last issue, I added a new line of code inside the plugins/gpg/gpg_encrypt.php file right after the one updating the body part of the message. It is the last line in this code snippet:

//set the body to be the cyphertext
gpg_setglobal ('body' ,$cyphertext);
// set the attachments - the ASC ones - :
gpg_setglobal('attachments',serialize($newMessage->entities));

Testing the patch

 After pushing the “Encrypt” button once more, we got the correct attachment in the attachment’s list, as clearly shown below:

Now, the same email message is showing the correct filename and mime type for its encrypted attachment.

Now, the same email message is showing the correct filename and mime type for its encrypted attachment.

Finally, we could even see the “Decrypt” link beside the attachment’s name when reading the email message:

And now, we can see the Decrypt and Verify Sign beside the attachment's name.

And now, we can see the Decrypt and Verify Sign beside the attachment’s name.

You can get the gpg_encrypt.php patched file from here; all you have to do is to replace yours with this new version.

Or you can download the complete GPG plugin with the altered gpg_encrypt.php file from HERE.