Unix Groups

From DreamHost
Jump to: navigation, search
The instructions provided in this article or section are considered advanced.

You are expected to be knowledgeable in the UNIX shell.
Support for these instructions is not available from DreamHost tech support.
Server changes may cause this to break. Be prepared to troubleshoot this yourself if this happens.
We seriously aren't kidding about this.

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.
Your account must be configured for shell access in the Control Panel.
More information may be available on the article's talk page.


Unix groups are used for sharing files between users. Only users with Enhanced User Security disabled can have their user group changed.

UNIX Groups & FTP users

Here's how to use UNIX groups to give individual FTP users access to specific subdirectories of a website.

1) Go to the Dreamhost Web panel, Users --> Manage Users. Create a user with shell access (example: "webmaster")

2) Go to Domains --> Manage Domains and assign the domain to the "webmaster" user (example: "mydomain.com"). Create directories and subdirectories.

3) Go to Users --> Manage Users and create another user with shell access (example: "contributor")

4) Go to Users --> UNIX Groups and create a group with both users in it (example: "contributor_group"). Every new FTP user will get his or her own UNIX group (contributer02_group, contributer03_group, etc.). Ideally, the "webmaster" user should belong to all these groups, but on some DreamHost servers users can't belong to more than 16 groups, apparently.

5) SSH to the server as "webmaster". Give the "contributor_group" access to whichever directory you want the user "contributor" to build (example: "contributor_directory") with this command: chgrp contributor_group contributor_directory

  • To give access to contributor_directory and all of its subdirectories and files, use this command: chgrp -R contributor_group contributor_directory

6) While still logged in as "webmaster", give the group (and all users in it) the desired level of access for that directory.

  • To provide full read/write/execute access, use this command: chmod g+rwxs contributor_directory
  • To provide full read/write/execute access to contributor_directory and all of its subdirectories and files, use this command: chmod -R g+rwxs contributor_directory

7) Exit the session and log back in as "contributor." Make a symbolic link (aka a shortcut) to the directory with this command: ln -s /home/webmaster/mydomain.com/contributor_directory /home/contributor/

This will create a symbolic link called "contributor_directory" in "contributor's" home directory. To upload or download files, "contributor" will have to use SFTP, because FTP will not work with symbolic links.

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.

Super double caveat: Some of our file servers have an internal limit of 16 groups. If you are in more than 16 groups, only the first 16 (as listed by the "groups" command) will be considered.

DreamHost Security Settings

Fundamentals

Unix Groups:

  1. Every DreamHost shared hosting account has a Unix Group of the form pg####### (where each # is a [0-9] digit):
    1. This group is called "a default group" and there seemingly is exactly 1 per account, so it could be called the default group for the account
    2. Every User and every (Mailbox --found here) belonging to the account is a member of this group and nobody else is (so don't worry that your files & folders will be shared outside of your account because you see they belong to this group: they won't!).
      • Note (in this default group) the first User (aka primary account holder) appears to be listed once for every computer/server on which the account was hosted (which will be more than one computer in the case of Server Moves).
    3. Each Unix User's default Unix Group is entirely determined by the User's Enhanced User Security check-box option (set in Editing Unix User ):
      • if Enhanced User Security is NOT selected (the default), this default pg####### group is the user's default group (probably explaining its name "default group")
      • if Enhanced User Security IS selected (not the default), the "user's home directory has its permissions set to 750 and its group is changed to adm" as Enhanced User Security details.
    4. None of the above can be changed (except Enhanced User Security per User).
  2. Any number of additional Unix Group can be added/deleted (by that link);
  3. Every Unix Group of an account can contain any subset (combination) of Unix Users which belong to that same DreamHost account.
  4. Unix Groups seemingly cannot be nested.
  5. The only users (including Users) and Unix Group visible/accessible to the account are those created by the account.

Unix Permissions:

  1. Default Permissions (for user+group+other) for each user,
    1. The default values are detailed in Enhanced User Security for this option and seeming for without it, too.
    2. However the user can seemingly override these defaults by say putting a "umask" command in the user's ~/.bashrc .
  2. Permissions for each user's home directory within the account:
    1. As far as "other/world" (everyone besides the account's users & groups) getting to your files & folders, such as other DreamHost account/customers or the general public since it's on the Internet. At least by looking at my home directory which should be using default settings (but check your own to confirm):
      1. Home directory is NOT readable by "other/world" so even if their files & folders are readable by "other" these home folders won't be browse-able to anyone other than potentially users of your account.
      2. However, home directory IS executable by "other/world" so it would seem if "other" had the path to a file or folder which had permissions saying "other" could access it, "other" could get to it. Such access might be disallowed by other mechanisms, but it could be desirable for when you do want sharing (and also know the path in the other home directory); just know that if "other/world" IS given access on a file or folder within the account, then that access might be possible by other DreamHost customers (and so in theory the world) if the particular path was known else guessed.

Consequences

...of the above fundamentals are many. Some are:

  1. When you add a user, it is automatically added to your default pg###### group.
  2. By default, every user's files & folders belong to the pg###### or adm group unless changed by a member of that group, so by default (no Enhanced User Security) 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.
  3. Common Issue If you have enabled "extra security" for the domain in the control panel (--Edit Domain's Mod security? Or do you mean User's Enhanced User Security?) then this will not allow other group members to view or access the files. Make sure to have this option turned off if you plan share files with other group users.
  4. No other Unix Group can be set as the User's default group (as it must be pg####### or adm) so the user needs to do a chgrp on every file & folder she creates when such is needed.
  5. “The only users (including Users) and Unix Group visible/accessible to the account are those created by the account.” is a notable (questionable?) restriction. Consequently:
    1. You can't share data (via this facility) with other DreamHost accounts/customers (without you having to give each yet-another username & password or vice versa).
    2. You could not say create a group containing say your users plus dhapache (the DreamHost Apache web server) say to solve problems problem with Subversion "dhapache" permission problems after the user understandably further (directly) edits the control panel's initial basic settings.

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 -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


If a symbolic link is created, an SFTP user will also be able to access shared sub-directories/files through an FTP client.


See also Sharing Domain Files with Multiple Users