Ubuntu – How to safely allow a php based website to create a linux user and interact with the environment

Apache2cronpermissionsPHPserver

My company has a web hosting service for which people sign up. After the sign up process is complete, we go in manually and create a test / dev environment for that client to use. Generally the process goes like this:

  1. create Linux user, switch to that user
  2. run scripts to install templated set of files and directories into their home directory
  3. create an Apache .conf file
  4. restart apache
  5. Send an email to let them know the server is setup and ready for access
  6. Finally, the client can access their site as somerandomstring.devserver.com

Even though we use scripts to do this, volume dictates that manually having to log in and run them is now inconvenient. So, we want to automate this process to be triggered immediately after the client sign up process is complete.

I've thought of a couple ways to handle this.

1) Give a user the addusercapability and use PHP exec() function to create said user. I'd have to give that capability to www-data though, right? With PHP running in safe mode, commands for exec() are restricted to a specified directory. So, if I were to copy /usr/sbin/adduser to /my/custom/dir where only that command is available, what would be the lingering security concerns? I'm still at a loss though how I'd update the sites-available folder with the new site, since those are owned by root.

2) Let cron do it: A person has to sign up for the service, so by default they have a username and other client data stored in mysql. From an account that has adduser capabilities, have cron run a routine script that checks for new accounts (maybe every 30 to 60 seconds). If found, create a linux account for them, populate the home directories, write the apache conf virtualhost file, and reload apache.

Option 2 feels like the most secure way in that an isolated admin account handles this without www-data or the website having to execute system scripts and programs. The problem is the batch. Preferably, I'd like to find an option 1 solution so that a client is immediately signed up and they are redirected to their installed-and-ready-to-use server instance. I also don't like that I'm having to reload / restart apache so much.

Companies do this every day, especially web hosting companies. Bluehost, for example, once you've completed the sign up process, you immediately have access to /home/user/public_html with which you can interact. Because commercial solutions exist, I'm sure a lot of thought has been given to how to accomplish it securely and safely. What I'm trying to accomplish is identical, just on a much smaller scale.

Best Answer

WARNING


This is an inherent security risk and has a lot of potential to go south at at any time. I'd highly advise against this setup, but oh well.

I'm not responsible for anything that happens as a result of you following anything given in this post, nor do I advise you to follow this system. This is mostly for educational/research purposes.

Linux has something known as setuid that allows any given program (like sudo) to run with privileges higher than the current executing user. You can write a shell script to do everything you need.

From there, because shell scripts can not be setuid, you need to convert this into a binary. You can use something like shc for this.

Once you have your shell pseudo-binary (example name: bootstrap_user) containing everything you need, you can do some fun alterations to get it ready. Namely, this:

  1. Set it owned by root, and group www-data.

     chown root:www-data ./bootstrap_user
    
  2. Assign RWX perms for owner (root), read and execute for group, none for anyone else:

     chmod 750 ./bootstrap_user
    
  3. Move the binary to somewhere PHP can exec() it.

  4. Finally, add the setuid bit to it, so that it's executed as root:

     chmod u+s ./bootstrap_user
    

In PHP, you can now call bootstrap_user as your executable, passing any required parameters. Be sure to take care to escape and sanitize input.

Related Question