The easiest way to manage this is with access control lists. They allow permissions to be set for as many users and groups as you want, not just one user and one group like the basic unix permissions.
ACLs need to be enabled on the filesystem. With ext[234] or reiserfs, you need to pass the acl
mount option. Also make sure you have the ACL utilities installed (acl
package on Debian or Ubuntu).
Set an ACL that allows both users to access the files, and set a matching default ACL on directories (the default ACL is inherited by files created in the directory).
setfacl -m user:www-data:rwx -m user:svnuser:rwx -R /path/to/directory/tree
setfacl-d -m user:www-data:rwx -m user:svnuser:rwx -R /path/to/directory/tree
You can set different permissions if you like. The executable bit will be ignored if the file is not made executable through the non-ACL permissions (the ones you set with chmod
).
The commands given are for Linux. Many other unix variants support ACLs, but the exact set of available permissions and the utility to set them are not standardized.
You can use groups to control access if you want. Even if you do, ACL have the advantage that you won't run into a umask issue: if you just create a group, you have to ensure that all files and directories are group-writable, which means you have to make sure any process creating a file has a umask of 002 or 007, which in turn may cause permissions elsewhere to be more liberal. So even if you create a group, ACLs are useful.
setfacl -m group:mygroup:rwx -R /path/to/directory/tree
setfacl -d -m group:mygroup:rwx -R /path/to/directory/tree
Note that I make no warranty as to the suitability of this security model to your use case. I'm just providing an implementation.
I’ll answer your questions in three parts: file types, permissions, and use cases for the various forms of chmod
.
File types
The first character in ls -l
output represents the file type; d
means it’s a directory. It can’t be set or unset, it depends on how the file was created. You can find the complete list of file types in the ls documentation; those you’re likely to come across are
-
: “regular” file, created with any program which can write a file
b
: block special file, typically disk or partition devices, can be created with mknod
c
: character special file, can also be created with mknod
(see /dev
for examples)
d
: directory, can be created with mkdir
l
: symbolic link, can be created with ln -s
p
: named pipe, can be created with mkfifo
s
: socket, can be created with nc -U
D
: door, created by some server processes on Solaris/openindiana.
Permissions
chmod 0777
is used to set all the permissions in one chmod
execution, rather than combining changes with u+
etc. Each of the four digits is an octal value representing a set of permissions:
suid
, sgid
and “sticky” (see below)
- user permissions
- group permissions
- “other” permissions
The octal value is calculated as the sum of the permissions:
- “read” is 4
- “write” is 2
- “execute” is 1
For the first digit:
suid
is 4; binaries with this bit set run as their owner user (commonly root
)
sgid
is 2; binaries with this bit set run as their owner group (this was used for games so high scores could be shared, but it’s often a security risk when combined with vulnerabilities in the games), and files created in directories with this bit set belong to the directory’s owner group by default (this is handy for creating shared folders)
- “sticky” (or “restricted deletion”) is 1; files in directories with this bit set can only be deleted by their owner, the directory’s owner, or
root
(see /tmp
for a common example of this).
See the chmod
manpage for details. Note that in all this I’m ignoring other security features which can alter users’ permissions on files (SELinux, file ACLs...).
Special bits are handled differently depending on the type of file (regular file or directory) and the underlying system. (This is mentioned in the chmod
manpage.) On the system I used to test this (with coreutils
8.23 on an ext4
filesystem, running Linux kernel 3.16.7-ckt2), the behaviour is as follows. For a file, the special bits are always cleared unless explicitly set, so chmod 0777
is equivalent to chmod 777
, and both commands clear the special bits and give everyone full permissions on the file. For a directory, the special bits are never fully cleared using the four-digit numeric form, so in effect chmod 0777
is also equivalent to chmod 777
but it’s misleading since some of the special bits will remain as-is. (A previous version of this answer got this wrong.) To clear special bits on directories you need to use u-s
, g-s
and/or o-t
explicitly or specify a negative numeric value, so chmod -7000
will clear all the special bits on a directory.
In ls -l
output, suid
, sgid
and “sticky” appear in place of the x
entry: suid
is s
or S
instead of the user’s x
, sgid
is s
or S
instead of the group’s x
, and “sticky” is t
or T
instead of others’ x
. A lower-case letter indicates that both the special bit and the executable bit are set; an upper-case letter indicates that only the special bit is set.
The various forms of chmod
Because of the behaviour described above, using the full four digits in chmod
can be confusing (at least it turns out I was confused). It’s useful when you want to set special bits as well as permission bits; otherwise the bits are cleared if you’re manipulating a file, preserved if you’re manipulating a directory. So chmod 2750
ensures you’ll get at least sgid
and exactly u=rwx,g=rx,o=
; but chmod 0750
won’t necessarily clear the special bits.
Using numeric modes instead of text commands ([ugo][=+-][rwxXst]
) is probably more a case of habit and the aim of the command. Once you’re used to using numeric modes, it’s often easier to just specify the full mode that way; and it’s useful to be able to think of permissions using numeric modes, since many other commands can use them (install
, mknod
...).
Some text variants can come in handy: if you simply want to ensure a file can be executed by anyone, chmod a+x
will do that, regardless of what the other permissions are. Likewise, +X
adds the execute permission only if one of the execute permissions is already set or the file is a directory; this can be handy for restoring permissions globally without having to special-case files v. directories. Thus, chmod -R ug=rX,u+w,o=
is equivalent to applying chmod -R 750
to all directories and executable files and chmod -R 640
to all other files.
Best Answer
This is an extremely common problem, if I understand it accurately, and I encounter it constantly. If I used ACLs for every trivial grouping problem, I would have tons of unmanageable systems. They are using the best practice when you cannot do it any other way, not for this situation. This is the method I very strongly recommend.
First you need to set your umask to 002, this is so a group can share with itself. I usually create a file like
/etc/profile.d/firm.sh
, and then add a test command with the umask.[ $UID -gt 10000 ] && umask 002
Next you need to set the directories to their respective groups,
Finally you need to set the SGID bit properly, so the group will always stay to the one you set. This will prevent a written file from being set to the writer's GID.
Now finally if you want to prevent the directories from being accessed by other users.