Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

In a linux system, I've done a chmod o+r -R mydir/ and I want to check that users in the 'o' group are able to read the contents of mydir. How can I do an 'ls mydir' as if I were a user in the other users not in the file’s group (o)?

Thanks

share|improve this question
add comment

2 Answers

up vote 1 down vote accepted

When I am in a system with only access to one account, at least what I do when I want to check if 'rest-of-the-world' can access to the files, is to check the permissions for the file AND THE FULL PATH to it:

# take the cannonic absolute path
# split the dirs and check for each one if it is x and r by 'others'
# check that the final file is readable by 'others'

This is easy to implement with perl and File::Specs, Cwd, File::stat and Fncl

This is a example script (unfortunately I have forgoten how to use the S_I* constants from Fnctl (:mode) to operate the bitwise logic with mode, or the :FIELDS from File::stat).

#!/usr/bin/env perl

=head check_file_access_for_all_users.pl

    -- Given a path this script checks that all subpaths are
       accessible for all users in the system. If no path is given, 
       then uses the current path

    -- <TO_DO> add an option for testing access to all files and dirs
       in the last dir of the path

=cut

use strict;
use File::Spec;
use Cwd  'realpath';
use File::stat;
use Fcntl qw(:mode);

my $path = shift;
$path ||='.'; # test current paths if no paths as an argument


# make it absolute and resolve symlinks
my $realpath = realpath($path);

print "realpath: $realpath\n";

# you can split with regex or split but I prefer splitdir
my @dirs= File::Spec->splitdir($realpath);

# last item of @dirs could be a file or symlink (check for (! -d) )
# Remove it: the dirs should be checked for rx and the file only for r
my $file;
if (! -d $dirs[-1]) {
    $file = pop @dirs;
}

# prepend / to first element in @dirs: it is an absolute path
# create an array for all the paths to check
my $path_str;
my @paths_list = map {$path_str.='/'.$_;} grep {$_} @dirs;

# list of paths win no access for others
my @paths_for_chmod;
$DB::single=1;
foreach my $path_to_check (@paths_list) {

    # this is a dir, so test is 'rw'
    my $test = 'rw';
    check_path_access($path_to_check, $test);
}

if ($file) {
    # check that is readable
    my $path_to_check = "$path_str/$file";

    # this is a file, so test is 'r'
    my $test = 'r';
    check_path_access($path_to_check, $test);
}


$DB::single=1;
if (@paths_for_chmod){
    print "#[NOT_OK]: Some elements of the path are not accesible by OTHER:\n";
    printf (("  %s %s\n" x @paths_for_chmod), map{$_->[0], $_->[1]} @paths_for_chmod);
}
else {
    print "The path $path and all its subpaths are accesible by OTHER\n";
}

print "end\n";

##################################################
#   Methods
##################################################

sub check_path_access{
    my ($path_to_check,$test) = @_;

    # dispatch table
    my $wanted_test = {
                       rw => {
                              test=> \&is_other_rx_bf,
                              msg => '',
                             },
                       r  => {
                              test => \&is_other_r_bf,
                              msg => '',
                             },
                      };


    my $mode = stat($path_to_check)->mode;
    # get if is rw by others and the octal value of the file permisions
    my ($has_o_access, $mode_oct) = $wanted_test->{$test}{test}->($mode);

    my $status   = $has_o_access?'':' NOT';
    my $mode_str = $has_o_access?'':" (mode=$mode_oct)";

    print {*STDERR} 'Others can '.$status .' access to ' .$path_to_check. $mode_str."\n";

    push @paths_for_chmod,  [$mode_str, $path_to_check] unless $has_o_access;

}

# brute force method for obaining mode for others (direct substr to mode string)
sub is_other_rx_bf{
    my $mode =shift;
    my $mode_oct = sprintf ("%04o", $mode & 07777);
    my $oth_mod  = substr($mode_oct,3,1);

    return $oth_mod>=4?1:0, $mode_oct;
}

sub is_other_r_bf{
    my $mode =shift;
    my $mode_oct = sprintf ("%04o", $mode & 07777);
    my $oth_mod  = substr($mode_oct,3,1);

    return $oth_mod>=4?1:0, $mode_oct;
}
# unfinished exploration for Fncl :mode constants
sub is_other_rx {
    my $mode =shift;
    die "not implemented yet\n";

    # ?? I can remember how to do this test properly
    my $allCanAccess = ($mode & S_IRUSR)   # User can read
        && ($mode & S_IRGRP)   # Group can read
            && ($mode & S_IROTH);  # Others can read

#### perldoc -f stat
##          use Fcntl ’:mode’;
##
##          $mode = (stat($filename))[2];
##
##          $user_rwx      = ($mode & S_IRWXU) >> 6;
##          $group_read    = ($mode & S_IRGRP) >> 3;
##          $other_execute =  $mode & S_IXOTH;
##
##          printf "Permissions are %04o\n", S_IMODE($mode), "\n";
##
##          $is_setuid     =  $mode & S_ISUID;
##          $is_setgid     =  S_ISDIR($mode);
##
##          # Permissions: read, write, execute, for user, group, others.
##
##          S_IRWXU S_IRUSR S_IWUSR S_IXUSR
##          S_IRWXG S_IRGRP S_IWGRP S_IXGRP
##          S_IRWXO S_IROTH S_IWOTH S_IXOTH
##

}



# chdir $path;
# my $canonical_path =qx{pwd -P};

Result:

perl check_file_access_for_all_users.pl /Users/pablo/tmp/dir1/dir2/dir3/txt1
Others can  access to /Users
Others can  access to /Users/pablo
Others can  access to /Users/pablo/tmp
Others can  NOT access to /Uspablo/pmg/tmp/dir1 (mode=0750)
Others can  access to /Users/pablo/tmp/dir1/dir2
Others can  access to /Users/pablo/tmp/dir1/dir2/dir3
Others can  access to /Users/pablo/tmp/dir1/dir2/dir3/txt1
realpath: /Users/pablo/tmp/dir1/dir2/dir3/txt1
#[NOT_OK]: Some elements of the path are not accesible by OTHER:
   (mode=0750) /Users/pablo/tmp/dir1
end

Disclaimer: this is a half brute force approach (I am sure there would be better functions for checking permisions) but at least it does not use system calls and regex. And at least point the fact that you should check all dirs in the path.

Please comments are welcome for refactoring this script. I will appreciate suggestions for removing the use of substr for catching the mode for others.

share|improve this answer
add comment

The only method I know of is to create such a user (if one does not already exist) and then use su -c "ls mydir" user.

share|improve this answer
    
The user nobody is usually sufficient. –  Lekensteyn Jun 7 '11 at 12:39
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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