Ubuntu – Terminal: List all directories for which a user or group has write permission

command linegroupspermissionsusers

I'd like to list all the directories for which a user or group has write permissions.

I found this question on ServerFault, but it addresses a Windows Server, so I'm optimistic there's something better for us in the Linux community. At the same time, I realize there is a recursive twist to this question that may render it impossible without a long-running script.

I'm aware of the following useful commands:

  • List all the groups: cut -d : -f 1 /etc/group
  • List all the users: cut -d : -f 1 /etc/passwd
  • Get a user's home dir: getent passwd user-name| cut -d: -f 6
  • This script that lists each user and their group assignments
  • Get permissions and user/group details on folder contents: ls -la

However when I don't have a clue what a user's purpose is, it'd be nice to pull up a list of ALL the directories they have write permission for and start looking around from there. If nothing else it's a super-useful audit..

If it helps to understand my purpose, I inherited (or am at least baby-sitting?) a couple of systems after our SysAdmin took a new position. So I've been trying to understand the evolution of these two systems, such as what software is installed, and where (..ugh), where various config files live, and now, what different groups and users have been created–including the directories they are allowed to write to. Usually I can find such useful terminal commands here on askubuntu, but not finding this one I thought I'd go ahead and ask.

The exact system is Ubuntu 10.04.2, but we also support Ubuntu 12.04.5, so the most version-agnostic solution would be best. Thanks in advance for any help.


[Update: Initial results for the two quick answers]

It's worth noting I'm logged in as root for these, and / was my working directory. Also, they took a comparable amount of time to run.

@Rinzwind's combined command got the following output in about 5.5 min..

root@tatooine:/# sudo find -type d \( \( -user ftpgisdata -perm /u=w \) -o \( -group ftpgisdata -perm /g=w \) -o -perm /o=w \)
./tmp
./tmp/.ICE-unix
./tmp/.X11-unix
find: `./proc/6594/task/6594/fd/5': No such file or directory
find: `./proc/6594/task/6594/fdinfo/5': No such file or directory
find: `./proc/6594/fd/5': No such file or directory
find: `./proc/6594/fdinfo/5': No such file or directory
./var/tmp
./var/lib/php5
./var/crash
./var/lock
./home/ftpgisdata
./home/ftpgisdata/.ssh
./home/ftpgisdata/.cache
./home/sitename-i-changed.com/wp-content/profile-pics
./dev/shm

@Oli's revised command gets something very similar, also in about 5.5 minutes..

root@tatooine:/# sudo find / -type d -print0 | sudo -u ftpgisdata xargs -0 sh -c 'for p; do [ -w "$p" ] && echo "$p"; done' -
/tmp
/tmp/.ICE-unix
/tmp/.X11-unix
find: `/proc/15541': No such file or directory
find: `/proc/15542': No such file or directory
find: `/proc/15543': No such file or directory
find: `/proc/15567': No such file or directory
find: `/proc/15568/task/15568/fd/5': No such file or directory
find: `/proc/15568/task/15568/fdinfo/5': No such file or directory
find: `/proc/15568/fd/5': No such file or directory
find: `/proc/15568/fdinfo/5': No such file or directory
/var/tmp
/var/lib/php5
/var/crash
/var/lock
/home/ftpgisdata
/home/ftpgisdata/.ssh
/home/ftpgisdata/.cache
/home/sitename-i-changed.com/wp-content/profile-pics
/dev/shm

@PeterCordes answer also returned similar results in about 5.5 minutes..

root@tatooine:~# username_to_check=ftpgisdata base_dir=/   # for example
root@tatooine:~# sudo -u "$username_to_check" find "$base_dir" -type d -writable  2>/dev/null ## GNU find, not POSIX
/tmp
/tmp/.ICE-unix
/tmp/.X11-unix
/proc/7159/task/7159/fd
/proc/7159/fd
/proc/7159/map_files
/var/tmp
/var/lib/php5
/var/crash
/var/lock
/home/ftpgisdata
/home/ftpgisdata/.ssh
/home/ftpgisdata/.cache
/home/sitename-i-changed.com/wp-content/profile-pics
/dev/shm

Best Answer

Working out what a user can do is hard if you're not that user. You can test various things (is owner, same group, etc) but ACL might apply, there might be no permissions in the mount, who knows. It's hard.

If you can turn into that user, you can test -w <path> to see if they can write. This isn't as fast as just looking at the inode but it's possible with sudo.

sudo -u oli test -w <path> && echo "HOORAY"

We can then squirl that onto the back-end of find. Instead of just using -exec to change to the oli user over and over and over again (see past revisions), we pipe everything into a xargs instance running as oli. This is much faster.

sudo find / -type d -print0 | sudo -u oli xargs -0 -I{} sh -c 'test -w "$0" && echo "$0"' {}

A somewhat optimised (but visually flabbier) version of this involves minimising the amount of subshelling the xargs performs by piping a stream of paths into a low number of bash subshells. This is undoubtedly faster for big searches.

sudo find / -type d -print0 | sudo -u oli xargs -0 sh -c 'for p; do [ -w "$p" ] && echo "$p"; done' -
Related Question