fixing shared group permissions for sftp

Here's a really common scenario I've encountered in my days of server-ing: shared folders. The story goes like this: "we set up a shared folder, but when one person uploads a file, then no one else can write to or delete it. Even worse, the web server can't read/write to files that have been changed."

Hearing this problem description, I nod along to the familiar symptoms, and then reply, "yep, I've seen this happen dozens of times, what you need is to set the setgid bit," which usually results in puzzled looks. "setgid bit?!"

Here are the ways that I've tried (and seen others try) that DO NOT solve this problem:

  1. Change the group permissions with chgrp -R sharedgroup /path/to/dir. This breaks the second someone uploads a new file or creates a directory.
  2. Set a cron job to fix the user/group permissions. Set it to run every minute. This sorta works, but it's hacky as hell. Your team will see random permission failures. Hope it's not too important to track who changed which file, because your cron job blows away that information!
  3. Let everyone log in as the web server user. This works, but then people have access to all the files the web server has — and the ability to screw them up. And, sharing a user account/password among multiple people is a recipe for disaster.

What we want is this:

  1. Ensure all of the files in the directory (and its subdirectories) are readable & writable by group members.
  2. If someone creates a new file, it must be owned by the group, and the group must be allowed to read & write to the file.
  3. Same goes for new directories: they must be owned and writable by the group.

The answer is actually straightforward: set the "setgid" or "set group ID" permission bit on your shared directory.

It looks like this:

chgrp webteam -R /path/to/share
find /path/to/share -type d -exec chmod g+rwxs '{}' \;

If you're not familiar with standard Unix file permissions, I wrote a bite-sized guide to Unix file permissions, so check that out.

Let's break this down. The first command makes all files & directories owned by the webteam group:

chgrp webteam -R /path/to/share

Standard stuff. Here's the tricky part: we want to set the "setgid" bit only on directories. It has a totally different meaning on files and can cause security problems. So, time to reach for our trusty "find" command, commented below:

find /path/to/share  \         # Look under find /path/to/share 
-type d              \         # Find directories
-exec chmod g+rwxs '{}' ';'    # Run this command on all directories found.

If you haven't seen that find invocation before, just imagine that {} is a "hole" in the chmod command that gets filled in with each matched directory.

This ensures that everyone in the group can read & write (and delete) all directories under the shared directory. The magic is in the g+s or "group setgid" permission. Setting this on a directory ensures that any new files or directories created under it will inherit the parent directory's group ownership AND permissions. This is exactly what we want.