Sometimes there are really strange problems which leave you mystified as you can't find a sensible cause for the problem at hand.
The follow problem had me stumped for several minutes:
One of our webhosting customers tried to install phpNuke on his account.
He did it by the book, extracted the files, edited the config.php-file, configured the right database, everything seemed to be perfect.
Curiously, accessing his phpNuke pages with a webbrowser only resulted in the message "No input file specified".
As he could't find out why, he asked our support.
I grepped the phpNuke directory for that string but could not find any reference to it. Very strange. Googling for it '"No input file specified." phpnuke' didn't turn up anything good. But leaving out the phpnuke string came up with http://jenseng.com/archives/000035.html.
So it turns out, the "No input file specified." message is not generated by phpNuke but by the PHP-cgi binary itself.
Jon Jensen does descripe where the problem stems from:
The php-cgi binary is executed for every file with the extension .php (or .php3 if you are using an older version of the php interpreter) without the webserver checking if the file requested does exist. When it doesn't, the php-cgi binary will return said message: "No input file specified."
Strangely, the files requested do in fact exist.
Nevertheless, I tried the workaround and added the following commands to the httpd configuration:
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule ^.+.php$ /falsche_baustelle
Same result. Still the "No input file specified" message. As I expected, the webserver sees the file and calls the php-cgi binary which then reacts as if the file does not exist.
So, the problem was caused by something else.
Now, we are using not mod_php on our Apache httpd but mod_suphp, a Apache module which does change to the appropriate user before executing the php binary. This is pretty nifty, as it allows unix file permissions to work with the httpd.
In normal circumstances the phpfiles are read by the httpd server and the php code is executed internally and then the output is sent to the browser. This however means that the webserver has to be able to read the files (naturally) but also to have write access to a directory if you want to be able to upload files or generate images on the server or do any other thing which requires write-access to the filesystem.
This problem can be easily overcome by chmodding the directory where the files are put into to world writeable by calling chmod 777.
But this does pose a bigger problem. Consider a malvolent user on the same machine or even an external attacker who is able to exploit a hole in some other users webapplication. He can easily upload or write a php file with the following code:
The content of the .htpassword from some other user file will then be viewable by accessing the just written or uploaded php script.
Normally, this is not possible as file permissions prevent this. By instructing the mod_php interpreter to read this file, the .htpasswd file is accessed by the httpd, which has to be able to access this file.
Thus, unix file permissions are circumvented.
It is left as an excercise to the reader to implement other, much more interesting uses of the php filesystem commands. Think about writing to the htpasswd file to give yourself access to other peoples protected directories. Or write a script which recurses through all the homedirs and reads in every file, getting passwords.
Or just personal informations.
PHP has something called safe-mode. When activated, severe restrictions are put on filesystem commands preventing this. Furthermore, several other exploits are prevented as well. A recent example was the phpNuke security bug which allowed any attacker to add a &cmd= command to the URL of the phpnuke site. The value of the cmd variable was subsequently executed as a system command by the php interpreter. This is usually "not good"[tm].
Considering this, safe-mode seems like the best thing since sliced bread as it makes php much more secure.
But on the other hand, it limits the users severely as well. We do have several extensive webapplications running on our systems, most of the complex ones will be negatively affected if we would activate safe-mode.
Hence, we needed a different solution. This is where suphp comes in.
By executing the php-cgi binary after changing privileges to the owner of the php script, the unix filepermissions work again and the fopen-call described above will fail which is the "correct" behaviour and which is why several sites are using this mod_suphp wrapper.
Checking the logs, we see that the request for the index.php file is made, the wrapper intercepts it and calls the php binary to parse the script, which is where the message gets generated.
This was when I took a closer look at the permissions. Before, I checked the permissions of the files and considered them okay. The direcories in the webroot where set to 755 and the php files to 644, which is okay, as it only allows the owner to write to the files and everyone only can read the files.
As it turns out, the permissions of the files where in order but the permission of the docroot was messed up. The user in question set the docroot to 055 or d---r-xr-x, meaning that everyone is able to read the directory contents and also chdir to it, only the owner itself is unable to do so.
Which is exactly the reason why this strange problem appeared in the first place. The webserver sees the file and the suphp wrapper changes privileges to the user and spawns the php binary in the users security context.
Thanks to these messed up permissions the php binary is unable to access the files and just prints the failure message.
Thanks to the admin working as root and calling the php-cgi binary as root this never happened to us when looking at the problem.
So, if you ever see the "No input file specified." message and you are using mod_suphp, check the directory or file permissions first. It might save some time.