Terminal: List all directories for which a user or group has write permission
Solution 1
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' -
Solution 2
In chat we came to the following instructions for user and group:
sudo find / -type d -user rinzwind -perm /u=w
sudo find / -type d -group rinzwind -perm /g=w
sudo find / -type d -perm /o=w
Or combine all three into one:
sudo find -type d \( \( -user rinzwind -perm /u=w \) -o \( -group rinzwind -perm /g=w \) -o -perm /o=w \)
Without the / it searches current directory.
Took less than 2 seconds on 67Gb of data on my system ;)
Solution 3
Answer under construction, please be patient
Testing for oneself
One can test write permissions for him/herself with the following code:
[ -w /home/$USER ] && echo yes # using home directory as example
Using -d
flag for test , we can test if something is a directory.
Knowing all that and find
we can do
find /home/ -print0 2> /dev/null | while IFS="" read -r -d "" file ; do [ -d "$file" ] && [ -w "$file" ] && echo "$file" is writeable ; done
Side note:
Obviously , if you get permission errors with find, you cannot read that file, hence there's no reason to output those errors, hence redirection to dev null. Obviously this won't work if we want to find out permissions for users other than oneself, and note - /home is just an example here. Such folders as /var
do have folders shared between multiple users
Testing for others
One could use stat
per each file the find
finds and filter it out with awk
find /var -type d -exec stat --format '%g %n' {} \; 2> /dev/null | awk '$1=='1000'{print}'
Here i am filtering for numeric ID of my own user , 1000, but it could be ID of any user. Of course one can play with options, use group name instead of numeric ids. It's something that is very pliable and adaptable to the purpose you need
Small adjustments
So I've noticed that you mention being logged in as root. Here's an output of my command, where I stat files and print their group and file name, then filter out using AWK by appropriate group name.
$ find /proc -type d -exec stat --format '%G %n' {} \; 2> /dev/null | awk '$1=="syslog"{print}'
syslog /proc/560
syslog /proc/560/task
syslog /proc/560/task/560
syslog /proc/560/task/560/net
syslog /proc/560/task/560/attr
syslog /proc/560/task/562
syslog /proc/560/task/562/net
syslog /proc/560/task/562/attr
syslog /proc/560/task/563
syslog /proc/560/task/563/net
syslog /proc/560/task/563/attr
syslog /proc/560/task/564
syslog /proc/560/task/564/net
syslog /proc/560/task/564/attr
syslog /proc/560/net
syslog /proc/560/attr
^C
Solution 4
If you have GNU find, you can use the -writable
test (note the spelling, it's not writeable
). That uses the access(2)
system call instead of just trying to figure things out from looking at the permissions, so it works correctly with ACLs. (But might break on NFS with ID mappings).
It will also find directories that are writeable by the user thanks to being a member of a secondary group. (e.g. a directory in /usr/local
writeable by users in the admin
group, or something like chown root:users /data/share && chmod 2775 /data/share
, where some accounts are members of the users
group.)
username_to_check=peter base_dir=/ # for example
sudo -u "$username_to_check" find "$base_dir" -type d -writable 2>/dev/null ## GNU find, not POSIX
There will be errors when find
encounters directories the user can't descend into, so we redirect errors to /dev/null
.
This will not find any directories that are writeable but inside directories without execute permission, because find
running as the user can't traverse the higher directories. However, if a process they own is started inside such a directory, they will be able to write to it with relative paths. (or they get hold of an open file descriptor to such a directory, they can use openat(2)
). pwd
won't work if they don't have exec permission on one of the directory components of the full path, so it's not a common setup.
This also misses writeable directories that are inside executable but not readable directories. To work around those limitations, probably run find -type d
as root, and use find -writable
as the user to check the resulting paths. That might be more efficient than a shell loop using [ -w "$f" ]
.
POSIX find(1)
has far fewer options than GNU find. If your script has to be portable to POSIX, it's probably easiest to pipe into something else that checks permissions, like a shell with [ -w "$f" ]
(see the other answer that suggests this.)
Related videos on Youtube
elrobis
GIS Developer Bad hockey player So-so musician Likes fishing
Updated on September 18, 2022Comments
-
elrobis over 1 year
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
- List all the groups:
-
elrobis about 8 yearsHmm.. maybe I'm doing something wrong? But when I execute exactly this to target user
ftpgisdata
, I'm not getting any results. It just drops down to the next line in the terminal:find -type d -user ftpgisdata -perm /u=w,g=w
-
Oli about 8 years
sudo mkdir cheese; sudo chmod o+w cheese
is a directory anybody can write to but won't show in either of these. -
Oli about 8 years@elrobis Change them so they start
find /
. It's currently just searching the current working directory. -
elrobis about 8 yearsahh ok. ..so does it follow that if I
cd /
, that it will search forward from the root and consider any given user or group? It's running right now and looks promising--definite taking a little longer than 2 sec though! -
muru about 8 yearsAnd you'll probably need to run this with
sudo
to avoid permission errors. -
elrobis about 8 yearsThis seems to work. I ran it on a user I understood and got results I'd expect to get. I'm trying @Oli's approach right now to see how comparable they are.
-
elrobis about 8 yearsI tried @Rinzwind's approach first because this one was a bit scary, however curiously they are getting somewhat different results..!
-
Rinzwind about 8 years@elrobis Oli's version is a bit more difficult to grasp but also includes ACL ( a tool to set permissions more precise than general chmod can)
-
Oli about 8 yearsAnd simple directories that not owned by the given user that allow others to write.
-
Oli about 8 yearsDon't you just need a third option?
sudo find / -type d -perm /o=w
. Also can't you combine all three searches into one with-o
? Still won't do ACL but it's closer. -
elrobis about 8 yearsRinzwind and @Oli, I edited to include the output I got from both of your solutions--thoughts? Oli's seems more comprehensive ..and I was particularly intrigued to see that it found a defunct wordpress site lurking on the system. (Exactly the sort of weird stuff I was hoping to learn with this exercise!)
-
Oli about 8 years@elrobis Try the combined version I edited into this answer. It should also show the Wordpress site and be somewhat faster than my answer.
-
elrobis about 8 yearsThe combined result set is pretty noisy. It includes specific files rather than just directories (not necessarily a bad thing), but alot of the results don't make sense for the user I tested, and when I ran
ls -la
on one of the paths returned, it provided numbers (id's maybe?) rather than seemingly legit user/group names for what struck me as a very vague, low-level path. -
elrobis about 8 yearsTrue, I am logged in as route, but basically I want to learn "hey what directories can X user write to?" I just tried your approach on user with id=1001, i.e.
$1=='1001'
, but it didn't return any hits. Thoughts? -
Sergiy Kolodyazhnyy about 8 years@elrobis Yeah, I've got side tracked - I realize that you wanted to check write permissions on a directory per user. Thing is , a user may be part of a group, so they can write to directory. For example, directory group is
foobar
, but user that belongs to that group may have usernamescooby
. This is a more complex problem that it seems . . .I'll be working on it more, probably will need to write functions for checking user and checking group write access on a file -
Peter Cordes about 8 years@Oli and Rinzwind: this misses directories with group-ownership of one of the user's secondary groups, doesn't it? e.g.
chown root:users /data/share && chmod 2775 /data/share
, where some accounts are members of theusers
group. -
Oli about 8 years@PeterCordes Yeah. I'm sure there's a way of wrapping the find command in a function that builds out all the various things to search but by that point, we might all have expired.
-
Peter Cordes about 8 years@Oli: Or just use GNU find's
-writable
, like I did in my answer. It usesaccess(2)
to check writeability. -
Oli about 8 yearsThe problem with running the find as non-root is you don't evaluate the entire tree. For example, create the following:
sudo mkdir -p cheese/deep; sudo chmod o+w cheese/deep; sudo chmod o-r cheese
anybody can write tocheese/deep
but they can't read the contents of the parentcheese
directory, and thereforefind
can't seecheese/deep
. Your find will just error out (and suppress the error). Sorry. -
Oli about 8 years@PeterCordes Unfortunately running find as the user has its own problems. I've commented with a breaking example.
-
Peter Cordes about 8 years@Oli: Oh right, I overlooked the
x
withoutr
case. Thanks. I guess we could construct afind
command line with a shell loop that iterates over the user's secondary groups, if we don't want to just pipe root-find output into another process that doesaccess(2)
checks as the user. That 2nd process could befind -writable
. -
elrobis about 8 yearsPeter thanks for your contribution and the helpful description. I ran your solution and updated my post to include the result for the same user I've been testing against.
-
Rinzwind about 8 yearsAlso a nice approach but this turned out to be pretty difficult and you'd almost file for a bug report to improve this D: The question is a valid one when you look at securing a system. And it is just too darn difficult.