Perl:用于查找世界可写文件但未找到世界可写文件的脚本

时间:2014-06-04 22:31:57

标签: perl

我有一个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;

我个人不会对正则表达式方法有任何问题,但是,我想要获得最佳性能,如果排除列表增加,则正则表达式会增加并且时间会增加。

我确信在脚本测试运行期间打印出内容时,正确填充了%排除哈希值。

我的脚本中的错误在哪里?

编辑1: 我正在逐步取得进展。我已经用我刚刚运行的脚本替换了上面的脚本,该脚本找到了我希望找到的所有文件。不幸的是,它还找到了它不应该找到的文件(其中一个被排除在外)。事实上,这个文件已经两次写入报告。

另外值得注意的是,我根据@Borodin的建议进行了更改,并使用了$mask变量,用于在$dirStats[2]内对wanted进行逐位比较子程序。这实际上不起作用并且返回服务器上的每个文件,除了返回错误,该错误指出possible precedence problem on bitwise & operator指向我已经进行了更改的第107行。我已经恢复了对每个文件执行stat三次。

编辑2: 我在另一个论坛上问道,并指出我需要在按位AND周围放置一些parens(@Borodin也在他的建议中找到并纠正了它):

return unless ($dirStats[2] & $mask) == $mask;

这消除了Possible precedence错误。但是,我仍然在获取包含应明确忽略的文件的输出,以及将所述文件写入输出文件两次。

编辑3: 结果脚本按预期工作。在排除列表中找到的文件是不是。它很相似,但路径有一个额外的目录。

1 个答案:

答案 0 :(得分:0)

这是最终形式的脚本:

#!/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_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 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 special 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}, $!";

}