security between sites
anarcat - November 14, 2008 - 19:51
| Project: | Hosting |
| Version: | 5.x-0.2.x-dev |
| Component: | Code |
| Category: | feature request |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | needs work |
Description
Right now, since all settings.php files are owned by the www-data user, sites can read each other's database settings. That's a security issue that can be worked around using various techniques described in:
http://groups.drupal.org/node/12066
In any case, I feel that hostmaster should have plugins to manage permissions on those files depending on the technique chosen.

#1
We want to at least move the db_url into the apache environment so that sites can't access each other's databases. They will still see private file uploads and things like that, but at least damage is limited for 0.1.
#2
The issue we have then is we can't rely on the settings in settings.php to install / synch / disable / etc sites.
This is an issue since we are only interfacing with drupal in command line mode. In HM1, i was parsing the vhost and setting up _SERVER vars by hand, but that was a hack. In this case i think we might need to use site.php instead of the vhost.
#3
Then maybe we just need to bite the bullet and properly setup file permissions and setup vhosts with fastcgi and proper permissions...
#4
I have made a lot of progress here.
I have built a hosting_itk and provision_itk modules that creates a vhost configuration file for the Apache ITK module. It's *almost* working: the file is created properly (through a new hook_provision_vhost_config()), the web_group is modified to be 5000 (hardcoded for now) + the client_id, and the webserver actually runs as that group. The only problem at this point is that the hosting task refuses to fix the permissions properly:
Could not change group ownership of settings.php to 5001 (the group does not exist)That would be actually true if I didn't make any other modification to my system. But I also experimented with libnss-mysql. I installed the libnss-mysql-bg package, which allows UID/GID <-> name mappings to be performed by MySQL. I have configured it to consult the Drupal 'users' and 'hosting_client' tables, the latter being the "group" "users" are part of...
It works on the command line:
mumia:/var/hostmaster/drupal-5.x/sites/testitk11# chgrp 5001 settings.phpmumia:/var/hostmaster/drupal-5.x/sites/testitk11# ls -l settings.php
-r--r----- 1 hostmaster Administrator 1820 nov 28 00:44 settings.php
Of course that's as root. If I add the "hostmaster" user to the "Administrator" group, it also works:
mumia:~/drupal-5.x/sites/testitk11# echo Administrator:x:5001:hostmaster >> /etc/hostsmumia:~/drupal-5.x/sites/testitk11# su hostmaster
mumia:~/drupal-5.x/sites/testitk11$ chown :5001 settings.php
mumia:~/drupal-5.x/sites/testitk11$
Note that I had to patch provision.path.inc so that it would take regular UIDs:
--- provision.path.inc 13 nov 2008 17:17:47 -0500 1.13.2.3
+++ provision.path.inc 28 nov 2008 00:42:56 -0500
@@ -183,10 +182,11 @@
return provision_posix_username(fileowner($path));
}
-function provision_path_chgrp($path, &$group, &$reason) {
- if ($group = provision_posix_groupname($group)) {
+function provision_path_chgrp($path, &$gid, &$reason) {
+ if ($group = provision_posix_groupname($gid)) {
if (provision_user_in_group(PROVISION_SCRIPT_USER, $group)) {
if (chgrp($path, $group)) {
+ $gid = $group;
return $group;
}
else {
@@ -197,7 +197,7 @@
$reason = t("@user is not in @group group", array("@user" => PROVISION_SCRIPT_USER, "@group" => $group));
}
}
- else {
+ elseif (!@chgrp($path, $gid)) { # try to change the group anyways
$reason = t("the group does not exist");
}
That hack is kinda crude and I probably should load that client and find its name, and chgrp on that, which may work.
I also needed this patch to make the settings.php fixed with the right perms:
--- provision_drupal.module 27 nov 2008 23:54:10 -0500 1.37.2.23+++ provision_drupal.module 28 nov 2008 00:42:44 -0500
@@ -83,7 +83,7 @@
provision_path("chmod", "sites/$url/settings.php", 0440,
t('Changed permissions of settings.php to @confirm'),
t('Could not change permissions of settings.php to @confirm'));
- provision_path("chgrp", "sites/$url/settings.php", PROVISION_WEB_GROUP,
+ provision_path("chgrp", "sites/$url/settings.php", $data['web_group'],
t('Change group ownership of settings.php to @confirm'),
t('Could not change group ownership of settings.php to @confirm'));
}
... not sure this is right, though..
Anyways, long story short, this works in principle, but there are implementation problems at this point. There also may be performance problems, but I would need a much larger test scenario here.
Note that the libnss configuration is minimal:
mysql> grant select on hostmaster.hostmaster_client to nss@localhost identified by '2JV2OHuO1dxb';mysql> grant select on hostmaster.users to nss@localhost identified by '2JV2OHuO1dxb';
I also include my configuration file.
Bottomline:
* works (or "should work" if it wasn't for PHP/provision.path.inc) as a module, marked as experimental
* depends on user/client relationship
* there will need to be a hostmaster users that is a member of every group for this to work
* needs benchmarking
#5
Stupid drupal.org refused my file...
#6
I have committed some changes to provision described above so that ITK can work out of the box with HEAD.
I have also committed nodeapi hooks that automatically add the hostmaster user to the right groups when they are created.
I need to test all this.
#7
the gid listings were broken in the nss configuration, here's an updated (fixed) config.
#8
I have imported ITK into provision HEAD now, but issues remain. Even though I committed code regarding that in hosting_itk, I still can't find a way to elegantly add the hostmaster user to every group created. Mainly because the Drupal users start at 1, so I have to add a "base uid" offset (GID_BASE, hardcoded to 5000 right now). This then means that the hostmaster user cannot be in that database because it's very likely to be created with a lower UID than GID_BASE. And anyways, the 'hostmaster user' isn't in the Drupal user database in the first place.
So in short, it's pretty hard to fix group memberships with 'real' unix users (in /etc/password) and groups define in the mysql database without some major hooplas. I even tried to make the hosting_client_user table to be unsigned, but that doesn't change anything because the libnss looks into the users table even for group lookups.
So the problem remaining still:
The symptom right now is this:
Could not change group ownership of settings.php to 5390 (the group does not exist)In fact, it's not that the group does not exist: it's that hostmaster isn't part of the group and therefore cannot change the ownership to that group. Example:
$ chgrp 5390 settings.phpchgrp: modification du groupe de `settings.php': Opération non permise
Right now, I see only two remaining solutions:
, backups, etc...)This is rather unfortunate and a major blocker at this point.
#9
Another solution would be to put the hostmaster user directly in the mysql database, as a real drupal user, and then manage permissions properly.
#10
Not needed for 0.2 release.