Когда я нахожусь в системе с доступом только к одной учетной записи, по крайней мере, то, что я делаю, когда хочу проверить, может ли «остальной мир» иметь доступ к файлам, это проверить права доступа к файлу И ПОЛНОМУ ПУТЬ к нему:
# 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'
Это легко реализовать с помощью Perl и File::Specs, Cwd, File::stat и Fncl.
Это пример сценария (к сожалению, я забыл, как использовать константы S_I * из Fnctl (:mode) для работы с побитовой логикой в режиме или:FIELDS из 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};
Результат:
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
Отказ от ответственности: это полубрутный подход (я уверен, что были бы лучшие функции для проверки разрешений), но по крайней мере он не использует системные вызовы и регулярные выражения. И, по крайней мере, укажите тот факт, что вы должны проверить все каталоги на пути.
Пожалуйста, комментарии приветствуются для рефакторинга этого скрипта. Буду признателен за предложения по удалению использования substr для ловли режима для других.