After much reading on the net, I decided that there was very little in the way of good advise as to how to neatly run PHP in a secure wrapped way, without having to have a !#/usr/local/bin/php at the top (or if there was, I couldn't find it).
However, I believe I have a solution (that I threw together with suggestions from other peoples pages, who I would credit now if I could find them).
The premise is quite simple, I have two compiled versions of PHP on my box, a DSO module version and a standalone binary.
In my apache config (which is set to SUEXEC CGIs) I added the line:
AddType application/x-httpd-wphp .wphp
Action application/x-httpd-wphp /~fennb/wrapper/phpwrapper.cgi
Note that the wrapper must go here and be owned by the owner of the directory, and the person who you wish to SUEXEC as.
Now, phpwrapper.cgi was originally a shell script, but for speed purposes, I rewrote it in C. Now I am by no means a C programmer, so please excuse the code, but it went as follows:
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
/ Set the PHP constant to point to the PHP command interpreter /
#define PHP "/usr/local/bin/php"
int main (void)
{
int status;
pid_t pid;
pid = fork ();
if (pid == 0)
{
/ This is the child process. Execute the php interpreter. /
execl (PHP, PHP, NULL);
_exit (EXIT_FAILURE);
}
else if (pid < 0)
/ The fork failed. Report failure. /
status = -1;
else
/ This is the parent process. Wait for the child to complete. This seems to be necessary /
if (waitpid (pid, &status, 0) != pid)
status = -1;
return status;
}
Now, essentially what happens is that whenever you want to run a wrapped script, you change the extension to .wphp and apache hands it off to the CGI to handle, the CGI then is SUEXEC'd and forks to the PHP command interpreter, which then runs the script setuid.
The reason I have the 2 copies of PHP (DSO/CGI) is for speed reasons, so that if a script does not need to be wrapped, it can be ran as normal. However, I ran a few speed test, and much to my surprise, the CGI standalone version ran 30-50% faster than the DSO version which was very odd.
My main question is: Is this secure, or have I missed a massive security hole. No arguments are passed to the PHP interpreter and the location is explicitly specified so I don't see any my self, but I'm sure there may be some I'm missing.
I'm writing a full doc as to how to set it up so if anyone is interested, I'd be happy to make it available.
Cheers,
Fenn Bailey.