(Note: if you're familiar with suPHP setups and want to skip the question's details, you'll find a quick explanation of what I'm trying to achieve at the end)
I am currently setting up a machine to host several websites, belonging to several users. For convenience purposes, these users are stored in a MySQL database. libnss-mysql
and pam-mysql
are used to connect this backend and Linux, therefore allowing these users to log-in and use the machine's services. Every user stored in the MySQL database belongs to the users
group.
Each of these users is given a home directory under /home/users
. For instance, user test
' s files can be found under /home/users/test
. This directory has the following ownership/permissions:
drwx--x--- test www-data /home/users/test
Similarly, the website index (and other files) display the following permissions:
-rw-r----- test www-data /home/users/test/index.php
-rw-r----- test www-data /home/users/test/robots.txt
In order to allow access to these websites, the following VirtualHost is configured in Apache, using DBD and relying on the MySQL backend.
<VirtualHost *:80>
ServerName *
DBDriver mysql
DBDParams host=localhost,user=user,pass=pass,dbname=db
DBDocRoot "SELECT document_root FROM users WHERE domain=%s" HOSTNAME
</VirtualHost>
If the domain associated with test
is example.com, Apache will use DBD to match this domain with /home/users/test
and provide its contents. For instance, example.com/index.php will pass the index to the PHP interpreter, while example.com/robots.txt will have Apache deliver the file as static content.
Now, in order to protect my users from each other, I would like to restrict the permissions of their PHP scripts. With the above setup, PHP scripts go through Apache, and are interpreted by mod_php
. Thing is : the Apache process in run by www-data:www-data
, which gives access to all homes to any script.
To prevent this, I decided to install suPHP, but here is my problem : suPHP and the DBD MySQL lookup don't actually cooperate well:
- If I compile suPHP in paranoid mode, I must set a static user and group for all requests. However, scripts in
/home/users/test
must be run astest:users
, while those in/home/users/othertest
must be run asothertest:users
.
Here is where the problem happens in the configuration :
<VirtualHost *:80>
ServerName *
suPHP_Engine on
# The user is stored in the database, it can't be set statically.
suPHP_UserGroup ??user?? users
DBDriver mysql
DBDParams host=localhost,user=user,pass=pass,dbname=db
DBDocRoot "SELECT document_root FROM users WHERE domain=%s" HOSTNAME
</VirtualHost>
If I compile suPHP in owner mode, then all PHP scripts are executed as
test:www-data
instead oftest:users
. This will also provide privileges in all home directories.If I set all files to a
test:users
ownership in/home/users/test
(and use owner mode), then the web server can no longer access it, even to deliver static contents.
All in all
Is there any way I could combine both DBD MySQL and suPHP, and achieve something between paranoid mode and owner mode? I need to change the executing group from www-data
to users
(paranoid mode), but the executing user must be the script owner (owner mode). In a simple way :
# The following script must be interpreted as test:users.
-rw-r----- test www-data /home/users/test/index.php
# The following script must be interpreted as othertest:users.
-rw-r----- othertest www-data /home/users/test/index.php