(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 as test:users, while those in /home/users/othertest must be run as othertest: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 of test: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

I am not sure if I understood your question, but if you are trying to restrict execution and access between different users while removing read permission from others and allowing www-data to access these files you may try to do the following:

  • Compile suphp with paranoid setid-mode
  • Use the virtual host configuration and permissions you already have
  • Use extended acls to give read permission to www-data user on the specified folders (setfacL)

Suphp impersonate the script execution by using setuid, it will be based on filesystem permissions after comparing with the suPHP_UserGroup value. Using extended acls would allow www-data user to access all files, but will not permit execution of php scripts as it is not specified on suPHP_UserGroup directive.

You will need to add acl option on your /home filesystem (adding it to fstab and remounting the filesystem will be fine) before adding your extended acls on files and folders.

You can get more information about setfacl on it's manpage (http://linuxcommand.org/man_pages/setfacl1.html), it's fairly complete.

  • I'm afraid you may have missed a part of my question. Using paranoid mode isn't possible, since I can't set the user part. suPHP_UserGroup ??user?? users : I can't set a user, since they are many of them in the database. According to the request, the user may be different. Scripts from example.com and example.org must not be executed as the same user/group. – John WH Smith Jul 23 '14 at 22:58
  • I really didn't notice this part of the question. In this case where you can have more than one user in each folder and you can't set the suPHP_UserGroup in the specific virtual hosts, I don't see a solution without using dynamic configuration with a configuration management solution. – Luiz Viana Jul 30 '14 at 16:14

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.