Wednesday, September 21, 2011

Apache segfaults when PHP runs LDAP functions

I've been spending some time at work compiling a web stack to update the old, unsupported, and unmaintained Solaris webstack/coolstack software. It consists of the latest stable releases of Apache's httpd, MySQL, PHP, Python, and phpMyAdmin, compiled from source, to include all of their dependencies. One specific requirement here is that the various LDAP modules work. Many of our customers use this to authenticate users against a master directory on the network. I've encountered a problem.

I have a test script that pulls my own user information from our LDAP server. If I run this through the CLI PHP parser, it successfully and correctly gathers my information. If I hit that page up through Apache, httpd throws a segmentation fault. Even if I set Apache's LogLevel directive to 'debug', I get no information aobut *why* it segfaults. The only relevant output is as follows:

[Wed Sep 21 13:23:06 2011] [notice] child pid 6928 exit signal Segmentation fault (11) [Wed Sep 21 13:23:06 2011] [info] removed PID file /opt/utsawebstack/apache2/logs/httpd.pid (pid=6923) [Wed Sep 21 13:23:06 2011] [notice] caught SIGTERM, shutting down

The segfault *only* happens when LDAP functions are called from PHP. ldap_connect(), for example, fails. Other pages render fine through Apache.

Google hasn't been much help. The closest I've come to a solution is a patch for PHP version 4.4.4 — a version of PHP known to be buggy and unusable — and the patch no longer applies.

For the sake of detail, here are the configure strings for the relevant software (taken from a working build script, hence the variable names):

  • Berkeley DB (a dependency of OpenLDAP):
  • ../dist/configure --prefix=$BUILDBASE/lib
  • OpenLDAP (client only):
  • ./configure --prefix=$BUILDBASE/lib/ --disable-slapd --disable-slurpd
  • httpd:
  • ./configure --prefix=$BUILDBASE/apache2 --with-ldap --enable-authnz-ldap=shared --enable-ldap=shared --enable-headers=shared --enable-mime-magic=shared --enable-proxy=shared --enable-rewrite=shared --enable-mods-shared --enable-ssl=shared --with-z=$BUILDBASE/lib
  • PHP
  • ./configure --prefix=$BUILDBASE/php --with-apxs2=$BUILDBASE/apache2/bin/apxs --with-zlib=$BUILDBASE/lib --with-curl=$BUILDBASE/lib --with-iconv=$BUILDBASE/lib --enable-calendar --with-mysql=mysqlnd --with-mysqli=mysqlnd --enable-sockets --enable-zip --with-pear -with-mcrypt=$BUILDBASE/lib --enable-mbstring --with-ldap=$BUILDBASE/lib

Level of Difficulty: Solaris 10

Other Things I Know:

  • It's probably not a compiler problem. I'm using the latest version of make to do all of the compiling, and it's using GCC 3.4.3. And besides, most of this code requires GCC. Using the Sun/Oracle compiler would likely cause problems and failure.
  • It's not an architecture thing. I have compiled this and reproduced the problem on i386 and sparc hardware.
  • Since PHP and Apache are both compiled against the version of OpenLDAP that gets compiled first (see config string above), both are heavily reliant upon the ldap.conf file associated with it. Perhaps this is obvious to most, but I had wrongly assumed for some reason that Apache was the only thing using that. For what it's worth, that file is properly written.

Who has any idea what's going on here? Anybody?

FOUND A SOLUTION

The problem basically boils down to this:

I wrongly assumed that the --with-ldap configure argument would accept a directory to look in for the OpenLDAP libs (f/ex, --with-ldap=/opt/webstack/lib). It does not. Instead, I needed to throw in the --with-ldap argument with no directory attached to it along with --with-ldap-libs=/my/openldap/lib/dir and --with-ldap-include=/my/openldap/include/dir. Problem solved.

Sunday, January 23, 2011

Setting up public key authentication for SSH

If you're like me, you remote into a handful of servers using SSH all the time. The process is fairly simple:

  1. Get to a terminal
  2. ssh username@hostname
  3. Type password
  4. Get to work

No, it's not terribly difficult, but when you have to type that password fifty times per day, you begin to realize that it's time-consuming and repetitive. And there happens to be a way to eliminate that step from the process.

The SSH protocol supports authentication by public keys, and setting this up is a trivial matter. The configuration process goes something like this:

  1. Generate a key for your client system
  2. Put it on the server

One prerequisite: your SSH server must have public key authentication enabled. This is usually the case by default, but if you want to check, you can look in your /etc/ssh/sshd_config file. Try this:

grep 'PubkeyAuth' /etc/ssh/sshd_config

If the output is

PubkeyAuthentication yes

then you're safe to continue. Otherwise, you'll have to make the change in that file and restart the SSH server. There are a few ways to accomplish this, and I won't go into them here because it's not the point.

The point is that once this is ready, you can create your RSA key on the client machine. This is the first step toward getting this done. On the client machine, run

ssh-keygen -t rsa

You'll be asked for a filename. Just press enter to accept the default, which is probably ~/.ssh/id_rsa

You'll also be asked for a passphrase. You can use this optionally. If the point is to eliminate having to enter a password with every SSH connection, it's best to supply no passphrase. You'll also be asked to confirm it.

When done, you'll get a printout of your fingerprint and you'll return to a prompt.

Now we need to check this file's permissions. We don't want any other users to be able to read this pubkey file lest they compromise your authentication.

chmod 600 ~/.ssh/id_rsa.pub

EDIT: Commentor FKereki rightly points out a simpler and better way to accomplish the publication of your public key to your server. You can (and should) run:

ssh-copy-id username@hostname

This command makes sure that the pubkey is added to the appropriate file, and it makes sure nothing gets lost. This is the best possible way to accomplish this task if the command is available to you. However, should you be working in a system where this isn't available (such as a Solaris environment), you can use the following steps to make things work.

Copy your public key to the server as a specific filename.

scp ~/.ssh/id_rsa.pub username@server:~/.ssh/authorized_keys

Make sure the authorized_keys file has the same permissions so it won't be compromised.

The next time you log in from this client machine, you won't be asked for your password.