Installing Apache 2.4 with PHP on FreeBSD for Drupal 8. It’s a Nightmare

I’ve been playing about the Drupal 8 (still in Beta) and one of its features is that it needs the latest version of PHP (5.5.9 or later). I have a server I keep for testing the latest whatever, and this includes Apache 2.4. So how hard can it be to compile in PHP?

Actually, it’s not straightforward. Apache 2.4 is fine, but PHP is another matter. First off, installing lang/php55 does not include mod_php for Apache. It’s not that the option to compile it hasn’t been set – the option has gone. With a bit of digging around you can find it elsewhere – in www/mod_php55. Don’t be fooled in to thinking you need to just build and install that though…

You’ll probably end up with stuff like this in your httpd error log:

Call to undefined function session_name()
Call to undefined function hash()

Digging further you’ll find www/php55-session and security/php55-hash in there, and go off to build those too. Then wonder why it still isn’t working.

The clue can be found with this log file error:

PHP Warning: PHP Startup: Unable to load dynamic library '/usr/local/lib/php/20121212-zts/session.so' - Cannot open &quote;/usr/local/lib/php/20121212-zts/session.so&quote; in Unknown on line 0

(NB. The &quote appears in the log file itself!)

Basically, mod_php expects you to compile the ZTS (Zend Thread Safe) version of everything. And why wouldn’t you? Well it turns out that this important option is actually turned off by default so you need to configure the build to include it. Any extensions you’ve compiled up until now will not have been placed in a directory tagged with -zts, which is why it’s looking in the wrong place as shown by the error log.

Please generate and paste your ad code here. If left empty, the ad location will be highlighted on your blog pages with a reminder to enter your code. Mid-Post

If you’re reading this following a Google search, you’ve probably already fallen down the Pooh trap. You need to go back to lang/php55 and start again with the correct options. The best way to do this (in case you didn’t know) is:

make clean
make config
make
make install

When you run make config it’ll give you a chance to select ZTS, so do it.

Repeat this for compiling www/mod_php55 and then go back and compile www/php55-session, security/php55-hash and anything else you got wrong the first time, You don’t have the option to configured them, but they must be compiled again once the core of PHP has been compiled using ZTS.

Incidentally, if you haven’t had this pain before, you will probably need to switch to using the new pkg system if you haven’t already. Trying to build without it, it’ll put up a curt little note about it and go in to sulk mode until you do. Unfortunately, on an older FreeBSD, any attempt to compile this will result in an O_CLOEXEC symbol undefined error in pkg.c. This is actually a flag to the open() kernel function that was added to POSIX in 2008. What it means is that if your process subsequently makes exec call, the file handle will be automatically closed. It saves leaking fds if your execution path goes awry. But what’s the solution?

Well, if you’re using an older version of the kernel then it won’t support O_CLOEXEC anyway, so my fix is to delete it from the source and try again. It only appears once, and if the code is so sloppy that it doesn’t close the handle, it’s not the end of the world. The official answer is, of course, to upgrade your kernel.

If you are running Drupal 8, here’s a complete list of the ports you’ll need to compile:

lang/php55 (select ZTS option in the configuration dialogue)
www/mod_php55 (select ZTS option in the configuration dialogue)
www/php55-session
security/php55-hash
security/php55-filter
devel/php55-json
devel/php55-tokenizer (for Drupal 8)
databases/php55-pdo
databases/php55-pdo_mysql
textproc/php55-ctype
textproc/php55-dom
textproc/php55-simplexml
graphics/php55-gd
converters/php55-mbstring (not tested during setup)

All good fun! This relates to Drupal 8.0.0 RC1 – it may be different with the final release, of course.

FreeBSD ports build fails because of gfortran

I’ve been having some fun. I wanted to install the latest ported versions of Apache and PHP for test purposes, so set the thing compiling. There are a couple of gotchas!

First off, the current ports tree will throw errors on the Makefile due to invalid ‘t’ options and other fun things. That’s because make has been updated. In order to prevent you from using old “insecure” versions of FreeBSD, it’s considered “a good thing” to cause the build to break. I’m not kidding – it’s there in the bug reports.

You can get around this by extracting the new version of make for the 8.4 iso image (oldest updated version) – just copy it over the old one.

Some of the ports also require unzip, which you can build and install from its port in archivers.

Now we get to the fun part – because the current system uses CLANG but some of the ports disagree, when you go to build things like php5_extensions (I think the gd library in particular) it depends gcc, the GNU ‘C’ compiler, and other GNU tools – so it tries to build them. The preferred version appears to be 4.7, so off it goes. Until it goes crunch. On inspection it was attempting to build Fortran at the time. Fortran? It wasn’t obvious why it broke, but I doubted I or anyone else wanted stodgy old Fortran anyway, so why was it being built?

If you look in the config options you can choose whether or not you want Java. (No thanks). But in the Makefile it lists
LANGUAGES:=    c,c++,objc,fortran
I’m guessing that’s Objective C in there – no thanks to that too. Unfortunately removing them from this assignment doesn’t solve the problem, but it helps. The next problem will come when, thanks to the new binary package system, it tries to make a tarball of the fortran stuff it never compiled. I haven’t found how this mechanism works, but if you create a couple of empty directories and a an empty file for the man page it’ll proceed oblivious. I haven’t noticed and adverse effects yet.

A final Pooh trap if you’re trying to build Apache 2.4, mod_php5 and php5-extensions is the Zen Thread-Safe options (ZTS). If you’re not consistent with these then Apache/mod_php will fail to load the extensions and print a warning in httpd-error.log. If you build www/mod_php5 you’ll see a warning like:

 

/!\ WARNING /!\
!!! If you have a threaded Apache, you must build lang/php5 with ZTS support to enable thread-safety in extensions !!!

 

Naturally, this was scary enough to make me stop the build “make config” to select the option. Unfortunately it’s also an option on lang/php5 and if you didn’t set it there then it’ll go crunch. Many, many thanks to Matthew Seaman from FreeBSD.org, who figured out what I’d done wrong.

PAM authentication in PHP on FreeBSD

I have several groups of lusers who want to be able to set/change their mail vacation settings but aren’t up to using ssh to edit their .forward and .vacation.msg files. I thought I’d write a quick PHP application to allow them to do it in a luser-friendly way using a web browser. If this isn’t what PHP is for, I don’t know what good it is. The snag: you need to make sure the right user is editing the right file.

The obvious answer is to authenticate them with their mail user-name and password pair using PAM. (This is the system that will check user-name/password combinations against whatever authentication you see fit – by default /etc/passwd).

PHP has a module available for doing just this – it’s called “PAM” and there’s even a FreeBSD port of it you can install from /usr/ports/security/pecl-pam. If you want to use it, just “make” and “make install” – it’ll add it to the PHP extensions automatically, but don’t forget to restart Apache if you’re planning to use it there.

You’ll also have to configure PAM itself. This involves listing the authentication methods applicable to your module in /etc/pam.d/. In this case the php module will have the default name ‘php’ unless you’ve changed it in /etc/php.ini using a line like pam.servicename = "php";

Adding the above line above obviously does nothing as it’s the default, but it’s useful as a reminder of what the default is set to. I don’t like implicit defaults, but then again I don’t like a lot of the shortcuts taken by PHP.

The only thing you need to do to get it workings is to add a PAM module definition file called /etc/pam.d/php. The easy way to create this is copy an existing one, such as /etc/pam.d/ftp. This will be about right for most people, but read /etc/pam.d/README if you want to understand exactly what’s going on.

So – to test it. A quick PHP program such as the following will do the trick:

<?php
var_dump (pam_auth('auser','theirpassword',&$error,0));
print $error;
?>

If there’s an entry in /etc/passwd that matches then it’ll return true, otherwise false, and $error will contain the reason. Actually, it checks the file /etc/master.passwd – the one that isn’t world readable and therefore can contain the MD5 password hashes. And there’s the rub…

This works fine when run as root, but not as any other users; it always returns false. This makes it next to useless. It might be a bug in the code, but even if it isn’t it leads to interesting questions about security. For example, it would allow a PHP user to hammer away trying to brute-force guess passwords. I’ve seen it suggested to Linux users can overcome the need to run as root by making their shadow password group or world readable. Yikes!

If you’re going to use this with PHP inside Apache, you’re talking about giving the “limited” Apache user access to one of the most critical system files as far as security goes. I can see the LAMP lusers clamouring for for me to let them do this, but the answer is “no!” Pecl-pam is not a safe solution to this, especially on a shared machine. You could probably persuade it to use a different password file, but what’s the point? If the www user can read it, all web hosting users can and you might just as well read it from the disk directly (or use a database). PAM only makes sense for using system-wide passwords for authenticating real users.

I do now have a work-around: if you want your Apache PHP script to modify files in a user’s home directory you can do this using FTP. I’ve written some code to achieve this (not hard) and I’ll post it here if there’s any interest, and after I’ve decided it’s not another security nightmare.

 

PHP PDO driver missing on FreeBSD

I got an email today – a FreeBSD 8.2 Web server installation with Apache and PHP 5.3 was missing its mySQL driver. No it wasn’t, I protested. But this error was appearing:

[error] [exception.CDbException] could not find driver
[error] [exception.CDbException] exception 'CDbException' with message 'CDbConnection failed to open the DB

“It’s not the database, it’s the PDO module”, came the explanation. Actually the pdo.so module was there and loaded, and it was installed in just the same way as it had been on earlier versions. So what was going on?

It turns out that as of PHP 5.3 there has been a change. You don’t get the important module – pdo_mysql – loaded when you compile /usr/ports/lang/php5-extensions. It’s not that it’s no longer checked by default – it’s not even there! I’m told this applies to Postgress too.

Further investigation revealed that PHP5.3 has a new native-mode driver (mysqlnd), and this is now outside the standard install. If you’re using sqlite for Persistant Data Objects, no problem, but if you’re using a more restrictive hosting account and therefore need to store them in a mySQL (or Postgress) database you seem to be out of luck.

For more information, see here.

However, the required module can still be found. Go to

/usr/ports/databases/php5-pdo_mysql

(If you’re using Postgress go to php5-pdo_pgsql instead – see Geoffrey McRae’s comment below).

make and make install what you find there. Also, make sure you compiled the original php5-extensions with mysql and mysqli, and don’t forget to restart Apache afterwards!

Note that it’s quite possible that none of the above relates to Linux. It’s to do with what gets installed from where with the FreeBSD ports tree.

Comment spam from Volumedrive

Comment spammers aren’t the sharpest knives in the draw. If they did their research properly they’d realise that spamming here was a stupid as trying to burgle the police station (while it’s open). You’ll notice there’s no comment spam around here, but that isn’t to say they don’t try.

Anyway, there’s been a lot of activity lately from a spambot running at an “interesting” hosting company called Volumedrive. They rent out rack space, so it’s not going to be easy for them to know what their customers are doing, but they don’t seem inclined to shut any of them down for “unacceptable” use. For all I know they’ve got a lot of legitimate customers, but people do seem to like running comment spammers through their servers.

If you need to get rid of them, there is an easy way to block them completely if you’re running WordPress, even if you don’t have full access to the server and its firewall. The trick is to over-ride the clients Apache is prepared to talk to (default: the whole world) by putting a “Deny from” directive in the .htaccess file. WordPress normally creates a .htaccess file in its root directory; all you do is add:

Deny from bad.people.com

Here, “bad.people.com” is the server sending you the spam, but in reality they probably haven’t called themselves anything so convenient. The Apache documentation isn’t that explicit unless you read the whole lot, so it’s worth knowing you can actually list IP addresses (more than one per line) and even ranges of IP addresses (subnets).

For example:

Deny from 12.34.56.78
Deny from 12.34.56.89 22.33.44.55
Deny from 123.45.67.0/24

The last line blocks everything from 123.45.67.0 to 123.45.67.255. If you don’t know why, please read up on IP addresses and subnet masks (or ask below in a comment).

So when you get a a load of spammers from similar IP addresses, look up to see who the block belongs to using “whois”. Once you know you can block the whole lot. For example, if you’re being hit by the bot using Volumedrive on 173.208.67.154, run “whois 173.208.67.154”. This will return:

NetRange: 173.242.112.0 - 173.242.127.255
CIDR: 173.242.112.0/20
OriginAS: AS46664
NetName: VOLUMEDRIVE
NetHandle: NET-173-242-112-0-1
Parent: NET-173-0-0-0-0
NetType: Direct Allocation

<snip>

If you don’t have whois on your comptuer (i.e. you’re using Windoze) there’s a web version at http://www.whois.net/.

In the above, the CIDR is the most interesting – it specifies the block of IP addresses routed to one organisation. I’m not going in to IP routing here and now, suffice to say that in this example it specifies the complete block of addresses belonging to volumedrive that we don’t want – at least until they clean up their act.

To avoid volumedrive’s spambots you need to add the following line to the end your .htaccess file:

Deny from 173.242.112.0/20

If this doesn’t work for you the the web server you’re using may have been configured in a strange way – talk to your ISP if they’re the approachable type.

I have contacted Volumedrive, but they declined to comment, or even reply; never mind curtail the activities of their users.

This isn’t a WordPress-only solution – .htaccess belongs to Apache and you can use it to block access to any web site.

Perhaps there’s some scope in sharing a list these comment spambots in an easy-to-use list. If anyone’s interested, email me. This is a Turing test :-)