139

I am having a problem with permissions on a Linux server. I am used to BSD. When a directory is owned by a group the user who owns it isn't in such as www-data, files created in it will be owned by that group. This is important because I want files to be readable by the webserver (which I will not run as root) but so a user can still put new files in the directory. I can't put the users in www-data because then they can read every other users websites.

I want the webserver to read all websites, I want users to be able to change their own.

The permissions are set like this on the folders at the moment....

drwxr-x--- 3 john www-data 4096 Feb 17 21:27 john

It is standard behavior on BSD for permissions to work this way. How do I get Linux to do this?

John Tate
  • 1,960

3 Answers3

186

It sounds like you're describing the setgid bit functionality where when a directory that has it set, will force any new files created within it to have their group set to the same group that's set on the parent directory.

Example

$ whoami
saml

$ groups
saml wheel wireshark

setup a directory with perms + ownerships

$ sudo mkdir --mode=u+rwx,g+rs,g-w,o-rwx somedir
$ sudo chown saml.apache somedir
$ ll -d somedir/
drwxr-s---. 2 saml apache 4096 Feb 17 20:10 somedir/

touch a file as saml in this dir

$ whoami
saml

$ touch somedir/afile
$ ll somedir/afile 
-rw-rw-r--. 1 saml apache 0 Feb 17 20:11 somedir/afile

This will give you approximately what it sounds like you want. If you truly want exactly what you've described though, I think you'll need to resort to Access Control Lists functionality to get that (ACLs).

ACLs

If you want to get a bit more control over the permissions on the files that get created under the directory, somedir, you can add the following ACL rule to set the default permissions like so.

before

$ ll -d somedir
drwxr-s---. 2 saml apache 4096 Feb 17 20:46 somedir

set permissions

$ sudo setfacl -Rdm g:apache:rx somedir
$ ll -d somedir/
drwxr-s---+ 2 saml apache 4096 Feb 17 20:46 somedir/

Notice the + at the end, that means this directory has ACLs applied to it.

$ getfacl somedir
# file: somedir
# owner: saml
# group: apache
# flags: -s-
user::rwx
group::r-x
other::---
default:user::rwx
default:group::r-x
default:group:apache:r-x
default:mask::r-x
default:other::---

after

$ touch somedir/afile
$ ll somedir/afile 
-rw-r-----+ 1 saml apache 0 Feb 17 21:27 somedir/afile
$ 

$ getfacl somedir/afile
# file: somedir/afile
# owner: saml
# group: apache
user::rw-
group::r-x              #effective:r--
group:apache:r-x        #effective:r--
mask::r--
other::---

Notice with the default permissions (setfacl -Rdm) set so that the permissions are (r-x) by default (g:apache:rx). This forces any new files to only have their r bit enabled.

slm
  • 369,824
  • 1
    That seems to provide the functionality I wanted, thanks. – John Tate Feb 18 '14 at 01:46
  • This seems to solve my similar problem, too. However, I don't quite understand the last sentence: "This forces any new files to only have their r bit enabled." Why is the x permission not enabled? Is there a way to enable it by default?? – yaobin Apr 06 '16 at 18:20
  • 1
    @yaobin I think it's a security thing, you don't really want to have a file executable by default – cdarken Nov 08 '16 at 11:30
  • 1
    This doesn't work with unzip? – datasn.io Mar 06 '19 at 02:07
  • 1
    @datasn.io - look at the man page of unzip. Specifically the -X switch. – slm Mar 06 '19 at 03:17
  • 1
    is that a typo in the chown command in the first example: sudo chown saml.apache somedir or is the period equivalent to : in this case (the man page doesn't say it is)? – RufusVS Jul 29 '19 at 22:27
  • @RufusVS - it's equivalent, you can use either. – slm Jul 30 '19 at 03:56
  • In the first, plain, setgid example, how does somedir/afile end up with group writeable set? setgid should only controls group, right, not permissions? Is this just a typo here, or is there a way to make that happen that I am missing? – Don't Panic Jun 05 '21 at 12:07
  • 1
    @Don'tPanic - def. not a typo. Forgive me but I haven't looked at this A'er in a very long time. I suspect that set of permissions on the touch somedir/afile was set via my system's umask. - https://www.liquidweb.com/kb/what-is-umask-and-how-to-use-it-effectively/#:~:text=Umask%2C%20or%20the%20user%20file,set%20for%20newly%20created%20files.. Back in 2014 I'm pretty sure I was rolling w/ a umask 002 on my system. – slm Jun 05 '21 at 13:37
90

TL:DR; to make new files inherit the group of the container folder do:

$ chmod g+s somefolder

Note: its implied in the accepted answer, this is just a snippet.

alo Malbarez
  • 1,003
  • 6
    setgid means that new files and folders will have the right group, but remember that if you move files into the tree, they won’t have the right owner configured. The ACL approach copes with that (in general). – Chris Morgan May 29 '18 at 11:23
  • 1
    @ChrisMorgan how does it cope with it? The solutions from the accepted answer didn't do anything for moved files in my case. – Dan M. Apr 03 '19 at 11:00
  • 1
    @DanM.: with file modes, you set permissions that are not inherited; but with ACLs, you set permissions that are inherited (though the children can specify ACLs of their own that override that), being checked at runtime. – Chris Morgan Apr 07 '19 at 14:18
  • @ChrisMorgan yes. How do you do that? Solution using ACL form accepted answer doesn't work. – Dan M. Apr 08 '19 at 13:06
  • 3
    I had to add -R for the setting to propagate down the directory tree – isapir Dec 08 '19 at 00:31
  • @isapir that would only work for files or dirs created (or copied) down the dir tree but not for those moved there, or unzipped, etc. At that point you need to run again chmod -R g+s basedir/, meaning you did not achieve automatic group inheritance. – red-o-alf Feb 12 '24 at 05:08
  • @red-o-alf Is there a way to achieve inheritance for the use cases you described? – isapir Feb 16 '24 at 17:03
  • 1
    @isapir no, from what I read the closest you can get is using a filesystem monitoring utility like inotify which can automatically fire a bash script on a certain filesystem events (for example: newFileInDir? > chmod -R g+s *, and with some logic you could make it efficient enough... But anyway! Make sure the approach you're following is 100% necessary... For example, in my case I was trying to clone python environments (within a setgid dir) with the conda --clone cmd. But then I decided I'd be better off manually generating the envs myself, so setgid would work again as expected. – red-o-alf Feb 24 '24 at 15:25
17

As a complement to slm's answer, note that, on an ext2/3/4 filesystem, you can replicate the BSD behavior you describe by using the bsdgroups mount option on the partition. From the mount(1) man page :

grpid|bsdgroups and nogrpid|sysvgroups
              These options define what group id a newly  created  file  gets.
              When  grpid  is  set,  it takes the group id of the directory in
              which it is created; otherwise (the default) it takes the  fsgid
              of  the current process, unless the directory has the setgid bit
              set, in which case it takes the gid from the  parent  directory,
              and also gets the setgid bit set if it is a directory itself.
user60039
  • 706