Unix Groups
From DreamHost
| The instructions provided in this article or section require shell access unless otherwise stated. You can use the PuTTY client on Windows, or SSH on UNIX and UNIX-like systems such as Linux or Mac OS X. |
Unix groups are used for file sharing, and that is it. They are not normally used for anything else.
Contents |
Creating Groups
To create a group, go to Users > Unix Groups in the Web Panel. Everything there should be self-explanatory. Please note that when adding users, they will be assigned to a default group (in the form of pg######).
Sharing Files between Groups
To share files or to share website access, first create a group (or use the default one if you don't mind all of your users having access). Next, sign in to SSH/shell. Go to the directory you want to share, and do:
chgrp -R new_group /home/user/directory
to change the group of that folder. To access the folder from other users, they will need to sign in to the shell and then CD to the shared folder. That's it! For more control over group permissions, just change the permissions of the group of the file. See Unix File Permissions.
Caveat: if you have any .cgi files, the above command will make them fail to run and generate HTTP 500 errors. Be sure that you leave the group for the .cgi and its parent directory as the default group. That is, if your .cgi file is in /home/joe/example.com/cgi/fun.cgi then the following directories/files must be joe's default group: /home/joe/example.com/cgi, /home/joe/example.com/cgi/fun.cgi.
DreamHost Security Defaults
When you add a user, it is automatically added to your default pg###### group. Another thing to note is that by default, all of your files are of the same default pg###### group unless you changed it yourself. This means that any other users that you have in the Web Panel have (read) access to all of your files. If you do not trust your users, follow the instructions below.
Protecting your files from other members of your group
Option 1: chgrp
To keep other members of your group out of your stuff, you can create a new group in the panel, and add only yourself to the group. Then change the group of all of your files that you want to protect:
chgrp -R my_group /home/user/directory
The down side to this is that you have to chgrp any new files when they are created in order to continue protecting them.
Option 2: chmod g-x
To keep everyone from your group out, you can also use this method. Simply remove execute permissions from the directory you want to protect:
chmod g-x /home/user/directory
The down side to this is that you have to remember to do this for every folder that you create, and have to remember not to do it to any of your web folders
Option 3: SetGID bit
Set the GID bit on your root folder and any already existing folders:
chgrp -R <my_group> ~/
find ~/ -xdev -user <username> -group <my_group> -type d -print -exec chmod +s {} \;
Line one of this changes the group ownership of all 'files' and 'folders' (within your home folder ~/) to the specified <my_group>.
Line two 'sets the GID bit' for all the 'folders' within your home folder and it's sub-folders. (In particular, it modifies all that are owned by the specified <my_group> which should be all of them if the command from line one was executed successfully.) Setting the GID bit on a folder changes it such that subsequently any folders or files created within it will be owned by the specified <my_group>.
The down side to this is that if the group of a folder is ever changed, it loses the GID flag and anything under that folder will now be created with your default (pg#######) group again. (When is this likely to happen?)
Option 4: Cron job
To effectively change your default group and make sure that anything new created is in that group, create a cron job that runs the setperms.sh script every hour or so.
Create your new group in the DreamHost Control Panel. Once your group has been created, SSH into your account and verify that you are a member of the group by typing
groups
and seeing if your new group is listed in the results.
Protect your webfolder appropriately
chmod 751 <webfolder>
Create the setperms.sh file in your home folder
setperms.sh
#!/bin/bash
LOCKFILE=$HOME"/.set-permissions.lock"
ABORT=0
NEEDSHELP=0
Usage()
{
echo "Usage: $0 -g <group> -p <group> -u <user>"
echo " -w <folder> [[-w <folder>] ...]"
echo " -g|--group <group> The group to chgroup your files to"
echo " -p|--primary <group> The group that files must have to be chgrouped"
echo " -u|--user <user> The user you are running as. The user must"
echo " be a member of both groups specified."
echo " -w|--web <folder> The foldername of your web directory that must be"
echo " world readable. You must specify at least one folder,"
echo " but may specify any number of folders to be"
echo " accessable from the web"
ABORT=1
}
ParseCommandLine()
{
echo "Parsing..."
# Parse the command line
if [ $# -eq 0 ]; then
NEEDSHELP=1
fi
i=0
while [ -n "$1" ]; do
case $1 in
"-g" | "--group")
[ -n "$2" ] || Usage
GROUP=$2
shift
;;
"-h" | "--help")
NEEDSHELP=1
shift
;;
"-p" | "--primary")
[ -n "$2" ] || Usage
PRIMARYGROUP=$2
shift
;;
"-u" | "--user")
[ -n "$2" ] || Usage
USERNAME=$2
shift
;;
"-w" | "--web")
[ -n "$2" ] || Usage
WEBFOLDER[$i]=$2
i=$i+1
shift
;;
*)
Usage;;
esac
shift
if [ $ABORT -eq 1 ]; then
return
fi
done
if [ ${NEEDSHELP} -lt 1 ]; then
if [ -z $GROUP ]; then
echo "You must specify a group (-g)"
NEEDSHELP=1
fi
if [ -z $PRIMARYGROUP ]; then
echo "You must specify a primary group (-p)"
NEEDSHELP=1
fi
if [ -z $USERNAME ]; then
echo "You must specify a user (-u)"
NEEDSHELP=1
fi
if [ -z $WEBFOLDER ]; then
echo "You must specify at least one webfolder (-w)"
NEEDSHELP=1
fi
fi
}
ValidateGroups()
{
echo "Validating group memberships"
# Check the primary group
groups ${USERNAME} | grep "${PRIMARYGROUP}" 2>&1 > /dev/null
if [ $? -gt 0 ]; then
echo "User ${USERNAME} is not a member of ${PRIMARYGROUP}"
ABORT=1
fi
# Check the target group
groups ${USERNAME} | grep "${GROUP}" 2>&1 > /dev/null
if [ $? -gt 0 ]; then
echo "User ${USERNAME} is not a member of ${PRIMARYGROUP}"
ABORT=1
fi
}
RunCommands()
{
# Deal with stuff in the webfolders first
for W in $WEBFOLDER
do
echo "Setting file permissions in web folder ${W}"
find ~/$W -xdev -user ${USERNAME} -group ${PRIMARYGROUP} -not -type d -print -exec chmod o+r,o-w {} \; -exec chgrp ${GROUP} {} \;
echo "Setting folder permissions in web folder ${W}"
find ~/$W -xdev -user ${USERNAME} -group ${PRIMARYGROUP} -type d -print -exec chmod o+x,o-wr {} \; -exec chgrp ${GROUP} {} \;
done
# Change anything in the primary group to the new group
echo "Setting group membership on items currently in group ${PRIMARYGROUP}"
find ~/ -xdev -user ${USERNAME} -group ${PRIMARYGROUP} -not -type l -not -print -exec chmod o-rwx {} \; -exec chgrp ${GROUP} {} \;
# Cleanup any messes we may have made
chmod o+x .
chmod u+x,g-wx,o-wx $0
for W in $WEBFOLDER
do
chmod o+x $W
done
}
Main()
{
# Make sure that we're the only instance of the script running
if [ -e $LOCKFILE ]
then
echo "Either another instance of this script is running or you need to remove the $LOCKFILE file"
exit 0
fi
touch $LOCKFILE
ParseCommandLine "$@"
if [ ${NEEDSHELP} -eq 0 ]; then
# All the parameters were there, now make sure they're valid
ValidateGroups
fi
if [ ${NEEDSHELP} -eq 0 ]; then
# Run the commands
echo "Running the commands"
RunCommands $0
elif [ ${ABORT} -lt 1 ]; then
Usage
fi
# Remove the temporary lockfile
rm $LOCKFILE
}
Main "$@"
Make sure that the file is in Unix mode (rather than DOS mode) so that weird things don't happen
dos2unix setperms.sh
Chmod the setperms.sh script so that you can execute it and no one else can
chmod 700 setperms.sh
Chgrp the setperms.sh script to something other than your default (pg#######) group
chgrp <newgroup> setperms.sh
Run the script for the first time to get everything set up properly and make sure it's working. This will probably take a long while to run the first time as it will touch just about, and will print out all of the files and folders that it is making changes to.
./setperms.sh -g <newgroup> -p <primary group, pg#######> -u <username> -w <webfolder>
For example
./setperms.sh -g fred -p pg1234567 -u fred -w fred.com
If you have multiple web folders, you can put additional -w <webfolder> statements on the end
Setup the cron job
crontab -e
Install the script to run every hour or so, and to dump all of the output to the garbage
0 * * * * /home/fred/setperms.sh -g fred -p pg1234567 -u fred -w fred.com >/dev/null 2>&1
If you want the results to be emailed to you every time the script runs:
MAILTO=<your@email.address> 0 * * * * /home/fred/setperms.sh -g fred -p pg1234567 -u fred -w fred.com
If you want the results to be emailed to you once a day:
MAILTO=<your@email.address> 0 * * * * /home/fred/setperms.sh -g fred -p pg1234567 -u fred -w fred.com >> /home/fred/setperms.log 2>&1 1 1 * * * cat /home/fred/setperms.log 2 1 * * * rm -rf /home/fred/setperms.log
Timings
I've run this in a few different sites, and the CPU time is not too bad, as long as it's not being run more than every 30-45 minutes. Sample timings:
#files | 743 | 1961 | 6709 | 19878 | 31302 | 31477 | -------|----------|----------|-----------|-----------|-----------|-----------| real | 0m2.600s | 0m6.427s | 0m48.321s | 1m48.668s | 4m39.025s | 4m41.896s | user | 0m0.050s | 0m0.120s | 0m0.090s | 0m0.170s | 0m0.460s | 0m0.570s | sys | 0m0.130s | 0m0.060s | 0m1.230s | 0m0.950s | 0m3.630s | 0m3.710s | -----------------------------------------------------------------------------/
This is for runs with no files/folders that needed changing. As the number of files/folders that have to be modified increases, so will the timings.
Details
This script traverses your entire structure looking for and doing the following things:
Order | Looking for | Action if found
------|---------------------------------------------------------------
1 | In each webfolder, a | Remove world write, add world
| file, your username, | read, make group the new group
| primary group (pg####), |
------|---------------------------------------------------------------
2 | In each webfolder, a | Remove world read and write, add
| folder, your username, | world execute, make group the
| primary group (pg####), | new group.
------|---------------------------------------------------------------
3 | From your home, a file | Remove world read, write, execute,
| or folder, your username, | world execute, make group the
| primary group (pg####), | new group.
------|---------------------------------------------------------------
4 | On your home folder | Add world execute
------|---------------------------------------------------------------
5 | On the script | Add owner execute, remove group
| | and world write and execute
------|---------------------------------------------------------------
6 | On each webfolder | Add world execute
------|---------------------------------------------------------------
Pros & Cons
Pros
- Anything that is created by your user from anywhere (ssh, sftp, ftp, etc.) is treated as "new" by the script and processed. Anything that has a group membership other than your primary (pg#######) group is treated as "old" and left alone. This means that you know that anything new you create will within the hour be assigned the correct group and permissions to be secure, but that if you want one particular item (file or folder) to have a non-default group or permissions it won't be messed with.
- Doesn't care what your umask is set at, it sets the permissions to properly protect the private files and properly serve the web-accessable ones.
Cons
- This script has 3 find commands in it, two of which are executed once for each web folder that you have. If you've got lots of web folders, this could potentially add up and might not be a viable way to go.
- The initial run takes quite a long time, even with under 800 files it still took close to a minute.
- Ignores your umask. (Well, it fits on both sides, what do you want?)
- Requires shell access for each account

