【发布时间】:2014-06-04 22:31:57
【问题描述】:
我有一个 Perl 脚本,该脚本旨在扫描本地安装的文件系统以查找全球可写文件。它的部分执行是读取排除文件的列表并从中构建哈希。然后检查每个文件在哈希中是否存在,以确定它是否实际上被排除在外。
#!/usr/bin/perl
use warnings;
use strict;
use Fcntl ':mode';
use File::Find;
no warnings 'File::Find';
no warnings 'uninitialized';
my $dir = "/var/log/tivoli/";
my $mtab = "/etc/mtab";
my $permFile = "world_writable_w_files.txt";
my $tmpFile = "world_writable_files.tmp";
my $exclude = "/usr/local/etc/world_writable_excludes.txt";
#my $mask = (S_IWUSR | S_IWGRP | S_IWOTH);
my (%excludes, %devNums);
my ($regExcld, $errHeader);
# Compile a list of mountpoints that need to be scanned
my @mounts;
open MT, "<${mtab}" or die "Cannot open ${mtab}, $!";
# We only want the local mountpoints
while (<MT>) {
if ($_ =~ /ext[34]/) {
chomp;
my @line = split;
push(@mounts, $line[1]);
my @stats = stat($_);
$devNums{$stats[0]} = $_;
}
}
close MT;
# Build a hash of each mountpoint's device number for future comparison
#foreach (@mounts) {
# my @stats = stat($_);
# $devNums{$stats[0]} = $_;
#}
# Build a hash from /usr/local/etc/world_writables_excludes.txt
if ((! -e $exclude) || (-z $exclude)) {
$errHeader = <<HEADER;
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! !!
!! /usr/local/etc/world_writable_excludes.txt is !!
!! is missing or empty. This report includes !!
!! every world-writable file including those which !!
!! are expected and should be excluded. !!
!! !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
HEADER
} else {
open XCLD, "<${exclude}" or die "Cannot open ${exclude}, $!\n";
while (<XCLD>) {
chomp;
$excludes{$_} = 1;
}
}
sub wanted {
# Is it excluded from the report...
return if (exists $excludes{$File::Find::name});
# ...in a basic directory, ...
return if $File::Find::dir =~ /sys|proc|dev/;
# ...a regular file, ...
return unless -f;
# ...local, ...
my @dirStats = stat($File::Find::name);
return if (exists $devNums{$dirStats[0]});
# ...and world writable?
# return unless $dirStats[2] & $mask == $mask;
return unless (((stat)[2] & S_IWUSR) && ((stat)[2] & S_IWGRP) && ((stat)[2] & S_IWOTH));
# If so, add the file to the list of world writable files
print(WWFILE "$File::Find::name\n");
}
# Create the output file path if it doesn't already exist.
mkdir($dir or die "Cannot execute mkdir on ${dir}, $!") unless (-d $dir);
# Create our filehandle for writing our findings
open WWFILE, ">${dir}${tmpFile}" or die "Cannot open ${dir}${tmpFile}, $!";
print(WWFILE "${errHeader}") if ($errHeader);
find(\&wanted, @mounts);
close WWFILE;
# If no world-writable files have been found ${tmpFile} should be zero-size;
# Delete it so Tivoli won't alert
if (-z "${dir}${tmpFile}") {
unlink "${dir}${tmpFile}";
} else {
rename("${dir}${tmpFile}","${dir}${permFile}") or die "Cannot rename file ${dir}${tmpFile}, $!";
}
问题似乎是与包含排除文件列表的哈希进行比较。
哈希的创建:
} else {
open XCLD, "<${exclude}" or die "Cannot open ${exclude}, $!\n";
while (<XCLD>) {
chomp;
$excludes{$_} = 1;
}
}
...和比较...
# Is it excluded from the report...
return if (exists $excludes{$File::Find::name});
我在恢复到以前从排除文件列表中构建正则表达式的方法后做出了这个决定
# Read in the list of excluded files and create a regex from them
my $regExcld = do {
open XCLD, "<${exclude}" or die "Cannot open ${exclude}, $!\n";
my @ignore = <XCLD>;
chomp @ignore;
local $" = '|';
qr/@ignore/;
};
(旁注:有人告诉我我没有正确锚定正则表达式。我不确定我应该做什么。)
还有:
# Is it excluded from the report...
return if $File::Find::name =~ $regExcld;
我个人不会对正则表达式方法有任何问题,但是,我会追求最佳性能,如果排除列表增加,则正则表达式会增加并且时间会增加。
我确定 %excludes 哈希值已正确填充,因为我已在脚本测试运行期间打印出内容。
我的脚本中的错误在哪里?
编辑 1: 我在这方面取得了渐进的进展。我已经用我刚刚运行的脚本替换了上面的脚本,该脚本找到了我希望找到的所有文件。不幸的是,它还找到了它不应该找到的文件(排除之一)。事实上,那个文件被写入报告两次。
另外值得注意的是,我按照@Borodin 的建议进行了更改,并使用了$mask 变量,该变量将用于在wanted 子例程中与$dirStats[2] 进行按位比较。这实际上不起作用并返回了服务器上的每个文件,此外还返回了一个错误,指出 possible precedence problem on bitwise & operator 指向我进行更改的第 107 行。从那以后,我又恢复到对每个文件执行 3 次 stat。
编辑 2: 我在另一个论坛上问过,有人指出我需要在按位 AND 周围放置括号(@Borodin 也注意到了他的建议并更正了它):
return unless ($dirStats[2] & $mask) == $mask;
这消除了Possible precedence 错误。但是,我仍然在获取包含应明确忽略的文件的输出,并将所述文件写入输出文件两次。
编辑 3: 原来脚本按预期工作。找到的文件在排除列表中不是。类似,但路径有一个额外的目录。
【问题讨论】:
-
您是否尝试过打印您的 %excludes 哈希,以检查它是否确实包含应包含的内容?
-
@Ashalynd 我引用:“我确信 %excludes 哈希值已正确填充,因为我在脚本测试运行期间打印了内容。”
-
正则表达式缺少锚定意味着您将匹配包含
@ignore中任何字符串的文件名。相反,你应该写qr/\A(?:@ignore)\z/ -
到底是什么问题?哈希方法是否不应该排除文件?正则表达式方法有效吗?
-
@Borodin 谢谢。如果没有指出哈希比较的修复方法,我会进行更改。
标签: perl