We tried suPHP on our servers for a short time. What suPHP does, is run PHP as the same user as owns that website. It will then only execute PHP scripts that are owned by that same user, and are not writeable by the group, i.e. not writeable by any other user. The idea of this on shared hosting, is to prevent one account writing PHP scripts in another account where the directory permissions have been left wide open, and then being able to execute those scripts through the HTTP interface.
The okay is okay at first glance, but does have a flaw. The scripts are all run as the same user that you FTP the PHP application as. The web user owns all the PHP scripts in the application. You may be protected from other users, but if a hacker gets into your site just by one back door or flaw, he can run riot with all your scripts, since he owns them and can change anything. By taking away the permission to change those files, you also take away the permission to execute those files at all, so you are stuck between a rock and a hard place. This would not do.
The more traditional way to run a PHP application, is to upload your files as an FTP user, then have them executed as a shared apache user – either apache or in older times nobody. This way you have more control of permissions and can decide which files in your application apache can read and write to, and which directories it has access to. The downside is that giving apache permissions to access files or write to a directory means giving everyone access to do so, which is especially dangerous on a shared hosting server.
One solution is a hybrid – mod_ruid2.
This is how we would set a site up:
The site would have two Linux users: one to manage FTP and ssh into the site, and the other to run the PHP web scripts. A user group would be set up and both these users would be added to the same group. So for mysite.com, the users may be:
Only ftpmysite would have a home directory. webmysite would have no home directory and no shell set up.
The group wound be:
I’ll list the Linux commands for setting this up later.
Now we need to tell mod_ruid2 to run any PHP scripts on this site as webmysite. This is done by adding an entry to:
<Directory /httpdocs> RMode config RUidGid webmysite mysitegrp </Directory>
The application is then uploaded to the web space as user ftpmysite. We then need to check permissions of the uploaded application:
- Firstly all directories that contain web-accessible resources or scripts must have read and execute permission for “other”, for everyone.
- Any .htaccess file must also be readable by “other”.
- Any php script needs read permission for “group”.
So when a PHP script is executed, the PHP process will run as webmysite. That user is a member of the mysitegrp group, and so can read that file.
The PHP script that runs as webmysite, may also need to create files on the server. This is where problems arise with SugarCRM.
SugarCRM makes heavy us of the “cache” directory. It will put PHP scripts in there for executing, and also web-accessible resources such as images and CSS files. By default SugarCRM will create files with this permission:
- 0660 – read/write for owner and group; nothing for anyone else.
It will also create folders of this permission:
- 02770 – read/write/list for owner and group; nothing for anyone else.
Remember, these files are being created by the webmysite user. The permissions lack two things:
- Apache cannot scan the directories in the first place, so cannot find any of these files if it needs to. It will not be able to find any of the web resources in the cache.
This is fixed in a setting that can be configured in SugarCRM. Here is the default, from config.php:
$sugar_config['default_permissions'] = array ( 'dir_mode' => 1528, // == 02770 'file_mode' => 432, // == 0660 'user' => '', 'group' => '', );
The permissions are bizarrely given in decimal. I’ve provided the octal equivalents. Copy this to config_override.php and change the permissions as follows:
$sugar_config['default_permissions'] = array ( 'dir_mode' => 02775, 'file_mode' => 0664, 'user' => '', 'group' => '', );
Once you have saved the permissions once, this array will be expanded into a separate line for each element, and will look like this:
$sugar_config['default_permissions']['dir_mode'] = 1533; $sugar_config['default_permissions']['file_mode'] = 436;
That explains where the integers come from in the permissions settings – they are system generated. Remember to convert them back into octal before trying to understand exactly what those permissions do.
With this configured, directories generated in the SugarCRM cache area will gain the read and execute (aka list) permission for everyone, and files will gain read permission for everyone. Ideally, read permission is only needed for web accessible resources, and not for PHP scripts in the cache, but without some changes to core SugarCRM there is not a lot we can do about that (SELinux may offer some solutions here, but that is a whole different area altogether).
TODO: Linux commands to set up the users and groups. What the sticky bit does. Come and kick me if I haven’t finished this off!