#!/usr/bin/perl -w # perform some consistency checks on permission files use Getopt::Long; use strict; use Data::Dumper; use File::Basename; my @deflevels = ('easy', 'secure', 'paranoid'); my @defpermfiles = ('permissions', 'permissions.easy', 'permissions.secure', 'permissions.paranoid'); # filename # - level (DEFAULT, easy, secure, paranoid) # - owner # - mode my %perms; my($nodups, $checkmissing, $defonly, $showsuid, $showsgid, $showww, $showgw, $show, @levels, $showsame, $dump, @permfiles, $help, $checkdirs); Getopt::Long::Configure("no_ignore_case"); GetOptions ( "nodups" => \$nodups, "missing" => \$checkmissing, "defonly" => \$defonly, "show" => \$show, "suid" => \$showsuid, "sgid" => \$showsgid, "ww" => \$showww, "gw" => \$showgw, "same" => \$showsame, "level=s" => \@levels, "dump" => \$dump, "checkdirs=s" => \$checkdirs, "help" => \$help, ); if($help) { print <) { chomp; s/#.*//; next if(/^$/); my ($file, $owner, $mode) = split(/\s+/); if(!$nodups && exists($perms{$file}{$level})) { print STDERR "$permfile:$. File listed twice: $file already in $level\n"; } else { $perms{$file}{$level}{'owner'} = $owner; $perms{$file}{$level}{'mode'} = $mode; } if($checkdirs) { if(! -e $checkdirs.$file) { #print STDERR "$permfile:$.: can't check $file\n"; } elsif(-d $checkdirs.$file && oct($mode)&020 && !(oct($mode)&01000)) { print STDERR "$permfile:$.: $file group writeable but not sticky\n" } } } close(FH); } my ($file, $owner, $mode, $level); format FORMATTED = @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<< @>>>> (@*) $file, $owner, $mode, $level . open FORMATTED, ">&STDOUT"; $checkmissing = 1 unless ($show || $showsuid || $showsgid || $showww || $showgw || $dump || $showsame); foreach $file (sort keys %perms) { next if($defonly && !exists($perms{$file}{'DEFAULT'})); { my @l = ('DEFAULT'); push @l, @levels unless $defonly; my ($om, $modechanged, $numseen); $numseen = 0; for $level (@l) { next unless exists $perms{$file}{$level}; ++$numseen; $mode = $perms{$file}{$level}{'mode'}; $om = oct($mode) unless $om; $modechanged = 1 if($om != oct($mode)); $owner = $perms{$file}{$level}{'owner'}; next if( ($showsuid && !(oct($mode) & 04000)) || ($showsgid && !(oct($mode) & 02000)) || ($showww && !(oct($mode) & 0002)) || ($showgw && !(oct($mode) & 0020)) ); write FORMATTED if ($show); } if($numseen > 3) { print STDERR "Suspicious: $file in >3 levels\n"; } if($showsame && $numseen > 1 && !$modechanged) { print STDERR "Useless: $file\n"; } } if($checkmissing) { my $msg = ''; if(!exists($perms{$file}{'DEFAULT'})) { for $level (@levels) { if(!exists($perms{$file}{$level})) { $msg .= " not in $level\n"; } } } if(length $msg) { print STDERR "$file:\n$msg\n"; } } } close FORMATTED; print Dumper(\%perms) if($dump); # vim: sw=4