I first installed linux some 15 years ago. Back then [leans back, scratches beard thoughtfully] a new user would be assigned the primary group
users. At some point I did not quite catch, this convention changed and new users got given their own, unique primary group named the same as the user. This seemed dumb to me: If user and group were the same, what was the point of having a group in the first place? I suspect I have been reverting this default on quite a number of machines since.
Today I learned that this newfangled idea is called private user groups, is at least 20 years old, and originated with Red Hat from where it presumably spread to Debian/Ubuntu sometime after I had installed my first distro. And that it has some interesting uses when you want to share files between different users on your system.
Before going any further I need to point out that what I am about to talk about has been picked up from a 20 year old book on Samba. So it goes without saying that these ideas may very well have been discredited for the past 19 years. I will probably find out in another 20 or so years. Also the book in question mentioned this as an already then somewhat oldfashioned file sharing and collaboration arrangement, compared to what Samba was offering! I suppose that in this age of cloud computing it is positively antiquated.
The short version is this: On a server I run scripts such as podcast clients that manage files: download, delete, rename etc. I want my primary user to have access to the files but I do not want the script to run as my primary user. The reason being that I do not entirely trust it because, well, I wrote it myself and so I know that it could very well turn on me and starting deleting files it shouldn’t. Or a malicious person could take control because I failed to sanitize files names or some such.
My solution to this sort of thing has always been to create a
nobody user and add them to
users, same as my primary user. At least this would give me the ability to read the files created by
nobody, and switch into
root should I need write access. The main problem with this is that it gives nobody read access files in my home directory, assuming umask 022 (user has read and write, group and others only read). The lack of write permissions for my primary user is also not ideal. All in all, it’s messy.
Private user groups in combination with a restrictive umask, say 006, solve the main problem: Now, nobody but my main user (and, hypothetically, someone who gets to join my private user group) can see that user’s files. I can also add my main user to nobody’s primary group and set their umask to 006 so I get read and write access. Changing the umask of a system user – or a user that does not log in – is tricky, however, so that may not be foolproof.
So here is another way of doing it. The first thing to do is to create a group that is shared between my primary user and the other user, a
project group. Then I chown the project directory to this group and set the special permissions on it to 2, like so
chown me:project /project/directory chmod 2770 /project/directory
(I‘m assuming the directory is new and empty so no need for recursive flags)
Setting group, i.e. 2 in the special permissions, means that all files added to the directory will not be assigned to the user‘s primary group but to the
project group. Since group members have all permissions (7) I can read and write to all the files that the script user has added – and vice versa. In this egalitarian setup ownership of a file in the directory, i.e. what user the file has attached, is irrelevant. Both of these users have unrestricted access to read, write, rename, delete etc.
Adding the sticky bit to the special permissions mixes it up a bit and removes the egalitarianism from the equation. Both set group and sticky bit count as special permissions. Set group is the value 2 in the special permissions, the sticky bit is 1, together they would be the value 3 (or 011 in binary).
chmod 3770 and all files created in the directory still follow the ‘set group‘ rule, i.e. they inherit the directory‘s group rather than the user‘s primary group. However as the main directory‘s owner my main user is now more equal than others: He still has the right to delete and rename files owned by other members of the group in the project directory but not vice versa (though it seems they retain the right to write to/add to the files in question). This kind of thing seems to be more relevant to actual, real life users collaborating than system users acting on files that I use too, though. If I really mistrust the process so much that I suspect it might delete or rename files that I have added and should be sacrosanct, maybe it‘s time to review my code or my choice of application.
As mentioned above umasks are tricky to get right for nonlogin users. Maybe the program has a setting, maybe the init that starts the daemon does. This is where
setfacl comes in. I‘m not quite sure how it works but the net effect is that on a per-directory basis I can decide what permissions a new file is created with. Like a per-directory umask, though I get the sense that that is a misrepresentation. At any rate
setfacl -d -m group:project:rwx /project/directory
The net result is to make files created in /project/directory have read and write permissions for both user and group and none for others, regardless of umask. There is obviously some subtle interplay with other settings here but I cannot say for certain how it plays out. The setfacl permissions are exhaustive – so since others aren‘t explicitly given permissions, none are granted – but cannot take away the user‘s rights? And the linux standard of never birthing files with execute permissions takes preeminence over all? I‘m guessing and speculating here, I‘m sorry to say.
I do find the end picture quite attractive, even if I don‘t entirely understand every piece of the puzzle. A folder that I can share with a daemon without any issues about ownership or rights – and without risking the integrity of my private files, or even having to compromise on umask settings.