A script which scans a local filesystem and writes to a file a list of world-writable files found on the filesystem.
I ran it on a server with a couple terabytes of storage; not all of it used. In fact, only 195GB have been used. I'm not sure how many files there are, though.
The script takes 23 minutes to run. Is there something I can do to make it run faster?
#!/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 $root = "/";
my (%excludes, %devNums);
my ($regExcld, $errHeader);
# Create an array of the file stats for "/"
my @rootStats = stat($root);
# 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]/) {
my @line = split;
push(@mounts, $line[1]);
}
}
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 (((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}, $!";
}
-f
andstat
calls insidewanted
withFile::stat
equivalents. \$\endgroup\$find / -perm -2 ! -type l -ls
. \$\endgroup\$