Friday, February 12, 2010

Change Control: PERL Directory and File Permission (statistics) recursively

Change Control: PERL Directory and File Permission (statistics) recursively

*******************************************************************************************
Programming Language: Perl
Calling Method: ./filePermissions.pl <dir Offset> <depth> <dir> or <file>
Example-1-: ./filePermissions.pl "/tmp" "n" "dir"
where starting dir is "/tmp" for "n" (depth=all levels) and list the directories recursively
Example-2-: ./filePermissions.pl "/usr" "1" ""
where starting dir is "/usr" for "1" level of depth and lists all files and directories


Recommendations:
===================
Run this program periodically. Grab the output, version it, BASELINE it, and archive it.
Subsequent time, the output of this report for the same criteria must be compared with the BASELINE. Report any anomalies.

Fields Reported: ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)
==========================================================================================================

dev:ID of device containing file. If this value and following has no meaning on the platform, it will contain undefined value.
ino: inode number.
mode: Unix mode for file.
nlink: Number of hard links.
uid:User ID of owner.
gid: Group ID of owner.
rdev: Device ID (if special file).
size:Total size, in bytes.
atime: Time of last access as DateTime object.
mtime:Time of last modification as DateTime object.
ctime: Time of last status change as DateTime object.
blksize: Block size for filesystem I/O.
blocks: Number of blocks allocated.

Custom:
==========
Feel free to modify to suite your requirements.
The MD5 checksum has been disabled from this script because of performance issues.
You may want to add, edit or remove field names that are being reported.

*********************************** Code Begins ****************************************

P=`for L in \`echo /usr/bin/perl /usr/local/perl5/bin/perl /usr/local/bin/perl /usr/local/bin/perl5 /bin/perl\`
do
if [ -f $L ]; then
V=\`$L -V | grep 'Summary' | awk '{ print \$4 }' \`
if [ "$V" = "perl5" ]; then
echo $L
exit
fi
fi
done`;$P -e '
use Getopt::Long;

my $verbose=0;
my @excludefiles;

$md5Found = 0;
#BEGIN{
# $md5Found = ;
# eval {require Digest::MD5;};
# if ($@) {
# $md5Found = 0;
# };
#}

$path = shift;
$depth = shift;
if ($depth eq "") {
$depth = "n";
}

$filter = shift;
if ($filter eq "") {
$filter = "all";
}


@excludefiles = split(",", $exclude);

#for my $path (@ARGV) {
$path =~ s{//}{/}; # remove multiple slashes
my $fullpath= makeFullPath($path, "", "");

if (-d $path) {
processDirectory($path, "", $md5Found, $depth);
} else {
print("$path not found\n");
exit(-1);
}
processFile($fullpath, $md5Found);
#}

exit(0);

sub processDirectory {
my ($root, $path, $md5Found, $currDepth)= @_;
$currDepth-- if ($currDepth ne "n");

my $files= getFilelist(makeFullPath($root, $path));

for my $file (@$files) {
next if ($file eq "." || $file eq "..");
my $fullpath= makeFullPath($root, $path, $file);
my $relative= makeFullPath($path, $file);

if (!isInIgnoreList($relative)) {
if ((-f $fullpath) && ($filter ne "dir")) {
processFile($fullpath, $md5Found);
}
elsif (-d $fullpath) {
processFile($fullpath, 0);
if (($currDepth eq "n") || ($currDepth > 0))
{
processDirectory($root, $relative, $md5Found, $currDepth);
}
}
}
}
}

sub makeFullPath {
my ($full, @parts)= @_;

$full ||="";
for my $path (@parts) {
next if (!defined $path);
$path =~ s{^/}{}; # remove leading slash
$full =~ s{/?$}{/$path}; # remove trailing slash, append path
}

return $full;
}

sub getFilelist {
my ($path)= @_;

die "$!: reading $path\n" unless opendir(DIR, $path);

my @files= readdir DIR;
closedir DIR;

return \@files;
}

sub processFile {
my ($filename, $md5Found)= @_;

$hex = -1;
if ($md5Found) {
open(FILE, $filename) or return;
binmode(FILE);
$hex = Digest::MD5->new->addfile(*FILE)->hexdigest;
}


($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);

$uname = getpwuid($uid);
$gname = getgrgid($gid);

printf("\"$filename\",\"$dev\",\"$ino\",\"%04o\",\"$nlink\",\"$uid\",\"$gid\",\"$rdev\",\"$size\",\"%s\",\"%s\",\"%s\",\"$gname\",\"$uname\",\"$hex\"\n",
($mode & 07777),
get_real_time($atime),get_real_time($mtime),get_real_time($ctime));
}

sub isInIgnoreList {
my $fullfilename= shift;

for my $pattern (@excludefiles) {
if (matches($fullfilename, glob2pat("/$pattern"))) {
return 1;
}
}
return 0;
}

sub matches {
my ($filename, $pattern)= @_;

return ($filename =~ m{$pattern}i);
}

sub glob2pat {
my $globstr = shift;
my %patmap = (
"." => "\.",
"*" => ".*",
"?" => ".",
"[" => "[",
"]" => "]",
);
$globstr =~ s{(.)} { $patmap{$1} || "\Q$1" }ge;
return $globstr;
}

sub get_real_time ($) {
my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime $_[0];
$year += 1900;
$mon += 1;
return "$year\-$mon\-$mday $hour:$min:$sec";
}

sub get_user($) {
($username) = split(":", `getent passwd $_[0]`);
return($username);
}

sub get_group($) {
($groupname) = split(":", `getent group $_[0]`);
return($groupname);
}' "$1" "$2" "$3"

*********************************** Code Ends ****************************************

No comments:

Post a Comment