Linux FilesystemLesson 8 of 8
Capstone: a shared project area
Combine ownership, permissions, setgid, sticky bits, usage reports and cleanup to build and audit a shared directory the way an administrator would.
useraddusermodgetenttarfindduuserdel
After this lesson you can
- Turn a written requirement into an owner, group and mode.
- Build a team directory where new files inherit the group and members cannot delete each other's files.
- Test permissions from each user's point of view.
- Report usage per user, archive and prune old files, and audit for policy violations.
The brief
A web team of two needs a shared directory. This is how the request would arrive:
Create
/srv/projects/web. Alice and Bob must both be able to add and edit files. Everything they create should belong to their team group. Nobody outside the team should see it. Bob must not be able to delete Alice’s files, or the other way round.
Administration is mostly this: turn a plain request into settings you can check. The skills from the previous seven lessons are all in it.
Step 1: requirements to settings
Take each sentence and find the setting that enforces it.
| Requirement | Setting |
|---|---|
| Alice and Bob add and edit files | A group webteam with both as members; group has rwx on the directory |
| New files belong to the team group | setgid on the directory (2) |
| Nobody outside the team sees it | Others have --- |
| Members cannot delete each other’s files | sticky bit on the directory (1) |
| Owner of the directory | root, so members cannot loosen the rules themselves |
Assemble the mode. Special bits 2 and 1 add to 3; the user and group get 7; others get 0:
3 7 7 0 → 3770 → drwxrws--T
The capital T means sticky is set but others have no execute, which is what we want. A lowercase t would mean others can enter.
Step 2: group and users
sudo groupadd webteam
sudo useradd -m -s /bin/bash -G webteam alice
sudo useradd -m -s /bin/bash -G webteam bob
sudo useradd -m -s /bin/bash carol
-m creates a home directory, -s sets the login shell and -G adds supplementary groups. carol is deliberately outside the team so you can test the boundary. Check:
id alice
getent group webteam
uid=1001(alice) gid=1003(alice) groups=1003(alice),1002(webteam)
webteam:x:1002:alice,bob
Step 3: the directory
sudo mkdir -p /srv/projects/web
sudo chown root:webteam /srv/projects/web
sudo chmod 3770 /srv/projects/web
ls -ld /srv/projects/web
drwxrws--T 2 root webteam 4096 Nov 3 11:05 /srv/projects/web
Owner root, group webteam, mode drwxrws--T. /srv/projects was created by mkdir -p with the default mode so that users can reach web through it. Always check that every parent directory on the path has x for the people who need it.
Step 4: prove it, as each user
A permission setup is not finished until you have tried it from every side. su - USER -c 'COMMAND' starts a fresh login for that user, so the groups and umask are the real ones.
Alice creates a file:
sudo su - alice -c 'echo "<h1>hi</h1>" > /srv/projects/web/index.html; mkdir /srv/projects/web/css; ls -l /srv/projects/web'
total 8
drwxrwsr-x 2 alice webteam 4096 Nov 3 11:08 css
-rw-rw-r-- 1 alice webteam 12 Nov 3 11:08 index.html
The group is webteam, not alice: that is setgid at work. The file is group-writable because the login umask is 002. The new css directory inherited setgid too (s in the group position), so the rule carries down the tree.
Bob edits Alice’s file, then tries to delete it:
sudo su - bob -c 'echo "<p>bob</p>" >> /srv/projects/web/index.html && echo append ok'
sudo su - bob -c 'rm /srv/projects/web/index.html'
append ok
rm: cannot remove '/srv/projects/web/index.html': Operation not permitted
Editing works because of the group write bit. Deleting fails because of the sticky bit, even though Bob has write access to the directory. Without it, w on a directory would let him remove anything inside.
Carol, outside the team:
sudo su - carol -c 'ls /srv/projects/web; cat /srv/projects/web/index.html'
ls: cannot open directory '/srv/projects/web': Permission denied
cat: /srv/projects/web/index.html: Permission denied
All four rules are now verified, not assumed.
Step 5: who is using the space?
Counting files per owner shows who is filling a shared area:
sudo su - alice -c 'touch /srv/projects/web/a1 /srv/projects/web/a2'
sudo su - bob -c 'touch /srv/projects/web/b1'
sudo find /srv/projects/web -type f -printf '%u\n' | sort | uniq -c
3 alice
1 bob
-printf '%u\n' prints the owner of each match, sort groups equal names together, and uniq -c counts runs. For sizes rather than counts:
sudo find /srv/projects/web -user alice -type f -exec du -ch {} + | tail -1
sudo du -sh /srv/projects/web
12K total
16K /srv/projects/web
Step 6: archive, then prune
Cleaning up is where data gets lost. The safe order is always: list, archive, verify, delete.
Backdate two files to simulate old data:
sudo touch -d '45 days ago' /srv/projects/web/old1.log /srv/projects/web/old2.log
- List what would be removed.
-mtime +30matches files last modified more than 30 days ago:
sudo find /srv/projects/web -type f -mtime +30
/srv/projects/web/old2.log
/srv/projects/web/old1.log
- Archive exactly those files:
sudo tar -czf ~/lab/web-old.tar.gz -C /srv/projects/web $(sudo find /srv/projects/web -type f -mtime +30 -printf '%P\n')
c creates, z compresses, f names the archive. -C makes tar change into the directory first, so the archive stores short names, and -printf '%P\n' prints each match relative to the directory being searched.
- Verify the archive.
tlists:
tar -tzf ~/lab/web-old.tar.gz
old2.log
old1.log
- Delete with the same selection:
sudo find /srv/projects/web -type f -mtime +30 -delete
sudo ls -l /srv/projects/web
total 12
-rw-rw-r-- 1 alice webteam 0 Nov 3 11:12 a1
-rw-rw-r-- 1 alice webteam 0 Nov 3 11:12 a2
-rw-rw-r-- 1 bob webteam 0 Nov 3 11:12 b1
drwxrwsr-x 2 alice webteam 4096 Nov 3 11:08 css
-rw-rw-r-- 1 alice webteam 23 Nov 3 11:09 index.html
Keeping the selection identical between the listing, the archive and the deletion is the point. Run the same find with -delete replaced by -print first, every time.
Step 7: audit
Months later, someone will have changed something. A few find expressions find the usual drift:
| Problem | Command |
|---|---|
| Anything writable by everyone | find /srv/projects -perm -o+w -not -type l |
| Files in the wrong group | find /srv/projects/web -not -group webteam |
| setuid or setgid files | find /srv/projects -type f -perm /6000 |
| Files whose owner was deleted | find /srv/projects -nouser -o -nogroup |
Plant a mistake and catch it:
sudo chmod o+w /srv/projects/web/index.html
sudo find /srv/projects -perm -o+w -not -type l
/srv/projects/web/index.html
Repair it, and run the audit again to confirm it prints nothing:
sudo chmod o-w /srv/projects/web/index.html
sudo find /srv/projects -perm -o+w -not -type l
Silence from an audit command is the pass condition. For a recurring job, put these commands in a script and run it from cron or a systemd timer, and mail yourself anything it prints.
Step 8: tear it down
Remove everything you created, in the reverse order:
sudo rm -r /srv/projects
sudo userdel -r alice
sudo userdel -r bob
sudo userdel -r carol
sudo groupdel webteam
userdel -r removes the home directory too. Confirm that nothing is left:
getent group webteam
ls /srv
The routine
The same sequence solves most filesystem requests:
- Write down who needs what, in plain words.
- Pick owner, group and mode for each sentence, and check parents are enterable.
- Create it. Prefer
rootas owner of shared areas. - Test as each kind of user, including one who should be refused.
- Measure:
df,du,find. - Keep an audit that prints nothing when all is well.
Practice
0 of 6 done
Do these on your own system. They get harder. Check each result, then tick it off.
- Warm-up
From requirement to mode
Without any users or
sudo, write the mode for a directory that satisfies all four rules, apply it to~/lab/spec, and show it.- The owner and the group may read, write and enter it.
- Others get no access.
- Files created inside belong to the directory's group.
- Only a file's owner can delete or rename it.
Check your result
ls -ld ~/lab/specdrwxrws--T 2 alex alex 4096 Nov 3 11:02 /home/alex/lab/specHint
Four digits: special bits, then user, group, others. Setgid is 2 and sticky is 1.
Solution
mkdir -p ~/lab/spec chmod 3770 ~/lab/spec ls -ld ~/lab/spec - Practice
Create the group, users and directory
On a disposable machine or container, create the group
webteam, the usersaliceandbobas members, andcarolwho is not a member. Create/srv/projects/webowned byroot:webteamwith the mode from the previous exercise. Show the group's members and the directory's listing.Check your result
getent group webteam ls -ld /srv/projects/webwebteam:x:1001:alice,bob drwxrws--T 2 root webteam 4096 Nov 3 11:05 /srv/projects/webHint
useradd -m -G GROUP USERcreates a user with a home directory and puts them in a supplementary group.Solution
sudo groupadd webteam sudo useradd -m -s /bin/bash -G webteam alice sudo useradd -m -s /bin/bash -G webteam bob sudo useradd -m -s /bin/bash carol sudo mkdir -p /srv/projects/web sudo chown root:webteam /srv/projects/web sudo chmod 3770 /srv/projects/web - Practice
Test it as each user
Show with real commands, run as each user, that:
alicecan create a file and its group iswebteam;bobcan append to it;bobcannot delete it;carolcannot list the directory or read the file.Check your result
alice's file is-rw-rw-r-- alice webteam.bob's append succeeds.bob'srmfails withOperation not permitted(the sticky bit).carolgetsPermission deniedon both the listing and the read.Hint
sudo su - USER -c 'COMMAND'runs a command as that user with a fresh login, including the right groups and umask.Solution
sudo su - alice -c 'echo "<h1>hi</h1>" > /srv/projects/web/index.html; ls -l /srv/projects/web' sudo su - bob -c 'echo "<p>bob</p>" >> /srv/projects/web/index.html && echo append ok' sudo su - bob -c 'rm /srv/projects/web/index.html' sudo su - carol -c 'ls /srv/projects/web; cat /srv/projects/web/index.html' - Practice
Report usage per user
Have
alicecreate two more small files andbobone. Print how many files each user owns in/srv/projects/web, and the total disk usage of the directory.Check your result
3 alice 1 bobfollowed by a size line such as
16K /srv/projects/web.Hint
find -type f -printf '%u\n'prints each file's owner. Count repeated lines withsort | uniq -c.Solution
sudo su - alice -c 'touch /srv/projects/web/a1 /srv/projects/web/a2' sudo su - bob -c 'touch /srv/projects/web/b1' sudo find /srv/projects/web -type f -printf '%u\n' | sort | uniq -c sudo du -sh /srv/projects/web - Challenge
Archive, check, then delete
Create two files in the area dated 45 days ago (
old1.log,old2.log). Safely remove everything older than 30 days in this order: list what matches, write it to a compressed archive in~/lab/web-old.tar.gz, list the archive to prove it contains exactly those files, and only then delete them from the area. Everything newer must stay.Check your result
The archive lists
old1.logandold2.logand nothing else. Afterwardsfind /srv/projects/web -type f -mtime +30prints nothing andindex.htmlis still there.Hint
touch -d '45 days ago'backdates a file.find -mtime +30matches files modified more than 30 days ago.tar -czf ARCHIVE -C DIR FILES...writes an archive,tar -tzflists one.Solution
sudo touch -d '45 days ago' /srv/projects/web/old1.log /srv/projects/web/old2.log sudo find /srv/projects/web -type f -mtime +30 sudo tar -czf ~/lab/web-old.tar.gz -C /srv/projects/web $(sudo find /srv/projects/web -type f -mtime +30 -printf '%P\n') tar -tzf ~/lab/web-old.tar.gz sudo find /srv/projects/web -type f -mtime +30 -delete - Challenge
Audit for policy violations
Plant three violations: make
index.htmlwritable by everyone, change the group ofcsstocarol, and make a new filetool.shsetuid. Write onefindcommand for each that reports exactly that violation, run them, repair all three, and run them again to show they now print nothing.Check your result
Before the repair the three commands print
index.html, thecssdirectory andtool.sh. After it, all three print nothing.Hint
find -perm -o+wmeans others can write.-not -group NAMEfinds the wrong group.-perm /4000matches setuid.Solution
sudo chmod o+w /srv/projects/web/index.html sudo chgrp carol /srv/projects/web/css sudo touch /srv/projects/web/tool.sh && sudo chmod u+s /srv/projects/web/tool.sh sudo find /srv/projects -type f -perm -o+w sudo find /srv/projects/web -not -group webteam sudo find /srv/projects -perm /4000 sudo chmod o-w /srv/projects/web/index.html sudo chgrp webteam /srv/projects/web/css sudo chmod u-s /srv/projects/web/tool.sh