104

*nix user permissions are really simple, but things can get messy when you have to take in account all the parent directory access before reaching a given file. How can I check if the user has enough privileges? If not, then which directory is denying access?

For example, suppose a user joe, and the file /long/path/to/file.txt. Even if file.txt was chmoded to 777, joe still has to be able to access /long/, and then /long/path/ and then /long/path/to/ before. What I need is a way to automatically check this. If joe does not have access, I would also like to know where he has been denied. Maybe he can access /long/, but not /long/path/.

1
  • So you're question is more "how to determine why a user cannot access a file"? :)
    – rogerdpack
    Nov 14, 2019 at 23:34

5 Answers 5

106

To verify access visually, you can use

namei -m /path/to/really/long/directory/with/file/in

which will output all of the permissions in the path in a vertical list.

or

namei -l /path/to/really/long/directory/with/file/in

to list all owners and the permissions. Other answers explain how to verify this programmatically.

3
  • 2
    This should be the right answer. In fact using namei <path> || exit 1 allows you to detect a permission problem much easily in a script.
    – lorenzog
    Jun 2, 2016 at 10:01
  • 23
    it doesn't answer directly whether joe has access to the file.
    – jfs
    Nov 6, 2017 at 20:03
  • This also does not elucidate how access control lists might influence things.
    – Andrew M
    Sep 15, 2021 at 0:41
21

You can use bash to do this.

$ cat check-permissions.sh
#!/bin/bash
file=$1
# Handle non-absolute paths
if ! [[ "$file" == /* ]] ; then
    path=.
fi
dirname "$file" | tr '/' $'\n' | while read part ; do
    path="$path/$part"
    # Check for execute permissions
    if ! [[ -x "$path" ]] ; then
        echo "'$path' is blocking access."
    fi
done
if ! [[ -r "$file" ]] ; then
    echo "'$file' is not readable."
fi
$ ./check-permissions.sh /long/path/to/file.txt

To check this for a specific user, you can use sudo.

sudo -u joe ./check-permissions.sh /long/path/to/file.txt
11
  • sudo -u joe script . Here script is the name of the script file right? so your telling sudo to act like joe was calling the script?
    – tgkprog
    Jul 9, 2013 at 14:24
  • Precisely. I have modified my answer to clarify that.
    – user26112
    Jul 9, 2013 at 14:31
  • I made a slight modification to my script to handle non-absolute paths.
    – user26112
    Jul 9, 2013 at 14:47
  • @EvanTeitelman With an absolute path, did you mean to initialize path to be empty? or /? Jul 9, 2013 at 20:31
  • @Gilles: I meant for it to be empty. In the example, path is set to /long the first time around the loop, which is correct. Should I set path to nothing explicitly (path=)? Also, thanks for simplifying out my use of tr.
    – user26112
    Jul 9, 2013 at 20:58
21

If you have root access, impersonate the user, then run test -r (read), test -w (write), or test -x (execute) to check whether the user can read/write/execute the given file.

sudo -u otheruser test -w /file/to/test || {
   echo "otheruser cannot write the file"
}
3
  • 2
    This is exact answer what I was searching for. Title of this question could be misleading. Apr 29, 2020 at 5:01
  • 3
    a slight embellishment to check if a process running as "USER:GROUP" can access a given file would be the following command: sudo su - USER -g GROUP -s /bin/bash -c "test -r /path/to/file"
    – MNB
    Jan 23, 2021 at 14:53
  • What is that exit 1 doing there, why is it necessary? I am asking just so I learn...
    – pgr
    Nov 11, 2021 at 15:01
5

As I got from your question, you should check it for different users (not only joe), so in that case the easiest way is to recursivly check it via sudo like this:

FILE=$1 ; T_USER=$2 ;
if sudo -u $T_USER [ -r "$FILE" ] ; then
    echo "original file $1 is readable for $T_USER"
else
    while sudo -u $T_USER [ ! -x "$FILE" ] ; do FILE=$(dirname "$FILE") ; done
    echo "only $FILE is readable for $T_USER"
fi

usage:

./script.sh /long/path/to/file.txt joe
6
  • Joe needs execute permissions on the directories, not read permissions.
    – user26112
    Jul 9, 2013 at 14:20
  • @EvanTeitelman yes, you're right. Fixed.
    – rush
    Jul 9, 2013 at 14:29
  • @rush I tried to test it using the following file: /root/test/test.txt (permissions are 0755, 0700, and 0777). I issued ./script.sh /root/test/test.txt joe and it echoed original file /root/test/test.txt is readable for joe. Also, while trying this I misstyped the test dir: ./script.sh /root/tst/test.txt joe, and it echoed original file /root/tst/test.txt is readable for joe. Did I missed something?
    – Metalcoder
    Jul 10, 2013 at 17:46
  • @Metalcoder sorry, it's my fault. There was one extra exclamation. It's removed now, you can try it one more time, it should work fine now.
    – rush
    Jul 10, 2013 at 17:50
  • @rush it worked! That extra exclamation negates the result of -r $FILE, right?
    – Metalcoder
    Jul 10, 2013 at 18:10
2

Here's my attempt at providing this functionality. I've opted to use stat, a while loop, and dirname.

I've created this script, walkdir.bash:

#/bin/bash

cwd="$1"
while [ "x$cwd" != x/ ]; do
  info=`stat "$cwd" |grep "Access: ("`
  printf "%s : %s\n" "$info" "$cwd"

  cwd=`dirname "$cwd"`;
done

You run it like so:

$ walkdir.bash "/home/saml/blog/vmware_networking_tutorial/url.txt"
Access: (0664/-rw-rw-r--)  Uid: (  500/    saml)   Gid: (  501/    saml) : /home/saml/blog/vmware_networking_tutorial/url.txt
Access: (0775/drwxrwxr-x)  Uid: (  500/    saml)   Gid: (  501/    saml) : /home/saml/blog/vmware_networking_tutorial
Access: (0775/drwxrwxr-x)  Uid: (  500/    saml)   Gid: (  501/    saml) : /home/saml/blog
Access: (0700/drwx------)  Uid: (  500/    saml)   Gid: (  501/    saml) : /home/saml
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root) : /home

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .