10

Under Linux, how can I find all the files and directories that are writable (or, actually, not writable) by a particular user?

Edit: To clarify, I meant under a particular subdir, not systemwide. And yes, that means all the permutations and combinations of user, group and world writability that would allow that user to write. I know what the question entails semantically, I was hoping for a one- or few-liner to execute to get a list of these files.

  • Okay, thanks to everyone for the answers. I already found the "find" solution via google, but was wondering if there were some way to generically apply it to a given user. Looks like there is no other way than to su as the user, then run the find command -- unless anyone else chimes in? I will accept Ophidian's answer some time tomorrow barring any better responses. – Pistos Jun 2 '09 at 2:51
18

Use the 'find' command if you have findutils version 4.3.0 or greater installed:

For all files under the current directory that are writable by the current user:

find . -writable

For all files under the current directory that are not writable by the current user:

find . ! -writable

According to the man page:

This test makes use of the access(2) system call, and so can be fooled by NFS servers which do UID mapping (or root-squashing), since many systems implement access(2) in the client’s kernel and so cannot make use of the UID mapping information held on the server.

  • 4
    Just thought I'd mention for further edification: I actually had to do this with a user who didn't have a login shell ( /sbin/nologin ). To do that, I used sudo, like this: sudo -u nobody find . ! -writable – Pistos Jun 7 '09 at 17:09
  • This doesn't answer the question and therefore shouldn't be the accepted answer. The question was about "a particular user", not about the "current user". – jlh Feb 7 '17 at 10:20
  • and to hide the permission denied errors add 2>&1 | grep -v "Permission denied" to be find . -writable 2>&1 | grep -v "Permission denied" – iolsmit Aug 24 '17 at 17:56
3

You can create a Perl script (writable.pl) like this:

#!/usr/bin/perl

use strict;

sub recurse {
  my $path = shift;
  my @files = glob "$path/{*,.*}";
  for my $file (@files) {
    if (-d $file) {
      if ($file !~ /\/\.$/ && $file !~ /\/\.\.$/) {
        recurse($file);
      }
    } else {
      print "$file\n" if -w $file;
    }
  }
}

print "Writable files for " . getlogin() . "\n";
recurse($ARGV[0]);

and then use this script, as root, as follows:

su USERNAME -c "./writable.pl DIRECTORY"

filling in USERNAME and DIRECTORY as appropriate.

  • Excellent. Thank you. The $ARGV[0] is taken as empty in the bash shell on CentOS 6.2. Not sure why. I modified the script to read from a file. – doon Apr 20 '13 at 12:42
1

Are you sure that is really the question that you want to be asking?

To say "I want to see all files that X account can write to" means every file owned by them with u+w, every file owned by any group they belong to that's set g+w, and every file world writable (o+w).

Not writable would be even harder. You'd be better off to make a list of every file, then exclude those that they can write to.

  • 3
    Of course it is even more complicated if the system has ACLs enabled. – Zoredache Jun 2 '09 at 0:08
  • 2
    Not counting chattr +i files – Matt Simmons Jun 2 '09 at 0:12
1

For Eddie's answer if you throw in:

my $path = quotemeta shift;

Then it will traverse directories with spaces in their name as well.

1

I'll use the gnu find syntax for the -perm flag in this example:

Basically -- if you throw out wacky extensions like ACLs, you've got 3 chocies - owner, group, and "other" write access. Sounds like a job for a loop.

There is plenty of room to optimize this but I'll leave that to someone else... Also, I never can remember all the details of find and crossing filesystems and that sort of nonsense. Also, make sure the output of groups is the same as on my test linux system

$ groups snoopy
snoopy : snoopy doghouse linus admin wwI woodstock
$

This is a rough example of how you'd find files writable by a user. This will when run as any user, but if you run it as a non-uid0 user you'll only find things that are in directories that the user running the script has both read and execute permissions to.

#!/bin/sh

user=snoopy

directory=/

# first files owned by the user and writable
find "$directory" -follow -user "$user" -perm /u+w 2> /dev/null


# now for files that are group writable with the user in that group
for groups in $(groups snoopy 2> /dev/null | cut -f2 -d:)
do
  find "$directory" -follow -group "$user" -perm /g+w 2> /dev/null
done

# now for everything else
find "$directory" -follow -perm /o+w 2> /dev/null
0

I'm not sure if this is the best way, but should do what you ask:

for file in *
do 
    if [ -w $file ] ; then 
        echo $file
    fi
done

key is of course in -w switch, which can also be negated

EDIT: Thinking more about this, this script prints what is writable by current user, it obviously wouldn't work for some given user.

  • Of course, you have to run this script as that user. – Eddie Jun 2 '09 at 0:54
  • yeah, figured... – Slartibartfast Jun 2 '09 at 0:57
  • how would you write this in perl? – ealeon Jan 21 '18 at 19:45
0

This command should find all writable directories, you can change the permissions as you see fit:

find / -type d \( -perm -g+w -or -perm -o+w \) -exec ls -adl {} \;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.